// SPDX-License-Identifier: 0BSD
// Copyright (c) 2024-2026 Sudo-Ivan / Quad4.io
package config

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"git.quad4.io/Networks/Reticulum-Go/pkg/common"
)

const (
	DefaultSharedInstancePort  = 37428
	DefaultInstanceControlPort = 37429
	DefaultLogLevel            = 4
)

func DefaultConfig() *common.ReticulumConfig {
	return &common.ReticulumConfig{
		EnableTransport:     true,
		ShareInstance:       true,
		SharedInstancePort:  DefaultSharedInstancePort,
		InstanceControlPort: DefaultInstanceControlPort,
		PanicOnInterfaceErr: false,
		LogLevel:            DefaultLogLevel,
		Interfaces:          make(map[string]*common.InterfaceConfig),
	}
}

func GetConfigPath() (string, error) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(homeDir, ".reticulum-go", "config"), nil
}

func EnsureConfigDir() error {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return err
	}

	configDir := filepath.Join(homeDir, ".reticulum-go")
	return os.MkdirAll(configDir, 0700) // #nosec G301
}

// parseValue parses string values into appropriate types
func parseValue(value string) interface{} {
	value = strings.TrimSpace(value)

	// Try bool
	if value == "true" {
		return true
	}
	if value == "false" {
		return false
	}

	// Try int
	if i, err := strconv.Atoi(value); err == nil {
		return i
	}

	// Return as string
	return value
}

// LoadConfig loads the configuration from the specified path
func LoadConfig(path string) (*common.ReticulumConfig, error) {
	// bearer:disable go_gosec_filesystem_filereadtaint
	file, err := os.Open(path) // #nosec G304
	if err != nil {
		return nil, err
	}
	defer file.Close()

	cfg := DefaultConfig()
	cfg.ConfigPath = path

	scanner := bufio.NewScanner(file)
	var currentInterface *common.InterfaceConfig

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())

		// Skip comments and empty lines
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		// Handle interface sections
		if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
			name := strings.Trim(line, "[]")
			currentInterface = &common.InterfaceConfig{Name: name}
			cfg.Interfaces[name] = currentInterface
			continue
		}

		parts := strings.SplitN(line, "=", 2)
		if len(parts) != 2 {
			continue
		}

		key := strings.TrimSpace(parts[0])
		value := strings.TrimSpace(parts[1])

		if currentInterface != nil {
			// Parse interface config
			switch key {
			case "type":
				currentInterface.Type = value
			case "enabled":
				currentInterface.Enabled = value == "true"
			case "address":
				currentInterface.Address = value
			case "port":
				currentInterface.Port, _ = strconv.Atoi(value)
			case "target_host":
				currentInterface.TargetHost = value
			case "target_port":
				currentInterface.TargetPort, _ = strconv.Atoi(value)
			case "discovery_port":
				currentInterface.DiscoveryPort, _ = strconv.Atoi(value)
			case "data_port":
				currentInterface.DataPort, _ = strconv.Atoi(value)
			case "discovery_scope":
				currentInterface.DiscoveryScope = value
			case "group_id":
				currentInterface.GroupID = value
			}
		} else {
			// Parse global config
			switch key {
			case "enable_transport":
				cfg.EnableTransport = value == "true"
			case "share_instance":
				cfg.ShareInstance = value == "true"
			case "shared_instance_port":
				cfg.SharedInstancePort, _ = strconv.Atoi(value)
			case "instance_control_port":
				cfg.InstanceControlPort, _ = strconv.Atoi(value)
			case "panic_on_interface_error":
				cfg.PanicOnInterfaceErr = value == "true"
			case "loglevel":
				cfg.LogLevel, _ = strconv.Atoi(value)
			}
		}
	}

	return cfg, nil
}

// SaveConfig saves the configuration to the specified path
func SaveConfig(cfg *common.ReticulumConfig) error {
	if cfg.ConfigPath == "" {
		return fmt.Errorf("config path not set")
	}

	var builder strings.Builder

	// Write global config
	builder.WriteString("# Reticulum Configuration\n")
	builder.WriteString(fmt.Sprintf("enable_transport = %v\n", cfg.EnableTransport))
	builder.WriteString(fmt.Sprintf("share_instance = %v\n", cfg.ShareInstance))
	builder.WriteString(fmt.Sprintf("shared_instance_port = %d\n", cfg.SharedInstancePort))
	builder.WriteString(fmt.Sprintf("instance_control_port = %d\n", cfg.InstanceControlPort))
	builder.WriteString(fmt.Sprintf("panic_on_interface_error = %v\n", cfg.PanicOnInterfaceErr))
	builder.WriteString(fmt.Sprintf("loglevel = %d\n\n", cfg.LogLevel))

	// Write interface configs
	for name, iface := range cfg.Interfaces {
		builder.WriteString(fmt.Sprintf("[%s]\n", name))
		builder.WriteString(fmt.Sprintf("type = %s\n", iface.Type))
		builder.WriteString(fmt.Sprintf("enabled = %v\n", iface.Enabled))

		if iface.Address != "" {
			builder.WriteString(fmt.Sprintf("address = %s\n", iface.Address))
		}
		if iface.Port != 0 {
			builder.WriteString(fmt.Sprintf("port = %d\n", iface.Port))
		}
		if iface.TargetHost != "" {
			builder.WriteString(fmt.Sprintf("target_host = %s\n", iface.TargetHost))
		}
		if iface.TargetPort != 0 {
			builder.WriteString(fmt.Sprintf("target_port = %d\n", iface.TargetPort))
		}
		if iface.DiscoveryPort != 0 {
			builder.WriteString(fmt.Sprintf("discovery_port = %d\n", iface.DiscoveryPort))
		}
		if iface.DataPort != 0 {
			builder.WriteString(fmt.Sprintf("data_port = %d\n", iface.DataPort))
		}
		if iface.DiscoveryScope != "" {
			builder.WriteString(fmt.Sprintf("discovery_scope = %s\n", iface.DiscoveryScope))
		}
		if iface.GroupID != "" {
			builder.WriteString(fmt.Sprintf("group_id = %s\n", iface.GroupID))
		}
		builder.WriteString("\n")
	}

	return os.WriteFile(cfg.ConfigPath, []byte(builder.String()), 0600) // #nosec G306
}

// CreateDefaultConfig creates a default configuration file
func CreateDefaultConfig(path string) error {
	cfg := DefaultConfig()
	cfg.ConfigPath = path

	cfg.Interfaces["Auto Discovery"] = &common.InterfaceConfig{
		Type:           "AutoInterface",
		Enabled:        true,
		GroupID:        "reticulum",
		DiscoveryScope: "link",
		DiscoveryPort:  29716,
		DataPort:       42671,
	}

	cfg.Interfaces["Go-RNS-Testnet"] = &common.InterfaceConfig{
		Type:       "TCPClientInterface",
		Enabled:    true,
		TargetHost: "127.0.0.1",
		TargetPort: 4242,
		Name:       "Go-RNS-Testnet",
	}

	cfg.Interfaces["Quad4 TCP"] = &common.InterfaceConfig{
		Type:       "TCPClientInterface",
		Enabled:    true,
		TargetHost: "rns.quad4.io",
		TargetPort: 4242,
		Name:       "Quad4 TCP",
	}

	cfg.Interfaces["Local UDP"] = &common.InterfaceConfig{
		Type:    "UDPInterface",
		Enabled: false,
		Address: "0.0.0.0",
		Port:    37696,
	}

	if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { // #nosec G301
		return err
	}

	return SaveConfig(cfg)
}

// InitConfig initializes the configuration system
func InitConfig() (*common.ReticulumConfig, error) {
	configPath, err := GetConfigPath()
	if err != nil {
		return nil, err
	}

	// Check if config file exists
	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		// Create default config
		if err := CreateDefaultConfig(configPath); err != nil {
			return nil, err
		}
	}

	// Load config
	return LoadConfig(configPath)
}
