package config

import (
	"log/slog"
	"mesh-drop/internal/security"
	"os"
	"path/filepath"
	"sync"

	"github.com/google/uuid"
	"github.com/spf13/viper"
)

// WindowState 定义窗口状态
type WindowState struct {
	Width     int  `mapstructure:"width"`
	Height    int  `mapstructure:"height"`
	X         int  `mapstructure:"x"`
	Y         int  `mapstructure:"y"`
	Maximised bool `mapstructure:"maximised"`
}

var Version = "next"

type Language string

const (
	LanguageEnglish Language = "en"
	LanguageChinese Language = "zh-Hans"
)

type configData struct {
	WindowState WindowState       `mapstructure:"window_state"`
	ID          string            `mapstructure:"id"`
	PrivateKey  string            `mapstructure:"private_key"`
	PublicKey   string            `mapstructure:"public_key"`
	SavePath    string            `mapstructure:"save_path"`
	HostName    string            `mapstructure:"host_name"`
	AutoAccept  bool              `mapstructure:"auto_accept"`
	SaveHistory bool              `mapstructure:"save_history"`
	TrustedPeer map[string]string `mapstructure:"trusted_peer"` // ID -> PublicKey

	Language       Language `mapstructure:"language"`
	CloseToSystray bool     `mapstructure:"close_to_systray"`
}

type Config struct {
	v    *viper.Viper
	mu   sync.RWMutex
	data configData
}

// 默认窗口配置
var defaultWindowState = WindowState{
	Width:  1024,
	Height: 768,
	X:      -1,
	Y:      -1,
}

func GetConfigDir() string {
	configPath, err := os.UserConfigDir()
	if err != nil {
		configPath = "/tmp"
	}
	return filepath.Join(configPath, "mesh-drop")
}

func GetUserHomeDir() string {
	home, err := os.UserHomeDir()
	if err != nil {
		return "/tmp"
	}
	return home
}

// New 读取配置
func Load() *Config {
	v := viper.New()
	configDir := GetConfigDir()
	err := os.MkdirAll(configDir, 0755)
	if err != nil {
		slog.Error("Failed to create config directory", "error", err)
	}
	configFile := filepath.Join(configDir, "config.json")

	// 设置默认值
	defaultSavePath := filepath.Join(GetUserHomeDir(), "Downloads")
	v.SetDefault("window_state", defaultWindowState)
	v.SetDefault("save_path", defaultSavePath)
	defaultHostName, err := os.Hostname()
	if err != nil {
		defaultHostName = "localhost"
	}
	v.SetDefault("host_name", defaultHostName)
	v.SetDefault("id", uuid.New().String())
	v.SetDefault("save_history", true)

	v.SetConfigFile(configFile)
	v.SetConfigType("json")

	// 尝试读取配置
	if err := v.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
			slog.Info("Config file not found, using defaults")
		} else {
			slog.Warn("Failed to read config file, using defaults", "error", err)
		}
	}

	// 确保默认保存路径存在
	err = os.MkdirAll(defaultSavePath, 0755)
	if err != nil {
		slog.Error("Failed to create default save path", "path", defaultSavePath, "error", err)
	}

	var data configData
	if err := v.Unmarshal(&data); err != nil {
		slog.Error("Failed to unmarshal config", "error", err)
	}

	config := Config{
		v:    v,
		data: data,
	}

	// 如果没有密钥对，生成新的
	if config.data.PrivateKey == "" || config.data.PublicKey == "" {
		priv, pub, err := security.GenerateKey()
		if err != nil {
			slog.Error("Failed to generate identity keys", "error", err)
		} else {
			config.data.PrivateKey = priv
			config.data.PublicKey = pub
			v.Set("private_key", priv)
			v.Set("public_key", pub)
			// 保存新生成的密钥
			if err := config.Save(); err != nil {
				slog.Error("Failed to save generated keys", "error", err)
			}
		}
	}

	// 初始化 TrustedPeer map if nil
	if config.data.TrustedPeer == nil {
		config.data.TrustedPeer = make(map[string]string)
	}

	return &config
}

// Save 保存配置到磁盘
func (c *Config) Save() error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.save()
}

func (c *Config) save() error {
	configDir := GetConfigDir()
	if err := os.MkdirAll(configDir, 0755); err != nil {
		return err
	}

	if err := c.v.WriteConfig(); err != nil {
		slog.Error("Failed to write config", "error", err)
		return err
	}

	// 设置配置文件权限为 0600 (仅所有者读写)
	configFile := c.v.ConfigFileUsed()
	if configFile != "" {
		if err := os.Chmod(configFile, 0600); err != nil {
			slog.Warn("Failed to set config file permissions", "error", err)
		}
	}

	return nil
}

// update 是一个辅助函数，用于在锁保护下更新配置并保存
func (c *Config) update(fn func()) {
	c.mu.Lock()
	defer c.mu.Unlock()

	fn()

	if err := c.save(); err != nil {
		slog.Error("Failed to save config", "error", err)
	}
}

// SetSavePath 修改配置
func (c *Config) SetSavePath(savePath string) {
	c.update(func() {
		c.data.SavePath = savePath
		c.v.Set("save_path", savePath)
		_ = os.MkdirAll(savePath, 0755)
	})
}

func (c *Config) GetSavePath() string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.SavePath
}

func (c *Config) SetHostName(hostName string) {
	c.update(func() {
		c.data.HostName = hostName
		c.v.Set("host_name", hostName)
	})
}

func (c *Config) GetHostName() string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.HostName
}

func (c *Config) GetID() string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.ID
}

func (c *Config) SetAutoAccept(autoAccept bool) {
	c.update(func() {
		c.data.AutoAccept = autoAccept
		c.v.Set("auto_accept", autoAccept)
	})
}

func (c *Config) GetAutoAccept() bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.AutoAccept
}

func (c *Config) SetSaveHistory(saveHistory bool) {
	c.update(func() {
		c.data.SaveHistory = saveHistory
		c.v.Set("save_history", saveHistory)
	})
}

func (c *Config) GetSaveHistory() bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.SaveHistory
}

func (c *Config) GetVersion() string {
	return Version
}

func (c *Config) SetWindowState(state WindowState) {
	c.update(func() {
		c.data.WindowState = state
		c.v.Set("window_state", state)
	})
}

func (c *Config) GetWindowState() WindowState {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.WindowState
}

func (c *Config) AddTrust(peerID string, publicKey string) {
	c.update(func() {
		if c.data.TrustedPeer == nil {
			c.data.TrustedPeer = make(map[string]string)
		}
		c.data.TrustedPeer[peerID] = publicKey
		c.v.Set("trusted_peer", c.data.TrustedPeer)
	})
}

func (c *Config) GetTrusted() map[string]string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.TrustedPeer
}

func (c *Config) RemoveTrust(peerID string) {
	c.update(func() {
		delete(c.data.TrustedPeer, peerID)
		c.v.Set("trusted_peer", c.data.TrustedPeer)
	})
}

func (c *Config) IsTrusted(peerID string) bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	_, exists := c.data.TrustedPeer[peerID]
	return exists
}

func (c *Config) SetLanguage(language Language) {
	c.update(func() {
		c.data.Language = language
		c.v.Set("language", language)
	})
}

func (c *Config) GetLanguage() Language {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.Language
}

func (c *Config) SetCloseToSystray(closeToSystray bool) {
	c.update(func() {
		c.data.CloseToSystray = closeToSystray
		c.v.Set("close_to_systray", closeToSystray)
	})
}

func (c *Config) GetCloseToSystray() bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.CloseToSystray
}

func (c *Config) GetPrivateKey() string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.PrivateKey
}

func (c *Config) GetPublicKey() string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.data.PublicKey
}
