package main

import (
	"encoding/json"
	"fmt"
	"os"
	"time"
)

type Config struct {
	Server struct {
		Name        string `json:"name"`
		Network     string `json:"network"`
		Description string `json:"description"`
		Version     string `json:"version"`
		AdminInfo   string `json:"admin_info"`
		Listen      struct {
			Host      string `json:"host"`
			Port      int    `json:"port"`
			SSLPort   int    `json:"ssl_port"`
			EnableSSL bool   `json:"enable_ssl"`
		} `json:"listen"`
		SSL struct {
			CertFile   string `json:"cert_file"`
			KeyFile    string `json:"key_file"`
			RequireSSL bool   `json:"require_ssl"`
		} `json:"ssl"`
	} `json:"server"`

	Limits struct {
		MaxClients          int `json:"max_clients"`
		MaxChannels         int `json:"max_channels"`
		MaxChannelUsers     int `json:"max_channel_users"`
		MaxNickLength       int `json:"max_nick_length"`
		MaxChannelLength    int `json:"max_channel_length"`
		MaxTopicLength      int `json:"max_topic_length"`
		MaxKickLength       int `json:"max_kick_length"`
		MaxAwayLength       int `json:"max_away_length"`
		PingTimeout         int `json:"ping_timeout"`
		RegistrationTimeout int `json:"registration_timeout"`
		FloodLines          int `json:"flood_lines"`
		FloodSeconds        int `json:"flood_seconds"`
	} `json:"limits"`

	Features struct {
		EnableOper     bool   `json:"enable_oper"`
		EnableServices bool   `json:"enable_services"`
		EnableModes    bool   `json:"enable_modes"`
		EnableCTCP     bool   `json:"enable_ctcp"`
		EnableDCC      bool   `json:"enable_dcc"`
		CaseMapping    string `json:"case_mapping"`
	} `json:"features"`

	NickChangeNotification struct {
		ShowToEveryone bool `json:"to_everyone"`
		ShowToOpers    bool `json:"to_opers"`
		ShowToSelf     bool `json:"to_self"`
	} `json:"nick_change_notification"`

	Privacy struct {
		HideHostsFromUsers bool   `json:"hide_hosts_from_users"`
		OperBypassHostHide bool   `json:"oper_bypass_host_hide"`
		MaskedHostSuffix   string `json:"masked_host_suffix"`
	} `json:"privacy"`

	WhoisFeatures struct {
		// Basic information visibility
		ShowUserModes struct {
			ToEveryone bool `json:"to_everyone"`
			ToOpers    bool `json:"to_opers"`
			ToSelf     bool `json:"to_self"`
		} `json:"show_user_modes"`

		ShowSSLStatus struct {
			ToEveryone bool `json:"to_everyone"`
			ToOpers    bool `json:"to_opers"`
			ToSelf     bool `json:"to_self"`
		} `json:"show_ssl_status"`

		ShowIdleTime struct {
			ToEveryone bool `json:"to_everyone"`
			ToOpers    bool `json:"to_opers"`
			ToSelf     bool `json:"to_self"`
		} `json:"show_idle_time"`

		ShowSignonTime struct {
			ToEveryone bool `json:"to_everyone"`
			ToOpers    bool `json:"to_opers"`
			ToSelf     bool `json:"to_self"`
		} `json:"show_signon_time"`

		ShowRealHost struct {
			ToEveryone bool `json:"to_everyone"`
			ToOpers    bool `json:"to_opers"`
			ToSelf     bool `json:"to_self"`
		} `json:"show_real_host"`

		ShowChannels struct {
			ToEveryone     bool `json:"to_everyone"`
			ToOpers        bool `json:"to_opers"`
			ToSelf         bool `json:"to_self"`
			HideSecret     bool `json:"hide_secret_channels"`
			HidePrivate    bool `json:"hide_private_channels"`
			ShowMembership bool `json:"show_membership_levels"`
		} `json:"show_channels"`

		ShowOperClass struct {
			ToEveryone bool `json:"to_everyone"`
			ToOpers    bool `json:"to_opers"`
			ToSelf     bool `json:"to_self"`
		} `json:"show_oper_class"`

		ShowClientInfo struct {
			ToEveryone bool `json:"to_everyone"`
			ToOpers    bool `json:"to_opers"`
			ToSelf     bool `json:"to_self"`
		} `json:"show_client_info"`

		ShowAccountName struct {
			ToEveryone bool `json:"to_everyone"`
			ToOpers    bool `json:"to_opers"`
			ToSelf     bool `json:"to_self"`
		} `json:"show_account_name"`

		// Advanced/unique features
		ShowActivityStats     bool `json:"show_activity_stats"`
		ShowGitHubIntegration bool `json:"show_github_integration"`
		ShowGeolocation       bool `json:"show_geolocation"`
		ShowPerformanceStats  bool `json:"show_performance_stats"`
		ShowDeviceInfo        bool `json:"show_device_info"`
		ShowSocialGraph       bool `json:"show_social_graph"`
		ShowSecurityScore     bool `json:"show_security_score"`

		// Custom fields
		CustomFields []struct {
			Name        string `json:"name"`
			ToEveryone  bool   `json:"to_everyone"`
			ToOpers     bool   `json:"to_opers"`
			ToSelf      bool   `json:"to_self"`
			Format      string `json:"format"`
			Description string `json:"description"`
		} `json:"custom_fields"`
	} `json:"whois_features"`

	Channels struct {
		DefaultModes  string   `json:"default_modes"`
		AutoJoin      []string `json:"auto_join"`
		AdminChannels []string `json:"admin_channels"`
		FounderMode   string   `json:"founder_mode"` // Mode given to first user joining a channel: "o", "a", "q"
		AllowedModes  struct {
			Voice    bool `json:"voice"`    // +v
			Halfop   bool `json:"halfop"`   // +h
			Operator bool `json:"operator"` // +o
			Admin    bool `json:"admin"`    // +a
			Owner    bool `json:"owner"`    // +q
		} `json:"allowed_modes"`
		Modes struct {
			BanListSize    int `json:"ban_list_size"`
			ExceptListSize int `json:"except_list_size"`
			InviteListSize int `json:"invite_list_size"`
		} `json:"modes"`
	} `json:"channels"`

	Opers []struct {
		Name     string   `json:"name"`
		Password string   `json:"password"`
		Host     string   `json:"host"`
		Class    string   `json:"class"`
		Flags    []string `json:"flags"`
	} `json:"opers"`

	OperConfig struct {
		ConfigFile string `json:"config_file"`
		Enable     bool   `json:"enable"`
	} `json:"oper_config"`

	MOTD []string `json:"motd"`

	Linking struct {
		Enable      bool   `json:"enable"`
		ServerPort  int    `json:"server_port"`
		Password    string `json:"password"`
		Hub         bool   `json:"hub"`
		AutoConnect bool   `json:"auto_connect"`
		Links       []struct {
			Name        string `json:"name"`
			Host        string `json:"host"`
			Port        int    `json:"port"`
			Password    string `json:"password"`
			AutoConnect bool   `json:"auto_connect"`
			Hub         bool   `json:"hub"`
			Description string `json:"description"`
		} `json:"links"`
	} `json:"linking"`

	Logging struct {
		Level      string `json:"level"`
		File       string `json:"file"`
		MaxSize    int    `json:"max_size"`
		MaxBackups int    `json:"max_backups"`
		MaxAge     int    `json:"max_age"`
	} `json:"logging"`
}

func LoadConfig(filename string) (*Config, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("failed to read config file: %v", err)
	}

	var config Config
	if err := json.Unmarshal(data, &config); err != nil {
		return nil, fmt.Errorf("failed to parse config file: %v", err)
	}

	return &config, nil
}

func (c *Config) PingTimeoutDuration() time.Duration {
	return time.Duration(c.Limits.PingTimeout) * time.Second
}

func (c *Config) RegistrationTimeoutDuration() time.Duration {
	return time.Duration(c.Limits.RegistrationTimeout) * time.Second
}

func DefaultConfig() *Config {
	return &Config{
		Server: struct {
			Name        string `json:"name"`
			Network     string `json:"network"`
			Description string `json:"description"`
			Version     string `json:"version"`
			AdminInfo   string `json:"admin_info"`
			Listen      struct {
				Host      string `json:"host"`
				Port      int    `json:"port"`
				SSLPort   int    `json:"ssl_port"`
				EnableSSL bool   `json:"enable_ssl"`
			} `json:"listen"`
			SSL struct {
				CertFile   string `json:"cert_file"`
				KeyFile    string `json:"key_file"`
				RequireSSL bool   `json:"require_ssl"`
			} `json:"ssl"`
		}{
			Name:        "TechIRCd",
			Network:     "TechNet",
			Description: "A modern IRC server written in Go",
			Version:     "1.0.0",
			AdminInfo:   "admin@example.com",
			Listen: struct {
				Host      string `json:"host"`
				Port      int    `json:"port"`
				SSLPort   int    `json:"ssl_port"`
				EnableSSL bool   `json:"enable_ssl"`
			}{
				Host:      "localhost",
				Port:      6667,
				SSLPort:   6697,
				EnableSSL: false,
			},
			SSL: struct {
				CertFile   string `json:"cert_file"`
				KeyFile    string `json:"key_file"`
				RequireSSL bool   `json:"require_ssl"`
			}{
				CertFile:   "server.crt",
				KeyFile:    "server.key",
				RequireSSL: false,
			},
		},
		Limits: struct {
			MaxClients          int `json:"max_clients"`
			MaxChannels         int `json:"max_channels"`
			MaxChannelUsers     int `json:"max_channel_users"`
			MaxNickLength       int `json:"max_nick_length"`
			MaxChannelLength    int `json:"max_channel_length"`
			MaxTopicLength      int `json:"max_topic_length"`
			MaxKickLength       int `json:"max_kick_length"`
			MaxAwayLength       int `json:"max_away_length"`
			PingTimeout         int `json:"ping_timeout"`
			RegistrationTimeout int `json:"registration_timeout"`
			FloodLines          int `json:"flood_lines"`
			FloodSeconds        int `json:"flood_seconds"`
		}{
			MaxClients:          1000,
			MaxChannels:         100,
			MaxChannelUsers:     500,
			MaxNickLength:       30,
			MaxChannelLength:    50,
			MaxTopicLength:      307,
			MaxKickLength:       307,
			MaxAwayLength:       307,
			PingTimeout:         300,
			RegistrationTimeout: 60,
			FloodLines:          20,
			FloodSeconds:        10,
		},
		Features: struct {
			EnableOper     bool   `json:"enable_oper"`
			EnableServices bool   `json:"enable_services"`
			EnableModes    bool   `json:"enable_modes"`
			EnableCTCP     bool   `json:"enable_ctcp"`
			EnableDCC      bool   `json:"enable_dcc"`
			CaseMapping    string `json:"case_mapping"`
		}{
			EnableOper:     true,
			EnableServices: false,
			EnableModes:    true,
			EnableCTCP:     true,
			EnableDCC:      false,
			CaseMapping:    "rfc1459",
		},
		Channels: struct {
			DefaultModes  string   `json:"default_modes"`
			AutoJoin      []string `json:"auto_join"`
			AdminChannels []string `json:"admin_channels"`
			FounderMode   string   `json:"founder_mode"` // Mode given to first user joining a channel: "o", "a", "q"
			AllowedModes  struct {
				Voice    bool `json:"voice"`    // +v
				Halfop   bool `json:"halfop"`   // +h
				Operator bool `json:"operator"` // +o
				Admin    bool `json:"admin"`    // +a
				Owner    bool `json:"owner"`    // +q
			} `json:"allowed_modes"`
			Modes struct {
				BanListSize    int `json:"ban_list_size"`
				ExceptListSize int `json:"except_list_size"`
				InviteListSize int `json:"invite_list_size"`
			} `json:"modes"`
		}{
			DefaultModes:  "+nt",
			AutoJoin:      []string{"#general"},
			AdminChannels: []string{"#admin"},
			FounderMode:   "o", // Default to operator mode for channel founders
			AllowedModes: struct {
				Voice    bool `json:"voice"`
				Halfop   bool `json:"halfop"`
				Operator bool `json:"operator"`
				Admin    bool `json:"admin"`
				Owner    bool `json:"owner"`
			}{
				Voice:    true,
				Halfop:   true,
				Operator: true,
				Admin:    true,
				Owner:    true,
			},
			Modes: struct {
				BanListSize    int `json:"ban_list_size"`
				ExceptListSize int `json:"except_list_size"`
				InviteListSize int `json:"invite_list_size"`
			}{
				BanListSize:    100,
				ExceptListSize: 100,
				InviteListSize: 100,
			},
		},
		Opers: []struct {
			Name     string   `json:"name"`
			Password string   `json:"password"`
			Host     string   `json:"host"`
			Class    string   `json:"class"`
			Flags    []string `json:"flags"`
		}{
			{
				Name:     "admin",
				Password: "changeme",
				Host:     "*@localhost",
				Class:    "admin",
				Flags:    []string{"global_kill", "remote", "connect", "squit"},
			},
		},
		MOTD: []string{
			"Welcome to TechIRCd!",
			"A modern IRC server written in Go",
			"Enjoy your stay on TechNet!",
		},
		Logging: struct {
			Level      string `json:"level"`
			File       string `json:"file"`
			MaxSize    int    `json:"max_size"`
			MaxBackups int    `json:"max_backups"`
			MaxAge     int    `json:"max_age"`
		}{
			Level:      "info",
			File:       "techircd.log",
			MaxSize:    100,
			MaxBackups: 3,
			MaxAge:     28,
		},
	}
}

func SaveConfig(config *Config, filename string) error {
	data, err := json.MarshalIndent(config, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to marshal config: %v", err)
	}

	if err := os.WriteFile(filename, data, 0644); err != nil {
		return fmt.Errorf("failed to write config file: %v", err)
	}

	return nil
}
