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

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

type Config struct {
	Identity struct {
		Name        string
		StoragePath string
	}

	Interfaces []struct {
		Name        string
		Type        string
		Enabled     bool
		ListenPort  int
		ListenIP    string
		KissFraming bool
		I2PTunneled bool
	}

	Transport struct {
		AnnounceInterval   int
		PathRequestTimeout int
		MaxHops            int
		BitrateLimit       int64
	}

	Logging struct {
		Level string
		File  string
	}
}

func LoadConfig(path string) (*Config, error) {
	// bearer:disable go_gosec_filesystem_filereadtaint
	file, err := os.Open(path) // #nosec G304
	if err != nil {
		return nil, err
	}
	defer file.Close()

	cfg := &Config{}
	scanner := bufio.NewScanner(file)
	var currentSection string

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

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

		// Handle sections
		if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
			currentSection = strings.Trim(line, "[]")

			// If this is an interface section, append new interface
			if strings.HasPrefix(currentSection, "interface ") {
				cfg.Interfaces = append(cfg.Interfaces, struct {
					Name        string
					Type        string
					Enabled     bool
					ListenPort  int
					ListenIP    string
					KissFraming bool
					I2PTunneled bool
				}{})
			}
			continue
		}

		// Parse key-value pairs
		parts := strings.SplitN(line, "=", 2)
		if len(parts) != 2 {
			continue
		}

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

		switch currentSection {
		case "identity":
			switch key {
			case "name":
				cfg.Identity.Name = value
			case "storage_path":
				cfg.Identity.StoragePath = value
			}

		case "transport":
			switch key {
			case "announce_interval":
				cfg.Transport.AnnounceInterval, _ = strconv.Atoi(value)
			case "path_request_timeout":
				cfg.Transport.PathRequestTimeout, _ = strconv.Atoi(value)
			case "max_hops":
				cfg.Transport.MaxHops, _ = strconv.Atoi(value)
			case "bitrate_limit":
				cfg.Transport.BitrateLimit, _ = strconv.ParseInt(value, 10, 64)
			}

		case "logging":
			switch key {
			case "level":
				cfg.Logging.Level = value
			case "file":
				cfg.Logging.File = value
			}

		default:
			// Handle interface sections
			if strings.HasPrefix(currentSection, "interface ") && len(cfg.Interfaces) > 0 {
				iface := &cfg.Interfaces[len(cfg.Interfaces)-1]
				switch key {
				case "name":
					iface.Name = value
				case "type":
					iface.Type = value
				case "enabled":
					iface.Enabled = value == "true"
				case "listen_port":
					iface.ListenPort, _ = strconv.Atoi(value)
				case "listen_ip":
					iface.ListenIP = value
				case "kiss_framing":
					iface.KissFraming = value == "true"
				case "i2p_tunneled":
					iface.I2PTunneled = value == "true"
				}
			}
		}
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return cfg, nil
}

func SaveConfig(cfg *Config, path string) error {
	var builder strings.Builder

	// Write Identity section
	builder.WriteString("[identity]\n")
	builder.WriteString(fmt.Sprintf("name = %s\n", cfg.Identity.Name))
	builder.WriteString(fmt.Sprintf("storage_path = %s\n\n", cfg.Identity.StoragePath))

	// Write Transport section
	builder.WriteString("[transport]\n")
	builder.WriteString(fmt.Sprintf("announce_interval = %d\n", cfg.Transport.AnnounceInterval))
	builder.WriteString(fmt.Sprintf("path_request_timeout = %d\n", cfg.Transport.PathRequestTimeout))
	builder.WriteString(fmt.Sprintf("max_hops = %d\n", cfg.Transport.MaxHops))
	builder.WriteString(fmt.Sprintf("bitrate_limit = %d\n\n", cfg.Transport.BitrateLimit))

	// Write Logging section
	builder.WriteString("[logging]\n")
	builder.WriteString(fmt.Sprintf("level = %s\n", cfg.Logging.Level))
	builder.WriteString(fmt.Sprintf("file = %s\n\n", cfg.Logging.File))

	// Write Interface sections
	for _, iface := range cfg.Interfaces {
		builder.WriteString(fmt.Sprintf("[interface %s]\n", iface.Name))
		builder.WriteString(fmt.Sprintf("type = %s\n", iface.Type))
		builder.WriteString(fmt.Sprintf("enabled = %v\n", iface.Enabled))
		builder.WriteString(fmt.Sprintf("listen_port = %d\n", iface.ListenPort))
		builder.WriteString(fmt.Sprintf("listen_ip = %s\n", iface.ListenIP))
		builder.WriteString(fmt.Sprintf("kiss_framing = %v\n", iface.KissFraming))
		builder.WriteString(fmt.Sprintf("i2p_tunneled = %v\n\n", iface.I2PTunneled))
	}

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

func GetConfigDir() string {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		// Fallback to current directory if home directory cannot be determined
		return ".reticulum-go"
	}
	return filepath.Join(homeDir, ".reticulum-go")
}

func GetDefaultConfigPath() string {
	return filepath.Join(GetConfigDir(), "config")
}

func EnsureConfigDir() error {
	configDir := GetConfigDir()
	return os.MkdirAll(configDir, 0700) // #nosec G301
}

func InitConfig() (*Config, error) {
	// Ensure config directory exists
	if err := EnsureConfigDir(); err != nil {
		return nil, fmt.Errorf("failed to create config directory: %v", err)
	}

	configPath := GetDefaultConfigPath()

	// Check if config file exists
	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		// Create default config
		cfg := &Config{}

		// Set default values
		cfg.Identity.Name = "reticulum-node"
		cfg.Identity.StoragePath = filepath.Join(GetConfigDir(), "storage")

		cfg.Transport.AnnounceInterval = 300
		cfg.Transport.PathRequestTimeout = 15
		cfg.Transport.MaxHops = 8
		cfg.Transport.BitrateLimit = 1000000

		cfg.Logging.Level = "info"
		cfg.Logging.File = filepath.Join(GetConfigDir(), "reticulum.log")

		cfg.Interfaces = append(cfg.Interfaces, struct {
			Name        string
			Type        string
			Enabled     bool
			ListenPort  int
			ListenIP    string
			KissFraming bool
			I2PTunneled bool
		}{
			Name:       "Local UDP",
			Type:       "UDPInterface",
			Enabled:    true,
			ListenPort: 37697,
			ListenIP:   "0.0.0.0",
		})

		cfg.Interfaces = append(cfg.Interfaces, struct {
			Name        string
			Type        string
			Enabled     bool
			ListenPort  int
			ListenIP    string
			KissFraming bool
			I2PTunneled bool
		}{
			Name:       "Auto Discovery",
			Type:       "AutoInterface",
			Enabled:    true,
			ListenPort: 29717,
		})

		// Save default config
		if err := SaveConfig(cfg, configPath); err != nil {
			return nil, fmt.Errorf("failed to save default config: %v", err)
		}
	}

	// Load config
	cfg, err := LoadConfig(configPath)
	if err != nil {
		return nil, fmt.Errorf("failed to load config: %v", err)
	}

	return cfg, nil
}
