package integration

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	paymentutil "kra/pkg/paymentkit"
	"sort"
	"strconv"
	"strings"
	"time"
)

const (
	IntegrationKindPayment   = "payment"
	IntegrationKindMQ        = "mq"
	IntegrationKindWebSocket = "websocket"
)

type IntegrationConfig struct {
	Kind     string
	Provider string
	Enabled  bool
	Values   json.RawMessage
}

type IntegrationConfigField struct {
	Key         string                    `json:"key"`
	Label       string                    `json:"label"`
	Type        string                    `json:"type"`
	Required    bool                      `json:"required"`
	Secret      bool                      `json:"secret"`
	Placeholder string                    `json:"placeholder,omitempty"`
	Description string                    `json:"description,omitempty"`
	Options     []IntegrationConfigOption `json:"options,omitempty"`
}

type IntegrationConfigOption struct {
	Label string `json:"label"`
	Value any    `json:"value"`
}

type IntegrationConfigDefinition struct {
	Kind        string                   `json:"kind"`
	Provider    string                   `json:"provider"`
	Name        string                   `json:"name"`
	Description string                   `json:"description,omitempty"`
	Fields      []IntegrationConfigField `json:"fields"`
	Defaults    map[string]any           `json:"defaults"`
}

type IntegrationConfigRepo interface {
	ListIntegrationConfigs(context.Context, string) ([]*IntegrationConfig, error)
	FindIntegrationConfig(context.Context, string, string) (*IntegrationConfig, error)
	SaveIntegrationConfig(context.Context, *IntegrationConfig) error
	DeleteIntegrationConfig(context.Context, string, string) error
}

// ErrPaymentConfigNotFound marks an absent payment integration row without
// exposing the storage driver's not-found error to the payment data module.
var ErrPaymentConfigNotFound = errors.New("支付渠道配置不存在")

// PaymentConfig is the storage-neutral, unmasked snapshot used by payment
// persistence. It deliberately contains no ORM or table metadata.
type PaymentConfig struct {
	Enabled bool
	Values  json.RawMessage
}

// PaymentConfigReader is the narrow inversion seam between the payment and
// integration data modules. The integration module owns its ConfigPO.
type PaymentConfigReader interface {
	ReadPaymentConfig(context.Context, string) (*PaymentConfig, error)
}

type IntegrationConnectionTester interface {
	TestIntegration(context.Context, *IntegrationConfig) error
}

type IntegrationConfigUsecase struct {
	repo   IntegrationConfigRepo
	tester IntegrationConnectionTester
}

func NewIntegrationConfigUsecase(repo IntegrationConfigRepo, tester IntegrationConnectionTester) *IntegrationConfigUsecase {
	return &IntegrationConfigUsecase{repo: repo, tester: tester}
}

func (uc *IntegrationConfigUsecase) List(ctx context.Context, kind string) ([]*IntegrationConfig, error) {
	kind = normalizeIntegrationPart(kind)
	if kind == "" {
		return nil, errors.New("集成配置 kind 不能为空")
	}
	return uc.repo.ListIntegrationConfigs(ctx, kind)
}

func (uc *IntegrationConfigUsecase) Find(ctx context.Context, kind, provider string) (*IntegrationConfig, error) {
	kind, provider = normalizeIntegrationPart(kind), normalizeIntegrationPart(provider)
	if kind == "" || provider == "" {
		return nil, errors.New("集成配置 kind 和 provider 不能为空")
	}
	return uc.repo.FindIntegrationConfig(ctx, kind, provider)
}

func (uc *IntegrationConfigUsecase) Save(ctx context.Context, config *IntegrationConfig) error {
	if config == nil {
		return errors.New("集成配置请求为空")
	}
	config.Kind = normalizeIntegrationPart(config.Kind)
	config.Provider = normalizeIntegrationPart(config.Provider)
	if config.Kind == "" || config.Provider == "" || len(config.Kind) > 32 || len(config.Provider) > 64 {
		return errors.New("集成配置 kind 或 provider 无效")
	}
	if !json.Valid(config.Values) {
		return errors.New("集成配置必须是合法 JSON")
	}
	values, err := decodeIntegrationObject(config.Values)
	if err != nil {
		return err
	}
	if definition, ok := IntegrationDefinition(config.Kind, config.Provider); ok {
		values = mergeIntegrationDefaults(definition.Defaults, values)
		if config.Enabled {
			if err := ValidateIntegrationConfig(config.Kind, config.Provider, values); err != nil {
				return err
			}
		}
		config.Values, _ = json.Marshal(values)
	}
	return uc.repo.SaveIntegrationConfig(ctx, config)
}

// Test validates and probes a candidate configuration without persisting it.
// The adapter may resolve masked secret values from the active runtime store.
func (uc *IntegrationConfigUsecase) Test(ctx context.Context, config *IntegrationConfig) error {
	if config == nil {
		return errors.New("集成配置请求为空")
	}
	config.Kind = normalizeIntegrationPart(config.Kind)
	config.Provider = normalizeIntegrationPart(config.Provider)
	if config.Kind != IntegrationKindMQ && config.Kind != IntegrationKindWebSocket {
		return errors.New("仅支持测试消息队列和 WebSocket 集成")
	}
	if config.Kind == "" || config.Provider == "" || len(config.Kind) > 32 || len(config.Provider) > 64 {
		return errors.New("集成配置 kind 或 provider 无效")
	}
	if !json.Valid(config.Values) {
		return errors.New("集成配置必须是合法 JSON")
	}
	values, err := decodeIntegrationObject(config.Values)
	if err != nil {
		return err
	}
	if definition, ok := IntegrationDefinition(config.Kind, config.Provider); ok {
		values = mergeIntegrationDefaults(definition.Defaults, values)
	}
	if err := ValidateIntegrationConfig(config.Kind, config.Provider, values); err != nil {
		return err
	}
	encoded, _ := json.Marshal(values)
	config.Enabled = true
	config.Values = encoded
	if uc.tester == nil {
		return errors.New("集成连接测试器未初始化")
	}
	return uc.tester.TestIntegration(ctx, config)
}

func (uc *IntegrationConfigUsecase) Delete(ctx context.Context, kind, provider string) error {
	kind, provider = normalizeIntegrationPart(kind), normalizeIntegrationPart(provider)
	if kind == "" || provider == "" {
		return errors.New("集成配置 kind 和 provider 不能为空")
	}
	return uc.repo.DeleteIntegrationConfig(ctx, kind, provider)
}

func normalizeIntegrationPart(value string) string {
	return strings.ToLower(strings.TrimSpace(value))
}

func decodeIntegrationObject(raw json.RawMessage) (map[string]any, error) {
	values := map[string]any{}
	if err := json.Unmarshal(raw, &values); err != nil || values == nil {
		return nil, errors.New("集成配置必须是 JSON 对象")
	}
	return values, nil
}

func IntegrationDefinitions(kind string) []IntegrationConfigDefinition {
	kind = normalizeIntegrationPart(kind)
	definitions := integrationDefinitions[kind]
	out := append([]IntegrationConfigDefinition(nil), definitions...)
	sort.Slice(out, func(i, j int) bool { return out[i].Provider < out[j].Provider })
	return out
}

func IntegrationDefinition(kind, provider string) (IntegrationConfigDefinition, bool) {
	for _, definition := range integrationDefinitions[normalizeIntegrationPart(kind)] {
		if definition.Provider == normalizeIntegrationPart(provider) {
			return definition, true
		}
	}
	return IntegrationConfigDefinition{}, false
}

func DefaultIntegrationConfig(kind, provider string) map[string]any {
	definition, ok := IntegrationDefinition(kind, provider)
	if !ok {
		return map[string]any{}
	}
	return mergeIntegrationDefaults(definition.Defaults, nil)
}

func mergeIntegrationDefaults(defaults, values map[string]any) map[string]any {
	out := make(map[string]any, len(defaults)+len(values))
	for key, value := range defaults {
		out[key] = value
	}
	for key, value := range values {
		out[key] = value
	}
	return out
}

func ValidateIntegrationConfig(kind, provider string, values map[string]any) error {
	kind = normalizeIntegrationPart(kind)
	provider = normalizeIntegrationPart(provider)
	switch kind {
	case IntegrationKindPayment:
		return validatePaymentIntegrationConfig(provider, values)
	case IntegrationKindMQ, IntegrationKindWebSocket:
		return validateCommunicationIntegrationConfig(kind, provider, values)
	default:
		return nil
	}
}

func validateCommunicationIntegrationConfig(kind, provider string, values map[string]any) error {
	definition, ok := IntegrationDefinition(kind, provider)
	if !ok {
		return errors.New("不支持的通信集成")
	}
	for _, field := range definition.Fields {
		if field.Required && integrationText(values, field.Key) == "" {
			return fmt.Errorf("%s 缺少配置字段 %s", provider, field.Key)
		}
	}

	switch kind + "/" + provider {
	case IntegrationKindMQ + "/emqx":
		broker := strings.ToLower(integrationText(values, "broker"))
		if !strings.HasPrefix(broker, "tcp://") && !strings.HasPrefix(broker, "ssl://") && !strings.HasPrefix(broker, "ws://") && !strings.HasPrefix(broker, "wss://") && !strings.HasPrefix(broker, "mqtt://") {
			return errors.New("emqx broker 必须使用 tcp、ssl、ws、wss 或 mqtt 协议")
		}
		if keepAlive := integrationInt64(values, "keep_alive", 0); keepAlive <= 0 {
			return errors.New("emqx keep_alive 必须大于 0")
		}
		if timeout := integrationInt64(values, "connect_timeout", 0); timeout <= 0 {
			return errors.New("emqx connect_timeout 必须大于 0")
		}
		if interval := integrationInt64(values, "reconnect_interval", 0); interval <= 0 {
			return errors.New("emqx reconnect_interval 必须大于 0")
		}
	case IntegrationKindMQ + "/rabbitmq":
		port := integrationInt64(values, "port", 0)
		if port < 1 || port > 65535 {
			return errors.New("rabbitmq port 必须在 1-65535 之间")
		}
		exchangeType := strings.ToLower(integrationText(values, "exchange_type"))
		if exchangeType != "direct" && exchangeType != "fanout" && exchangeType != "topic" {
			return errors.New("rabbitmq exchange_type 必须是 direct、fanout 或 topic")
		}
		if integrationInt64(values, "prefetch_count", -1) < 0 {
			return errors.New("rabbitmq prefetch_count 不能小于 0")
		}
		if integrationInt64(values, "heartbeat", -1) < 0 {
			return errors.New("rabbitmq heartbeat 不能小于 0")
		}
		if integrationInt64(values, "connect_timeout", 0) <= 0 {
			return errors.New("rabbitmq connect_timeout 必须大于 0")
		}
		if integrationInt64(values, "reconnect_interval", 0) <= 0 {
			return errors.New("rabbitmq reconnect_interval 必须大于 0")
		}
	case IntegrationKindWebSocket + "/melody":
		path := integrationText(values, "path")
		if !strings.HasPrefix(path, "/") {
			return errors.New("websocket path 必须以 / 开头")
		}
		for _, key := range []string{"write_wait", "pong_wait", "ping_period"} {
			value := integrationText(values, key)
			if value == "" {
				continue
			}
			duration, err := time.ParseDuration(value)
			if err != nil || duration <= 0 {
				return fmt.Errorf("websocket %s 必须是大于 0 的时长", key)
			}
		}
		if integrationInt64(values, "max_message_size", -1) < 0 || integrationInt64(values, "message_buffer_size", -1) < 0 {
			return errors.New("websocket 消息大小和缓冲区不能小于 0")
		}
	}
	return nil
}

func validatePaymentIntegrationConfig(provider string, values map[string]any) error {
	definition, ok := IntegrationDefinition(IntegrationKindPayment, provider)
	if !ok {
		return errors.New("不支持的支付渠道")
	}
	for _, field := range definition.Fields {
		if field.Required && integrationText(values, field.Key) == "" {
			return fmt.Errorf("%s 缺少配置字段 %s", provider, field.Key)
		}
	}
	switch provider {
	case paymentutil.ProviderAlipayV3:
		for _, group := range []struct {
			label string
			keys  []string
		}{
			{"private_key", []string{"private_key", "private_key_content", "private_key_path"}},
			{"app_cert", []string{"app_cert", "app_cert_content", "app_cert_path", "app_public_cert", "app_public_cert_content", "app_public_cert_path"}},
			{"root_cert", []string{"root_cert", "root_cert_content", "root_cert_path", "alipay_root_cert", "alipay_root_cert_content", "alipay_root_cert_path"}},
			{"public_cert", []string{"public_cert", "public_cert_content", "public_cert_path", "alipay_public_cert", "alipay_public_cert_content", "alipay_public_cert_path"}},
		} {
			if integrationFirst(values, group.keys...) == "" {
				return fmt.Errorf("%s 缺少配置字段 %s", provider, group.label)
			}
		}
	case paymentutil.ProviderWechatV2:
		if integrationFirst(values, "client_cert", "cert_pem", "apiclient_cert") == "" || integrationFirst(values, "client_key", "key_pem", "apiclient_key") == "" {
			return fmt.Errorf("%s 退款要求同时配置 client_cert 和 client_key", provider)
		}
	case paymentutil.ProviderApple:
		if integrationInt64(values, "price_divisor", 0) <= 0 {
			if _, exists := values["price_divisors"].(map[string]any); !exists {
				return fmt.Errorf("%s 缺少配置字段 price_divisor 或 price_divisors", provider)
			}
		}
	case paymentutil.ProviderDouyin:
		if integrationFirst(values, "platform_serial_no", "platform_cert_serial") == "" {
			return fmt.Errorf("%s 缺少配置字段 platform_serial_no", provider)
		}
	case paymentutil.ProviderQQ:
		if integrationFirst(values, "mch_id", "merchant_id") == "" {
			return fmt.Errorf("%s 缺少配置字段 mch_id", provider)
		}
		if !hasQQIntegrationCertificate(values) {
			return fmt.Errorf("%s 退款要求配置 cert_file + key_file、pkcs12_file 或对应的 *_content", provider)
		}
		signType := strings.ToUpper(integrationText(values, "sign_type"))
		if signType != "" && signType != "MD5" && signType != "HMAC-SHA256" {
			return fmt.Errorf("%s sign_type 必须是 MD5 或 HMAC-SHA256", provider)
		}
	case paymentutil.ProviderAllinPay:
		orderType := strings.ToLower(integrationFirst(values, "query_order_type", "order_type"))
		if orderType != "" && orderType != "reqsn" && orderType != "trxid" {
			return fmt.Errorf("%s query_order_type 必须是 reqsn 或 trxid", provider)
		}
	case paymentutil.ProviderChinaums, paymentutil.ProviderSFT, paymentutil.ProviderSuperPay, paymentutil.ProviderWechatGame, paymentutil.ProviderDouyinGame:
		if integrationFirst(values, "app_key", "merchant_key", "signing_secret", "token") == "" {
			return fmt.Errorf("%s 缺少签名密钥", provider)
		}
		if !validIntegrationScale(integrationInt64(values, "query_amount_scale", 0)) {
			return fmt.Errorf("%s query_amount_scale 必须是正的 10 的幂", provider)
		}
	}
	if environment := strings.ToLower(integrationText(values, "environment")); environment != "" {
		allowedSandbox := provider != paymentutil.ProviderQQ && provider != paymentutil.ProviderDouyin && provider != paymentutil.ProviderLakala
		if environment != "production" && environment != "prod" && (!allowedSandbox || environment != "sandbox") {
			return fmt.Errorf("%s environment 配置无效", provider)
		}
	}
	return validateIntegrationCallbackAck(values)
}

func integrationText(values map[string]any, key string) string {
	value, exists := values[key]
	if !exists || value == nil {
		return ""
	}
	return strings.TrimSpace(fmt.Sprint(value))
}

func integrationFirst(values map[string]any, keys ...string) string {
	for _, key := range keys {
		if value := integrationText(values, key); value != "" {
			return value
		}
	}
	return ""
}

func integrationInt64(values map[string]any, key string, fallback int64) int64 {
	value := integrationText(values, key)
	if value == "" {
		return fallback
	}
	parsed, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		return fallback
	}
	return parsed
}

func hasQQIntegrationCertificate(values map[string]any) bool {
	if integrationFirst(values, "pkcs12_file", "p12_file", "pkcs12_content") != "" {
		return true
	}
	if integrationFirst(values, "cert_file", "cert_path") != "" && integrationFirst(values, "key_file", "key_path") != "" {
		return true
	}
	return integrationFirst(values, "cert_content") != "" && integrationFirst(values, "key_content") != ""
}

func validIntegrationScale(scale int64) bool {
	if scale <= 0 {
		return false
	}
	for scale%10 == 0 {
		scale /= 10
	}
	return scale == 1
}

func validateIntegrationCallbackAck(values map[string]any) error {
	for _, prefix := range []string{"callback_success_", "callback_failure_"} {
		if value := integrationText(values, prefix+"status"); value != "" {
			status, err := strconv.Atoi(value)
			if err != nil || status < 200 || status > 599 {
				return fmt.Errorf("%sstatus 必须是 200-599", prefix)
			}
		}
		if contentType := integrationText(values, prefix+"content_type"); strings.ContainsAny(contentType, "\r\n") || len(contentType) > 200 {
			return fmt.Errorf("%scontent_type 非法", prefix)
		}
	}
	return nil
}
