package paymentkit

import (
	"encoding/json"
	"fmt"
	"net/url"
	"strings"
)

func NormalizeStatus(value, fallback string) string {
	switch strings.ToUpper(strings.TrimSpace(value)) {
	case "SUCCESS", "OK", "PAID", "FULFILLED", "TRADE_SUCCESS", "TRADE_FINISHED", "COMPLETED", "PAY_SUCCESS", "REFUND_SUCCESS", "REFUNDED":
		return "success"
	case "WAIT_BUYER_PAY", "USERPAYING", "NOTPAY", "PROCESSING", "PENDING", "CREATED", "CLIENT_PENDING", "ACCEPT", "ACCEPTED", "PAYING":
		return "pending"
	case "CLOSED", "TRADE_CLOSED", "CANCELLED", "CANCELED", "REVOKED", "FAILED", "FAIL", "REJECTED", "DENIED", "DECLINED", "ERROR", "PAYERROR":
		return "failed"
	default:
		return fallback
	}
}

func NormalizeRefundStatus(value, fallback string) string {
	switch strings.ToUpper(strings.TrimSpace(value)) {
	case "SUCCESS", "OK", "PAID", "REFUND_SUCCESS", "REFUNDED", "COMPLETED", "FINISHED", "TRADE_SUCCESS":
		return "success"
	case "WAIT_BUYER_PAY", "USERPAYING", "NOTPAY", "PROCESSING", "PENDING", "CREATED", "ACCEPT", "ACCEPTED", "PAYING":
		return "pending"
	case "CLOSED", "TRADE_CLOSED", "CANCELLED", "CANCELED", "REVOKED", "REFUND", "FAILED", "FAIL", "REJECTED", "DENIED", "DECLINED", "ERROR", "PAYERROR":
		return "failed"
	default:
		return fallback
	}
}

// NormalizePaymentMethod canonicalizes provider method identifiers while
// leaving provider-specific classification to the integration adapter.
func NormalizePaymentMethod(value string) string {
	return strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(value)))
}

func ConfiguredInt64(values map[string]any, key string, fallback int64) int64 {
	value, ok := values[key]
	if !ok {
		return fallback
	}
	parsed, err := ParseIntegerAmount(strings.TrimSpace(toString(value)))
	if err != nil || parsed <= 0 {
		return fallback
	}
	return parsed
}

func ConfiguredValues(values map[string]any, key string) []string {
	result := []string{}
	for _, item := range strings.Split(toString(values[key]), ",") {
		item = strings.ToUpper(strings.TrimSpace(item))
		if item != "" {
			result = append(result, item)
		}
	}
	return result
}

func ContainsFold(values []string, value string) bool {
	value = strings.ToUpper(strings.TrimSpace(value))
	for _, item := range values {
		if item == value {
			return true
		}
	}
	return false
}

func Text(values map[string]any, key string) string {
	value, _ := values[key].(string)
	return value
}

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

func FirstString(values map[string]string, keys ...string) string {
	for _, key := range keys {
		if values[key] != "" {
			return values[key]
		}
	}
	return ""
}

// CallbackFields merges query parameters, form data, and top-level JSON
// strings using the same precedence for every payment boundary.
func CallbackFields(query, headers map[string]string, body []byte) map[string]string {
	fields := make(map[string]string, len(query))
	for key, value := range query {
		fields[key] = value
	}
	contentType := ""
	for key, value := range headers {
		if strings.EqualFold(key, "Content-Type") {
			contentType = strings.ToLower(value)
			break
		}
	}
	if strings.Contains(contentType, "application/x-www-form-urlencoded") {
		if values, err := url.ParseQuery(string(body)); err == nil {
			for key, value := range values {
				if len(value) > 0 {
					fields[key] = value[0]
				}
			}
		}
	}
	var object map[string]any
	if json.Unmarshal(body, &object) == nil {
		for key, value := range object {
			if text, ok := value.(string); ok {
				fields[key] = text
			}
		}
	}
	return fields
}

func toString(value any) string {
	if value == nil {
		return ""
	}
	return strings.TrimSpace(strings.ReplaceAll(strings.TrimSpace(stringify(value)), "<nil>", ""))
}

func stringify(value any) string {
	return fmt.Sprint(value)
}
