package auth

import (
	"context"
	"fmt"
	"strings"

	"hyapp/pkg/xerr"
	authdomain "hyapp/services/user-service/internal/domain/auth"
)

type edgeCountryProvider struct{}

type staticCountryProvider struct {
	name        string
	countryCode string
}

type unavailableIPGeoProvider struct {
	name string
}

func BuildIPGeoProviders(names []string) []IPGeoProvider {
	providers := make([]IPGeoProvider, 0, len(names))
	for _, name := range names {
		name = strings.TrimSpace(name)
		if name == "" {
			continue
		}
		switch {
		case strings.EqualFold(name, "edge_country"):
			providers = append(providers, edgeCountryProvider{})
		case strings.HasPrefix(strings.ToLower(name), "static:"):
			country := normalizeCountryCode(strings.TrimPrefix(name, "static:"))
			providers = append(providers, staticCountryProvider{name: name, countryCode: country})
		default:
			// 未配置具体 provider 适配器时显式降级为 unavailable，worker 会按顺序继续尝试下一个。
			providers = append(providers, unavailableIPGeoProvider{name: name})
		}
	}
	return providers
}

func (p edgeCountryProvider) Name() string {
	return "edge_country"
}

func (p edgeCountryProvider) ResolveCountry(_ context.Context, job authdomain.LoginIPRiskJob) (IPGeoResult, error) {
	country := normalizeCountryCode(job.EdgeCountryCode)
	if country == "" {
		return IPGeoResult{}, xerr.New(xerr.Unavailable, "edge country is empty")
	}
	return IPGeoResult{CountryCode: country, Confidence: 60}, nil
}

func (p staticCountryProvider) Name() string {
	return p.name
}

func (p staticCountryProvider) ResolveCountry(_ context.Context, _ authdomain.LoginIPRiskJob) (IPGeoResult, error) {
	if p.countryCode == "" {
		return IPGeoResult{}, xerr.New(xerr.Unavailable, "static country is empty")
	}
	return IPGeoResult{CountryCode: p.countryCode, Confidence: 100}, nil
}

func (p unavailableIPGeoProvider) Name() string {
	return p.name
}

func (p unavailableIPGeoProvider) ResolveCountry(_ context.Context, _ authdomain.LoginIPRiskJob) (IPGeoResult, error) {
	return IPGeoResult{}, fmt.Errorf("ip geo provider %s is not configured", p.name)
}
