package main

import (
	"regexp"
	"strconv"
	"strings"
	"sync"

	_ "github.com/mattn/go-sqlite3"
)

type TelnetSpot struct {
	DX             string
	Spotter        string
	Frequency      string
	Mode           string
	Band           string
	Time           string
	DXCC           string
	Comment        string
	CommandNumber  int
	FlexSpotNumber int
	NewDXCC        bool
	NewBand        bool
	NewMode        bool
	CallsignWorked bool
}

func ProcessTelnetSpot(re *regexp.Regexp, spotRaw string, SpotChanToFlex chan TelnetSpot, SpotChanToHTTPServer chan TelnetSpot, Countries Countries) {
	match := re.FindStringSubmatch(spotRaw)

	if len(match) != 0 {
		spot := TelnetSpot{
			DX:        match[3],
			Spotter:   match[1],
			Frequency: match[2],
			Mode:      match[4],
			Comment:   strings.Trim(match[5], " "),
			Time:      match[6],
		}

		spot.DXCC = GetDXCC(spot.DX, Countries)

		if spot.DXCC == "" {
			Log.Errorf("Could not identify the DXCC for %s", spot.DX)
			return
		}

		spot.GetBand()
		spot.GuessMode()
		spot.CallsignWorked = false
		spot.NewBand = false
		spot.NewMode = false
		spot.NewDXCC = false

		contactRepo := NewLog4OMContactsRepository(Cfg.SQLite.SQLitePath)
		defer contactRepo.db.Close()

		contactsChan := make(chan []Contact)
		contactsModeChan := make(chan []Contact)
		contactsBandChan := make(chan []Contact)
		contactsCallChan := make(chan []Contact)

		wg := new(sync.WaitGroup)
		wg.Add(4)

		go contactRepo.ListByCountry(spot.DXCC, contactsChan, wg)
		contacts := <-contactsChan

		go contactRepo.ListByCountryMode(spot.DXCC, spot.Mode, contactsModeChan, wg)
		contactsMode := <-contactsModeChan

		go contactRepo.ListByCountryBand(spot.DXCC, spot.Band, contactsBandChan, wg)
		contactsBand := <-contactsBandChan

		go contactRepo.ListByCallSign(spot.DX, spot.Band, spot.Mode, contactsCallChan, wg)
		contactsCall := <-contactsCallChan

		wg.Wait()

		if len(contacts) == 0 {
			spot.NewDXCC = true
		}

		if len(contactsMode) == 0 {
			spot.NewMode = true
		}
		if len(contactsBand) == 0 {
			spot.NewBand = true
		}
		if len(contactsCall) > 0 {
			spot.CallsignWorked = true
		}

		// Send spots to FlexRadio
		SpotChanToFlex <- spot

		if spot.NewDXCC {
			Log.Debugf("(** New DXCC **) DX: %s - Spotter: %s - Freq: %s - Band: %s - Mode: %s - Comment: %s - Time: %s - Command: %v, FlexSpot: %v",
				spot.DX, spot.Spotter, spot.Frequency, spot.Band, spot.Mode, spot.Comment, spot.Time, spot.CommandNumber, spot.FlexSpotNumber)
		}

		if !spot.NewDXCC && spot.NewBand && spot.NewMode {
			Log.Debugf("(** New Band/Mode **) DX: %s - Spotter: %s - Freq: %s - Band: %s - Mode: %s - Comment: %s - Time: %s - DXCC: %s",
				spot.DX, spot.Spotter, spot.Frequency, spot.Band, spot.Mode, spot.Comment, spot.Time, spot.DXCC)
		}

		if !spot.NewDXCC && spot.NewBand && !spot.NewMode {
			Log.Debugf("(** New Band **) DX: %s - Spotter: %s - Freq: %s - Band: %s - Mode: %s - Comment: %s - Time: %s - DXCC: %s",
				spot.DX, spot.Spotter, spot.Frequency, spot.Band, spot.Mode, spot.Comment, spot.Time, spot.DXCC)
		}

		if !spot.NewDXCC && !spot.NewBand && spot.NewMode && spot.Mode != "" {
			Log.Debugf("(** New Mode **) DX: %s - Spotter: %s - Freq: %s - Band: %s - Mode: %s - Comment: %s - Time: %s - DXCC: %s",
				spot.DX, spot.Spotter, spot.Frequency, spot.Band, spot.Mode, spot.Comment, spot.Time, spot.DXCC)
		}

		if !spot.NewDXCC && !spot.NewBand && !spot.NewMode && spot.CallsignWorked {
			Log.Debugf("(** Worked **) DX: %s - Spotter: %s - Freq: %s - Band: %s - Mode: %s - Comment: %s - Time: %s - DXCC: %s",
				spot.DX, spot.Spotter, spot.Frequency, spot.Band, spot.Mode, spot.Comment, spot.Time, spot.DXCC)
		}

		if !spot.NewDXCC && !spot.NewBand && !spot.NewMode {
			Log.Debugf("DX: %s - Spotter: %s - Freq: %s - Band: %s - Mode: %s - Comment: %s - Time: %s - DXCC: %s",
				spot.DX, spot.Spotter, spot.Frequency, spot.Band, spot.Mode, spot.Comment, spot.Time, spot.DXCC)
		}
	} else {
		// Log.Infof("Could not decode: %s", strings.Trim(spotRaw, "\n"))
	}

}

func (spot *TelnetSpot) GetBand() {
	switch true {
	case strings.HasPrefix(spot.Frequency, "1.8"):
		spot.Band = "160M"
		if spot.Mode == "SSB" {
			spot.Mode = "LSB"
		}
	case strings.HasPrefix(spot.Frequency, "3"):
		spot.Band = "80M"
		if spot.Mode == "SSB" {
			spot.Mode = "LSB"
		}
	case strings.HasPrefix(spot.Frequency, "5."):
		spot.Band = "60M"
		if spot.Mode == "SSB" {
			spot.Mode = "LSB"
		}
	case strings.HasPrefix(spot.Frequency, "7"):
		spot.Band = "40M"
		if spot.Mode == "SSB" {
			spot.Mode = "LSB"
		}
	case strings.HasPrefix(spot.Frequency, "10"):
		spot.Band = "30M"
	case strings.HasPrefix(spot.Frequency, "14"):
		spot.Band = "20M"
		if spot.Mode == "SSB" {
			spot.Mode = "USB"
		}
	case strings.HasPrefix(spot.Frequency, "18"):
		spot.Band = "17M"
		if spot.Mode == "SSB" {
			spot.Mode = "USB"
		}
	case strings.HasPrefix(spot.Frequency, "21"):
		spot.Band = "15M"
		if spot.Mode == "SSB" {
			spot.Mode = "USB"
		}
	case strings.HasPrefix(spot.Frequency, "24"):
		spot.Band = "12M"
		if spot.Mode == "SSB" {
			spot.Mode = "USB"
		}
	case strings.HasPrefix(spot.Frequency, "28"):
		spot.Band = "10M"
		if spot.Mode == "SSB" {
			spot.Mode = "USB"
		}
	case strings.HasPrefix(spot.Frequency, "29"):
		spot.Band = "10M"
		if spot.Mode == "SSB" {
			spot.Mode = "USB"
		}
	case strings.HasPrefix(spot.Frequency, "50"):
		spot.Band = "6M"
		if spot.Mode == "SSB" {
			spot.Mode = "USB"
		}
	default:
		spot.Band = "N/A"
	}
}

func (spot *TelnetSpot) GuessMode() {
	if spot.Mode == "" {
		freqInt, err := strconv.ParseFloat(spot.Frequency, 32)
		if err != nil {
			Log.Errorf("could not convert frequency string in float64:", err)
		}

		switch spot.Band {
		case "160M":
			if freqInt >= 1800 && freqInt <= 1840 {
				spot.Mode = "CW"
			}
			if freqInt >= 1840 && freqInt <= 1844 {
				spot.Mode = "FT8"
			}
		case "80M":
			if freqInt >= 3500 && freqInt < 3568 {
				spot.Mode = "CW"
			}
			if freqInt >= 3568 && freqInt < 3573 {
				spot.Mode = "FT4"
			}
			if freqInt >= 3573 && freqInt < 3580 {
				spot.Mode = "FT8"
			}
			if freqInt >= 3580 && freqInt < 3600 {
				spot.Mode = "CW"
			}
			if freqInt >= 3600 && freqInt <= 3800 {
				spot.Mode = "LSB"
			}
		case "60M":
			if freqInt >= 5351.5 && freqInt < 5354 {
				spot.Mode = "CW"
			}
			if freqInt >= 5354 && freqInt < 5366 {
				spot.Mode = "LSB"
			}
			if freqInt >= 5366 && freqInt <= 5266.5 {
				spot.Mode = "FT8"
			}
		case "40M":
			if freqInt >= 7000 && freqInt < 7045.5 {
				spot.Mode = "CW"
			}
			if freqInt >= 7045.5 && freqInt < 7048.5 {
				spot.Mode = "FT4"
			}
			if freqInt >= 7048.5 && freqInt < 7074 {
				spot.Mode = "CW"
			}
			if freqInt >= 7074 && freqInt < 7078 {
				spot.Mode = "FT8"
			}
			if freqInt >= 7078 && freqInt <= 7300 {
				spot.Mode = "LSB"
			}
		case "30M":
			if freqInt >= 10100 && freqInt < 10130 {
				spot.Mode = "CW"
			}
			if freqInt >= 10130 && freqInt < 10140 {
				spot.Mode = "FT8"
			}
			if freqInt >= 10140 && freqInt <= 10150 {
				spot.Mode = "FT4"
			}
		case "20M":
			if freqInt >= 14000 && freqInt < 14074 {
				spot.Mode = "CW"
			}
			if freqInt >= 14074 && freqInt < 14078 {
				spot.Mode = "FT8"
			}
			if freqInt >= 14074 && freqInt < 14078 {
				spot.Mode = "FT8"
			}
			if freqInt >= 14078 && freqInt < 14083 {
				spot.Mode = "FT4"
			}
			if freqInt >= 14083 && freqInt < 14119 {
				spot.Mode = "FT8"
			}
			if freqInt >= 14119 && freqInt < 14350 {
				spot.Mode = "USB"
			}

		case "17M":
			if freqInt >= 18068 && freqInt < 18095 {
				spot.Mode = "CW"
			}
			if freqInt >= 18095 && freqInt < 18104 {
				spot.Mode = "FT8"
			}
			if freqInt >= 18104 && freqInt < 18108 {
				spot.Mode = "FT4"
			}
			if freqInt >= 18108 && freqInt <= 18168 {
				spot.Mode = "USB"
			}

		case "15M":
			if freqInt >= 21000 && freqInt < 21074 {
				spot.Mode = "CW"
			}
			if freqInt >= 21074 && freqInt < 21100 {
				spot.Mode = "FT8"
			}
			if freqInt >= 21100 && freqInt < 21140 {
				spot.Mode = "RTTY"
			}
			if freqInt >= 21140 && freqInt < 21144 {
				spot.Mode = "FT4"
			}
			if freqInt >= 21144 && freqInt <= 21450 {
				spot.Mode = "USB"
			}

		case "12M":
			if freqInt >= 24890 && freqInt < 24915 {
				spot.Mode = "CW"
			}
			if freqInt >= 24915 && freqInt < 24919 {
				spot.Mode = "FT8"
			}
			if freqInt >= 24919 && freqInt < 24930 {
				spot.Mode = "CW"
			}
			if freqInt >= 24930 && freqInt <= 24990 {
				spot.Mode = "USB"
			}

		case "10M":
			if freqInt >= 28000 && freqInt < 28074 {
				spot.Mode = "CW"
			}
			if freqInt >= 28074 && freqInt < 28080 {
				spot.Mode = "FT8"
			}
			if freqInt >= 28080 && freqInt < 28100 {
				spot.Mode = "RTTY"
			}
			if freqInt >= 28100 && freqInt < 28300 {
				spot.Mode = "CW"
			}
			if freqInt >= 28300 && freqInt < 29000 {
				spot.Mode = "USB"
			}
			if freqInt >= 29000 && freqInt <= 29700 {
				spot.Mode = "FM"
			}
		case "6M":
			if freqInt >= 50000 && freqInt < 50100 {
				spot.Mode = "CW"
			}
			if freqInt >= 50100 && freqInt < 50313 {
				spot.Mode = "USB"
			}
			if freqInt >= 50313 && freqInt < 50320 {
				spot.Mode = "FT8"
			}
			if freqInt >= 50320 && freqInt < 50400 {
				spot.Mode = "USB"
			}
			if freqInt >= 50400 && freqInt < +52000 {
				spot.Mode = "FM"
			}
		}
	}

	if spot.Mode == "" {
		Log.Errorf("Could not identify mode for %s on %s", spot.DX, spot.Frequency)
	}
}