package serverimp

import (
	"os"
	"strings"
	"time"

	"github.com/tech/sendico/pkg/api/routers"
	"github.com/tech/sendico/pkg/server/grpcapp"
	"go.uber.org/zap"
	"gopkg.in/yaml.v3"
)

type config struct {
	*grpcapp.Config   `yaml:",inline"`
	CardGateways      map[string]cardGatewayRouteConfig `yaml:"card_gateways"`
	GatewayInstances  []gatewayInstanceConfig           `yaml:"gateway_instances"`
	Optimizer         optimizerConfig                   `yaml:"optimizer"`
	QuoteRetentionHrs int                               `yaml:"quote_retention_hours"`
}

type optimizerConfig struct {
	Aggregation aggregationConfig `yaml:"aggregation"`
}

type aggregationConfig struct {
	DefaultMode string                  `yaml:"default_mode"`
	Rules       []aggregationRuleConfig `yaml:"rules"`
}

type aggregationRuleConfig struct {
	ID       string                 `yaml:"id"`
	Enabled  *bool                  `yaml:"enabled"`
	Priority int                    `yaml:"priority"`
	Mode     string                 `yaml:"mode"`
	GroupBy  string                 `yaml:"group_by"`
	Match    aggregationMatchConfig `yaml:"match"`
}

type aggregationMatchConfig struct {
	Rail       string                   `yaml:"rail"`
	Providers  []string                 `yaml:"providers"`
	Networks   []string                 `yaml:"networks"`
	Currencies []string                 `yaml:"currencies"`
	Amount     *aggregationAmountConfig `yaml:"amount"`
}

type aggregationAmountConfig struct {
	Min      string `yaml:"min"`
	Max      string `yaml:"max"`
	Currency string `yaml:"currency"`
}

type cardGatewayRouteConfig struct {
	FundingAddress string `yaml:"funding_address"`
	FeeAddress     string `yaml:"fee_address"`
	FeeWalletRef   string `yaml:"fee_wallet_ref"`
}

type gatewayInstanceConfig struct {
	ID           string                    `yaml:"id"`
	Rail         string                    `yaml:"rail"`
	Network      string                    `yaml:"network"`
	Currencies   []string                  `yaml:"currencies"`
	Capabilities gatewayCapabilitiesConfig `yaml:"capabilities"`
	Limits       limitsConfig              `yaml:"limits"`
	Version      string                    `yaml:"version"`
	IsEnabled    *bool                     `yaml:"is_enabled"`
}

type gatewayCapabilitiesConfig struct {
	CanPayIn               bool `yaml:"can_pay_in"`
	CanPayOut              bool `yaml:"can_pay_out"`
	CanReadBalance         bool `yaml:"can_read_balance"`
	CanSendFee             bool `yaml:"can_send_fee"`
	RequiresObserveConfirm bool `yaml:"requires_observe_confirm"`
	CanBlock               bool `yaml:"can_block"`
	CanRelease             bool `yaml:"can_release"`
}

type limitsConfig struct {
	MinAmount      string                       `yaml:"min_amount"`
	MaxAmount      string                       `yaml:"max_amount"`
	PerTxMaxFee    string                       `yaml:"per_tx_max_fee"`
	PerTxMinAmount string                       `yaml:"per_tx_min_amount"`
	PerTxMaxAmount string                       `yaml:"per_tx_max_amount"`
	VolumeLimit    map[string]string            `yaml:"volume_limit"`
	VelocityLimit  map[string]int               `yaml:"velocity_limit"`
	CurrencyLimits map[string]limitsOverrideCfg `yaml:"currency_limits"`
}

type limitsOverrideCfg struct {
	MaxVolume string `yaml:"max_volume"`
	MinAmount string `yaml:"min_amount"`
	MaxAmount string `yaml:"max_amount"`
	MaxFee    string `yaml:"max_fee"`
	MaxOps    int    `yaml:"max_ops"`
}

func (c *config) quoteRetention() time.Duration {
	if c == nil || c.QuoteRetentionHrs <= 0 {
		return 72 * time.Hour
	}
	return time.Duration(c.QuoteRetentionHrs) * time.Hour
}

func (i *Imp) loadConfig() (*config, error) {
	data, err := os.ReadFile(i.file)
	if err != nil {
		i.logger.Error("Could not read configuration file", zap.String("config_file", i.file), zap.Error(err))
		return nil, err
	}

	cfg := &config{Config: &grpcapp.Config{}}
	if err := yaml.Unmarshal(data, cfg); err != nil {
		i.logger.Error("Failed to parse configuration", zap.Error(err))
		return nil, err
	}

	if cfg.Runtime == nil {
		cfg.Runtime = &grpcapp.RuntimeConfig{ShutdownTimeoutSeconds: 15}
	}

	if cfg.GRPC == nil {
		cfg.GRPC = &routers.GRPCConfig{
			Network:          "tcp",
			Address:          ":50062",
			EnableReflection: true,
			EnableHealth:     true,
		}
	} else {
		if strings.TrimSpace(cfg.GRPC.Address) == "" {
			cfg.GRPC.Address = ":50062"
		}
		if strings.TrimSpace(cfg.GRPC.Network) == "" {
			cfg.GRPC.Network = "tcp"
		}
	}

	if cfg.Metrics == nil {
		cfg.Metrics = &grpcapp.MetricsConfig{Address: ":9403"}
	} else if strings.TrimSpace(cfg.Metrics.Address) == "" {
		cfg.Metrics.Address = ":9403"
	}

	return cfg, nil
}
