package swModels

import (
	"regexp"
	"strings"
)

var (
	PORTSTATUSDESCRE   = regexp.MustCompile(`(?i)(\S+)\s+(.*?)\s+(notconnect|connected|disabled|err-disabled)\s+(\S+)\s+(\S+)\s+(.*?)$`)
	SPEEDTYPERE        = regexp.MustCompile(`(?i)(\S+)\s+(.*$)`)
	NEXUSPORTDESCRE    = regexp.MustCompile(`(?i)(\S+)\s+(.*?)\s+(noOperMem|connected|sfpAbsent|disabled|notconnec|err-disabled)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$`)
	PORTSTATUSRE       = regexp.MustCompile(`(?i)(\S+)\s+(notconnect|connected|disabled|err-disabled)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)`)
	PORTSTATUSPODESCRE = regexp.MustCompile(`(?i)(\S+)\s+(.*?)\s+(notconnect|connected|disabled|err-disabled)\s+(\S+)\s+(\S+)\s+(\S+)`)
	PORTSTATUSPORE     = regexp.MustCompile(`(?i)(\S+)\s+(notconnect|connected|disabled|err-disabled)\s+(\S+)\s+(\S+)\s+(\S+)`)
	PORTSTATUSNEXUS1RE = regexp.MustCompile(`(?i)(\S+)\s+--\s+(noOperMem|connected|sfpAbsent|disabled|notconnec|err-disabled)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)`)
	PORTSTATUSNEXUS2RE = regexp.MustCompile(`(?i)(\S+)\s+--\s+(noOperMem|connected|sfpAbsent|disabled|notconnec|err-disabled)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)`)
	INTNAMESPLITRE     = regexp.MustCompile(`(?i)([a-z]+)([0-9].*?)$`)
)

type (
	InterfacesStatus struct {
		Interfaces []*InterfaceStatus `json:"interface_status"`
	}

	InterfaceStatus struct {
		Description *string `json:"description"`
		Duplex      *string `json:"duplex"`
		Port        *string `json:"port"`
		Speed       *string `json:"speed"`
		Status      *string `json:"status"`
		Type        *string `json:"type"`
		Vlan        *string `json:"vlan"`
	}
)

func (i *InterfacesStatus) Parse(s *string) {
	for _, l := range strings.Split(*s, "\n") {
		des := NEXUSPORTDESCRE.FindStringSubmatch(l)
		if len(des) != 0 {
			i.Interfaces = append(i.Interfaces, &InterfaceStatus{
				Port:        nomalizeIntName(&des[1]),
				Description: itemNone(&des[2]),
				Status:      &des[3],
				Vlan:        &des[4],
				Duplex:      &des[5],
				Speed:       &des[6],
				Type:        itemNone(&des[7]),
			})
			continue
		}
		des = PORTSTATUSDESCRE.FindStringSubmatch(l)
		if len(des) != 0 {
			if des[1] != "Port" {
				speed := &des[6]
				var Type *string
				speedType := SPEEDRE.FindStringSubmatch(des[6])
				if len(speedType) != 0 {
					speed = &speedType[1]
					Type = &speedType[2]
				}

				i.Interfaces = append(i.Interfaces, &InterfaceStatus{
					Port:        nomalizeIntName(&des[1]),
					Description: itemNone(&des[2]),
					Status:      &des[3],
					Vlan:        &des[4],
					Duplex:      &des[5],
					Speed:       speed,
					Type:        itemNone(Type),
				})
			}
		}
	}
}

func (i *InterfacesStatus) FindPort(port string) *InterfaceStatus {
	port = strings.ToLower(port)
	for _, p := range i.Interfaces {
		if strings.ToLower(*p.Port) == port {
			return p
		}
	}
	return nil
}

func (i *InterfaceStatus) IsConnected() bool {
	if strings.ToLower(*i.Status) == "connected" {
		return true
	}
	return false
}

func nomalizeIntName(s *string) *string {
	port, num := IntFullPre(s)
	if port == "" {
		return s
	}

	port += num
	return &port
}

func IntFullPre(s *string) (string, string) {
	pn := INTNAMESPLITRE.FindStringSubmatch(*s)
	if len(pn) == 0 {
		return "", ""
	}
	switch strings.ToLower(pn[1]) {
	case "fa":
		return "fastethernet", pn[2]
	case "gi":
		return "gigabitethernet", pn[2]
	case "te":
		return "tengigabitethernet", pn[2]
	case "po":
		return "port-channel", pn[2]
	case "eth":
		return "ethernet", pn[2]
	default:
		return pn[1], pn[2]
	}
}

func nomalizePortName(s *string) string {
	pn := INTNAMESPLITRE.FindStringSubmatch(*s)
	if len(pn) == 0 {
		return *s
	}

	var port string
	switch strings.ToLower(pn[1]) {
	case "fa":
		port = "fastethernet"
	case "gi":
		port = "gigabitethernet"
	case "te":
		port = "tengigabitethernet"
	case "po":
		port = "port-channel"
	case "eth":
		port = "ethernet"
	}

	port += pn[2]
	return port
}

func itemNone(s *string) *string {
	if *s == "" {
		return nil
	}
	if strings.Contains(*s, "--") {
		return nil
	}
	return s
}
