package config

import (
	"fmt"
	"os"
	"time"

	"gopkg.in/yaml.v3"
)

type Config struct {
	Server   ServerConfig   `yaml:"server"`
	Database DatabaseConfig `yaml:"database"`
	World    WorldConfig    `yaml:"world"`
	Network  NetworkConfig  `yaml:"network"`
	Log      LogConfig      `yaml:"log"`
}

type DatabaseConfig struct {
	Host         string        `yaml:"host"`
	Port         int           `yaml:"port"`
	User         string        `yaml:"user"`
	Password     string        `yaml:"password"`
	DBName       string        `yaml:"dbname"`
	MaxConns     int32         `yaml:"max_conns"`
	MinConns     int32         `yaml:"min_conns"`
	SaveInterval time.Duration `yaml:"save_interval"`
}

func (d *DatabaseConfig) DSN() string {
	return fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable",
		d.User, d.Password, d.Host, d.Port, d.DBName)
}

type ServerConfig struct {
	Host string `yaml:"host"`
	Port int    `yaml:"port"`
}

type WorldConfig struct {
	TickRate   int       `yaml:"tick_rate"`
	AOI        AOIConfig `yaml:"aoi"`
	MaxPlayers int       `yaml:"max_players"`
}

type AOIConfig struct {
	Enabled   bool    `yaml:"enabled"`
	CellSize  float32 `yaml:"cell_size"`
	ViewRange int     `yaml:"view_range"`
}

type NetworkConfig struct {
	WriteBufferSize  int           `yaml:"write_buffer_size"`
	ReadBufferSize   int           `yaml:"read_buffer_size"`
	SendChannelSize  int           `yaml:"send_channel_size"`
	HeartbeatInterval time.Duration `yaml:"heartbeat_interval"`
	HeartbeatTimeout  time.Duration `yaml:"heartbeat_timeout"`
	MaxMessageSize   int64         `yaml:"max_message_size"`
}

type LogConfig struct {
	Level string `yaml:"level"`
}

func (c *Config) TickInterval() time.Duration {
	return time.Second / time.Duration(c.World.TickRate)
}

func (c *ServerConfig) Address() string {
	return fmt.Sprintf("%s:%d", c.Host, c.Port)
}

func Load(path string) (*Config, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("read config file: %w", err)
	}

	cfg := defaultConfig()
	if err := yaml.Unmarshal(data, cfg); err != nil {
		return nil, fmt.Errorf("parse config file: %w", err)
	}

	return cfg, nil
}

func defaultConfig() *Config {
	return &Config{
		Server: ServerConfig{
			Host: "0.0.0.0",
			Port: 8080,
		},
		World: WorldConfig{
			TickRate:   20,
			MaxPlayers: 5000,
			AOI: AOIConfig{
				Enabled:   true,
				CellSize:  50.0,
				ViewRange: 2,
			},
		},
		Database: DatabaseConfig{
			Host:         "localhost",
			Port:         5432,
			User:         "postgres",
			Password:     "postgres",
			DBName:       "mmorpg",
			MaxConns:     50,
			MinConns:     5,
			SaveInterval: 60 * time.Second,
		},
		Network: NetworkConfig{
			WriteBufferSize:   4096,
			ReadBufferSize:    4096,
			SendChannelSize:   256,
			HeartbeatInterval: 5 * time.Second,
			HeartbeatTimeout:  15 * time.Second,
			MaxMessageSize:    8192,
		},
		Log: LogConfig{
			Level: "info",
		},
	}
}
