package config

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type Config struct {
	GRPCListenAddr    string
	GRPCAdvertiseAddr string
	DiscoveryPort     int
	UARTDevice        string
	UARTBaud          int
}

func Default() Config {
	return Config{
		GRPCListenAddr:    ":50051",
		GRPCAdvertiseAddr: "127.0.0.1:50051",
		DiscoveryPort:     50052,
		UARTDevice:        "/dev/ttyS3",
		UARTBaud:          115200,
	}
}

func Load(path string) (Config, error) {
	cfg := Default()
	if path == "" {
		return cfg, nil
	}

	f, err := os.Open(path)
	if err != nil {
		if os.IsNotExist(err) {
			return cfg, nil
		}
		return Config{}, err
	}
	defer f.Close()

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		key, value, ok := strings.Cut(line, ":")
		if !ok {
			return Config{}, fmt.Errorf("invalid config line: %q", line)
		}

		key = strings.ToLower(strings.TrimSpace(key))
		value = strings.TrimSpace(value)
		value = strings.Trim(value, `"'`)

		switch key {
		case "grpc_addr":
			cfg.GRPCListenAddr = value
			cfg.GRPCAdvertiseAddr = value
		case "grpc_listen_addr":
			cfg.GRPCListenAddr = value
		case "grpc_advertise_addr":
			cfg.GRPCAdvertiseAddr = value
		case "discovery_port":
			n, err := strconv.Atoi(value)
			if err != nil {
				return Config{}, fmt.Errorf("invalid discovery_port: %w", err)
			}
			cfg.DiscoveryPort = n
		case "uart_device":
			cfg.UARTDevice = value
		case "uart_baud":
			n, err := strconv.Atoi(value)
			if err != nil {
				return Config{}, fmt.Errorf("invalid uart_baud: %w", err)
			}
			cfg.UARTBaud = n
		}
	}

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

	if cfg.GRPCAdvertiseAddr == "" {
		cfg.GRPCAdvertiseAddr = cfg.GRPCListenAddr
	}

	return cfg, nil
}
