package config

import (
	"errors"
	"strings"

	"hyapp/pkg/configx"
	"hyapp/pkg/logx"
)

// Config describes statistics-service dependencies and MQ subscriptions.
type Config struct {
	ServiceName      string         `yaml:"service_name"`
	NodeID           string         `yaml:"node_id"`
	Environment      string         `yaml:"environment"`
	HealthHTTPAddr   string         `yaml:"health_http_addr"`
	QueryHTTPAddr    string         `yaml:"query_http_addr"`
	MySQLDSN         string         `yaml:"mysql_dsn"`
	ActivityMySQLDSN string         `yaml:"activity_mysql_dsn"`
	RocketMQ         RocketMQConfig `yaml:"rocketmq"`
	Log              logx.Config    `yaml:"log"`
}

type RocketMQConfig struct {
	Enabled          bool             `yaml:"enabled"`
	NameServers      []string         `yaml:"name_servers"`
	NameServerDomain string           `yaml:"name_server_domain"`
	AccessKey        string           `yaml:"access_key"`
	SecretKey        string           `yaml:"secret_key"`
	SecurityToken    string           `yaml:"security_token"`
	Namespace        string           `yaml:"namespace"`
	VIPChannel       bool             `yaml:"vip_channel"`
	WalletOutbox     ConsumerMQConfig `yaml:"wallet_outbox"`
	RoomOutbox       ConsumerMQConfig `yaml:"room_outbox"`
	UserOutbox       ConsumerMQConfig `yaml:"user_outbox"`
	GameOutbox       ConsumerMQConfig `yaml:"game_outbox"`
	ActivityOutbox   ConsumerMQConfig `yaml:"activity_outbox"`
}

type ConsumerMQConfig struct {
	Enabled                   bool   `yaml:"enabled"`
	Topic                     string `yaml:"topic"`
	ConsumerGroup             string `yaml:"consumer_group"`
	ConsumerMaxReconsumeTimes int32  `yaml:"consumer_max_reconsume_times"`
}

func Default() Config {
	return Config{
		ServiceName:      "statistics-service",
		NodeID:           "statistics-local",
		Environment:      "local",
		HealthHTTPAddr:   ":13110",
		QueryHTTPAddr:    ":13010",
		MySQLDSN:         "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_statistics?parseTime=true&charset=utf8mb4&loc=UTC&multiStatements=true",
		ActivityMySQLDSN: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_activity?parseTime=true&charset=utf8mb4&loc=UTC",
		RocketMQ:         defaultRocketMQConfig(),
		Log: logx.Config{
			Level:           "info",
			Format:          "json",
			MaxPayloadBytes: 2048,
		},
	}
}

func Load(path string) (Config, error) {
	cfg := Default()
	if path != "" {
		if err := configx.LoadYAML(path, &cfg); err != nil {
			return Config{}, err
		}
	}
	cfg.ServiceName = strings.TrimSpace(cfg.ServiceName)
	if cfg.ServiceName == "" {
		cfg.ServiceName = "statistics-service"
	}
	cfg.NodeID = strings.TrimSpace(cfg.NodeID)
	if cfg.NodeID == "" {
		cfg.NodeID = cfg.ServiceName
	}
	cfg.Environment = strings.TrimSpace(cfg.Environment)
	if cfg.Environment == "" {
		cfg.Environment = "local"
	}
	cfg.HealthHTTPAddr = strings.TrimSpace(cfg.HealthHTTPAddr)
	if cfg.HealthHTTPAddr == "" {
		cfg.HealthHTTPAddr = ":13110"
	}
	cfg.QueryHTTPAddr = strings.TrimSpace(cfg.QueryHTTPAddr)
	if cfg.QueryHTTPAddr == "" {
		cfg.QueryHTTPAddr = ":13010"
	}
	cfg.MySQLDSN = strings.TrimSpace(cfg.MySQLDSN)
	cfg.ActivityMySQLDSN = strings.TrimSpace(cfg.ActivityMySQLDSN)
	cfg.RocketMQ = normalizeRocketMQConfig(cfg.RocketMQ)
	if cfg.RocketMQ.Enabled {
		if len(cfg.RocketMQ.NameServers) == 0 && cfg.RocketMQ.NameServerDomain == "" {
			return Config{}, errors.New("rocketmq name_servers or name_server_domain is required")
		}
		if (cfg.RocketMQ.AccessKey == "") != (cfg.RocketMQ.SecretKey == "") {
			return Config{}, errors.New("rocketmq access_key and secret_key must be configured together")
		}
	}
	return cfg, nil
}

func defaultRocketMQConfig() RocketMQConfig {
	return RocketMQConfig{
		Enabled:        false,
		WalletOutbox:   ConsumerMQConfig{Enabled: false, Topic: "hyapp_wallet_outbox", ConsumerGroup: "hyapp-statistics-wallet-outbox", ConsumerMaxReconsumeTimes: 16},
		RoomOutbox:     ConsumerMQConfig{Enabled: false, Topic: "hyapp_room_outbox", ConsumerGroup: "hyapp-statistics-room-outbox", ConsumerMaxReconsumeTimes: 16},
		UserOutbox:     ConsumerMQConfig{Enabled: false, Topic: "hyapp_user_outbox", ConsumerGroup: "hyapp-statistics-user-outbox", ConsumerMaxReconsumeTimes: 16},
		GameOutbox:     ConsumerMQConfig{Enabled: false, Topic: "hyapp_game_outbox", ConsumerGroup: "hyapp-statistics-game-outbox", ConsumerMaxReconsumeTimes: 16},
		ActivityOutbox: ConsumerMQConfig{Enabled: false, Topic: "hyapp_activity_outbox", ConsumerGroup: "hyapp-statistics-activity-outbox", ConsumerMaxReconsumeTimes: 16},
	}
}

func normalizeRocketMQConfig(cfg RocketMQConfig) RocketMQConfig {
	defaults := defaultRocketMQConfig()
	cfg.NameServers = normalizeStringSlice(cfg.NameServers)
	cfg.NameServerDomain = strings.TrimSpace(cfg.NameServerDomain)
	cfg.AccessKey = strings.TrimSpace(cfg.AccessKey)
	cfg.SecretKey = strings.TrimSpace(cfg.SecretKey)
	cfg.SecurityToken = strings.TrimSpace(cfg.SecurityToken)
	cfg.Namespace = strings.TrimSpace(cfg.Namespace)
	cfg.WalletOutbox = normalizeConsumer(cfg.WalletOutbox, defaults.WalletOutbox)
	cfg.RoomOutbox = normalizeConsumer(cfg.RoomOutbox, defaults.RoomOutbox)
	cfg.UserOutbox = normalizeConsumer(cfg.UserOutbox, defaults.UserOutbox)
	cfg.GameOutbox = normalizeConsumer(cfg.GameOutbox, defaults.GameOutbox)
	cfg.ActivityOutbox = normalizeConsumer(cfg.ActivityOutbox, defaults.ActivityOutbox)
	if cfg.WalletOutbox.Enabled || cfg.RoomOutbox.Enabled || cfg.UserOutbox.Enabled || cfg.GameOutbox.Enabled || cfg.ActivityOutbox.Enabled {
		cfg.Enabled = true
	}
	return cfg
}

func normalizeConsumer(cfg ConsumerMQConfig, defaults ConsumerMQConfig) ConsumerMQConfig {
	if cfg.Topic = strings.TrimSpace(cfg.Topic); cfg.Topic == "" {
		cfg.Topic = defaults.Topic
	}
	if cfg.ConsumerGroup = strings.TrimSpace(cfg.ConsumerGroup); cfg.ConsumerGroup == "" {
		cfg.ConsumerGroup = defaults.ConsumerGroup
	}
	if cfg.ConsumerMaxReconsumeTimes <= 0 {
		cfg.ConsumerMaxReconsumeTimes = defaults.ConsumerMaxReconsumeTimes
	}
	return cfg
}

func normalizeStringSlice(values []string) []string {
	normalized := make([]string, 0, len(values))
	for _, value := range values {
		if value = strings.TrimSpace(value); value != "" {
			normalized = append(normalized, value)
		}
	}
	return normalized
}
