package main

import (
	"fmt"
	"os"
	"sync"

	"github.com/fsnotify/fsnotify"
	log "github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"
)

var Cfg *Config

type Config struct {
	General struct {
		DeleteLogFileAtStart       bool   `yaml:"delete_log_file_at_start"`
		LogToFile                  bool   `yaml:"log_to_file"`
		Callsign                   string `yaml:"callsign"`
		LogLevel                   string `yaml:"log_level"`
		TelnetServer               bool   `yaml:"telnetserver"`
		FlexRadioSpot              bool   `yaml:"flexradiospot"`
		SendFreqModeToLog          bool   `yaml:"sendFreqModeToLog4OM"`
		SpotColorNewEntity         string `yaml:"spot_color_new_entity"`
		BackgroundColorNewEntity   string `yaml:"background_color_new_entity"`
		SpotColorNewBand           string `yaml:"spot_color_new_band"`
		BackgroundColorNewBand     string `yaml:"background_color_new_band"`
		SpotColorNewMode           string `yaml:"spot_color_new_mode"`
		BackgroundColorNewMode     string `yaml:"background_color_new_mode"`
		SpotColorNewBandMode       string `yaml:"spot_color_new_band_mode"`
		BackgroundColorNewBandMode string `yaml:"background_color_new_band_mode"`
		SpotColorNewSlot           string `yaml:"spot_color_new_slot"`
		BackgroundColorNewSlot     string `yaml:"background_color_new_slot"`
		SpotColorMyCallsign        string `yaml:"spot_color_my_callsign"`
		BackgroundColorMyCallsign  string `yaml:"background_color_my_callsign"`
		SpotColorWorked            string `yaml:"spot_color_worked"`
		BackgroundColorWorked      string `yaml:"background_color_worked"`
	} `yaml:"general"`

	Database struct {
		MySQL         bool   `yaml:"mysql"`
		SQLite        bool   `yaml:"sqlite"`
		MySQLUser     string `yaml:"mysql_db_user"`
		MySQLPassword string `yaml:"mysql_db_password"`
		MySQLDbName   string `yaml:"mysql_db_name"`
		MySQLHost     string `yaml:"mysql_host"`
		MySQLPort     string `yaml:"mysql_port"`
	} `yaml:"database"`

	SQLite struct {
		SQLitePath string `yaml:"sqlite_path"`
	} `yaml:"sqlite"`

	Cluster struct {
		Server      string `yaml:"server"`
		Port        string `yaml:"port"`
		Login       string `yaml:"login"`
		Password    string `yaml:"password"`
		Skimmer     bool   `yaml:"skimmer"`
		FT8         bool   `yaml:"ft8"`
		FT4         bool   `yaml:"ft4"`
		Beacon      bool   `yaml:"beacon"`
		Command     string `yaml:"command"`
		LoginPrompt string `yaml:"login_prompt"`
	} `yaml:"cluster"`

	Flex struct {
		Discover bool   `yaml:"discovery"`
		IP       string `yaml:"ip"`
		SpotLife string `yaml:"spot_life"`
	} `yaml:"flex"`

	TelnetServer struct {
		Host string `yaml:"host"`
		Port string `yaml:"port"`
	} `yaml:"telnetserver"`

	Gotify struct {
		Enable         bool   `yaml:"enable"`
		URL            string `yaml:"url"`
		Token          string `yaml:"token"`
		NewDXCC        bool   `yaml:"NewDXCC"`
		NewBand        bool   `yaml:"NewBand"`
		NewMode        bool   `yaml:"NewMode"`
		NewBandAndMode bool   `yaml:"NewBandAndMode"`
		WatchList      bool   `yaml:"Watchlist"`
	} `yaml:"gotify"`
}

type ConfigWatcher struct {
	watcher    *fsnotify.Watcher
	configPath string
	mu         sync.RWMutex
}

func NewConfig(configPath string) *Config {
	Cfg = &Config{}

	file, err := os.Open(configPath)
	if err != nil {
		log.Println("could not open config file")
	}
	defer file.Close()
	d := yaml.NewDecoder(file)

	if err := d.Decode(&Cfg); err != nil {
		log.Println("could not decode config file")
	}

	return Cfg
}

func ValidateConfigPath(path string) error {
	s, err := os.Stat(path)
	if err != nil {
		return err
	}
	if s.IsDir() {
		return fmt.Errorf("'%s' is a directory, not a normal file", path)
	}
	return nil
}

func NewConfigWatcher(configPath string) (*ConfigWatcher, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	return &ConfigWatcher{
		watcher:    watcher,
		configPath: configPath,
	}, nil
}

func (cw *ConfigWatcher) Start() error {
	if err := cw.watcher.Add(cw.configPath); err != nil {
		return err
	}

	go func() {
		for {
			select {
			case event, ok := <-cw.watcher.Events:
				if !ok {
					return
				}
				if event.Op&fsnotify.Write == fsnotify.Write {
					Log.Info("Config file modified, reloading...")
					cw.reloadConfig()
				}
			case err, ok := <-cw.watcher.Errors:
				if !ok {
					return
				}
				Log.Errorf("Config watcher error: %v", err)
			}
		}
	}()

	return nil
}

func (cw *ConfigWatcher) reloadConfig() {
	cw.mu.Lock()
	defer cw.mu.Unlock()

	newCfg := &Config{}
	file, err := os.Open(cw.configPath)
	if err != nil {
		Log.Errorf("Could not reload config: %v", err)
		return
	}
	defer file.Close()

	d := yaml.NewDecoder(file)
	if err := d.Decode(newCfg); err != nil {
		Log.Errorf("Could not decode reloaded config: %v", err)
		return
	}

	// Sauvegarder l'ancienne config
	oldCfg := Cfg

	// Appliquer la nouvelle config
	Cfg = newCfg

	// Vérifier les changements qui nécessitent des actions
	cw.applyConfigChanges(oldCfg, newCfg)

	Log.Info("✅ Config reloaded successfully")
}

func (cw *ConfigWatcher) applyConfigChanges(oldCfg, newCfg *Config) {
	// Log level
	if oldCfg.General.LogLevel != newCfg.General.LogLevel {
		switch newCfg.General.LogLevel {
		case "DEBUG":
			Log.SetLevel(log.DebugLevel)
		case "INFO":
			Log.SetLevel(log.InfoLevel)
		case "WARN":
			Log.SetLevel(log.WarnLevel)
		default:
			Log.SetLevel(log.InfoLevel)
		}
		Log.Infof("Log level changed to %s", newCfg.General.LogLevel)
	}

	// Gotify
	if oldCfg.Gotify.Enable != newCfg.Gotify.Enable {
		Log.Infof("Gotify notifications %s", map[bool]string{true: "enabled", false: "disabled"}[newCfg.Gotify.Enable])
	}

	if oldCfg.Cluster.FT8 != newCfg.Cluster.FT8 ||
		oldCfg.Cluster.FT4 != newCfg.Cluster.FT4 ||
		oldCfg.Cluster.Skimmer != newCfg.Cluster.Skimmer ||
		oldCfg.Cluster.Beacon != newCfg.Cluster.Beacon {
		Log.Info("Cluster filters changed, applying")
		httpServerInstance.TCPClient.ReloadFilters()
	}
}

func (cw *ConfigWatcher) Stop() {
	cw.watcher.Close()
}
