package iap

import (
	"context"
	"encoding/json"
	"strings"
	"time"

	"github.com/hibiken/asynq"
	"github.com/perfect-panel/server/internal/model/order"
	"github.com/perfect-panel/server/internal/model/payment"
	"github.com/perfect-panel/server/internal/svc"
	iapapple "github.com/perfect-panel/server/pkg/iap/apple"
	"github.com/perfect-panel/server/pkg/logger"
	pkgpayment "github.com/perfect-panel/server/pkg/payment"
	queueTypes "github.com/perfect-panel/server/queue/types"
)

// ReconcileLogic 第二层：每 5 分钟扫描 trade_no 非空的待支付 IAP 订单
type ReconcileLogic struct {
	svc *svc.ServiceContext
}

func NewReconcileLogic(svc *svc.ServiceContext) *ReconcileLogic {
	return &ReconcileLogic{svc: svc}
}

func (l *ReconcileLogic) ProcessTask(ctx context.Context, _ *asynq.Task) error {
	logger.Infof("[IAPReconcile] start at %s", time.Now().Format("2006-01-02 15:04:05"))
	return l.reconcile(ctx, 5*time.Minute, 48*time.Hour, false)
}

// reconcile 核心对账逻辑，被第二层和第三层共享
func (l *ReconcileLogic) reconcile(ctx context.Context, minAge, maxAge time.Duration, requireTradeNo bool) error {
	apiCfg, err := l.loadAppleAPIConfig(ctx)
	if err != nil {
		logger.Errorf("[IAPReconcile] load apple config error: %v", err)
		return nil
	}
	if apiCfg == nil {
		logger.Infof("[IAPReconcile] no enabled apple iap payment found, skip")
		return nil
	}

	orders, err := l.svc.OrderModel.FindPendingIAPOrders(ctx, minAge, maxAge, requireTradeNo)
	if err != nil {
		logger.Errorf("[IAPReconcile] find pending orders error: %v", err)
		return nil
	}
	if len(orders) == 0 {
		return nil
	}
	logger.Infof("[IAPReconcile] found %d pending IAP orders (requireTradeNo=%v)", len(orders), requireTradeNo)

	for _, ord := range orders {
		if ord.TradeNo != "" {
			// 有 trade_no：直接用 transactionId 查询 Apple Server API
			l.reconcileByTradeNo(ctx, apiCfg, ord)
		} else if ord.AppAccountToken != "" {
			// trade_no 为空但有 app_account_token：兜底查询
			l.reconcileByAppAccountToken(ctx, apiCfg, ord)
		}
		time.Sleep(100 * time.Millisecond) // 避免 Apple API 限频
	}
	return nil
}

// reconcileByTradeNo 通过 trade_no (originalTransactionId) 直接查询 Apple 交易状态
func (l *ReconcileLogic) reconcileByTradeNo(ctx context.Context, apiCfg *iapapple.ServerAPIConfig, ord *order.Order) {
	jws, e := iapapple.GetTransactionInfo(*apiCfg, ord.TradeNo)
	if e != nil {
		logger.Errorf("[IAPReconcile] GetTransactionInfo error: orderNo=%s tradeNo=%s err=%v",
			ord.OrderNo, ord.TradeNo, e)
		return
	}
	txPayload, e := iapapple.ParseTransactionJWS(jws)
	if e != nil {
		logger.Errorf("[IAPReconcile] ParseTransactionJWS error: orderNo=%s err=%v", ord.OrderNo, e)
		return
	}
	if txPayload.RevocationDate != nil {
		logger.Infof("[IAPReconcile] transaction revoked, closing order: %s", ord.OrderNo)
		if closeErr := l.svc.OrderModel.UpdateOrderStatus(ctx, ord.OrderNo, 3); closeErr != nil {
			logger.Errorf("[IAPReconcile] close revoked order failed: orderNo=%s err=%v", ord.OrderNo, closeErr)
		}
		return
	}
	// 正常已付款交易 → 先将状态改为已支付，再 enqueue 激活
	if statusErr := l.svc.OrderModel.UpdateOrderStatus(ctx, ord.OrderNo, 2); statusErr != nil {
		logger.Errorf("[IAPReconcile] update order status to paid error: orderNo=%s err=%v", ord.OrderNo, statusErr)
		return
	}
	payload, _ := json.Marshal(queueTypes.ForthwithActivateOrderPayload{OrderNo: ord.OrderNo})
	task := asynq.NewTask(queueTypes.ForthwithActivateOrder, payload)
	if _, e = l.svc.Queue.EnqueueContext(ctx, task); e != nil {
		logger.Errorf("[IAPReconcile] enqueue activate error: orderNo=%s err=%v", ord.OrderNo, e)
	} else {
		logger.Infof("[IAPReconcile] enqueued activate: %s", ord.OrderNo)
	}
}

// reconcileByAppAccountToken 兜底：trade_no 为空但有 app_account_token
// 通过用户历史交易 ID 查询 Apple 交易历史，匹配 appAccountToken 找到对应交易
func (l *ReconcileLogic) reconcileByAppAccountToken(ctx context.Context, apiCfg *iapapple.ServerAPIConfig, ord *order.Order) {
	// 1. 获取该用户最近的已知交易 ID
	lastTx, err := l.svc.IAPAppleTransactionModel.FindLatestByUserId(ctx, ord.UserId)
	if err != nil || lastTx == nil || lastTx.OriginalTransactionId == "" {
		logger.Infof("[IAPReconcile-Fallback] no historical transaction found for user %d, orderNo=%s, skip",
			ord.UserId, ord.OrderNo)
		return
	}

	logger.Infof("[IAPReconcile-Fallback] searching Apple history for orderNo=%s appAccountToken=%s using transactionId=%s",
		ord.OrderNo, ord.AppAccountToken, lastTx.OriginalTransactionId)

	// 2. 查询 Apple 交易历史
	jwsList, err := iapapple.GetTransactionHistory(*apiCfg, lastTx.OriginalTransactionId)
	if err != nil {
		logger.Errorf("[IAPReconcile-Fallback] GetTransactionHistory error: orderNo=%s err=%v", ord.OrderNo, err)
		return
	}

	// 3. 在交易历史中查找匹配 appAccountToken 的交易
	for _, jws := range jwsList {
		txPayload, e := iapapple.ParseTransactionJWS(jws)
		if e != nil {
			continue
		}
		if txPayload.AppAccountToken != ord.AppAccountToken {
			continue
		}
		// 匹配成功!
		logger.Infof("[IAPReconcile-Fallback] MATCHED! orderNo=%s appAccountToken=%s transactionId=%s",
			ord.OrderNo, ord.AppAccountToken, txPayload.TransactionId)

		if txPayload.RevocationDate != nil {
			logger.Infof("[IAPReconcile-Fallback] transaction revoked, closing order: %s", ord.OrderNo)
			if closeErr := l.svc.OrderModel.UpdateOrderStatus(ctx, ord.OrderNo, 3); closeErr != nil {
				logger.Errorf("[IAPReconcile-Fallback] close revoked order failed: orderNo=%s err=%v", ord.OrderNo, closeErr)
			}
			return
		}

		// 更新 trade_no 为找到的 originalTransactionId
		if updateErr := l.svc.DB.Model(&order.Order{}).
			Where("order_no = ?", ord.OrderNo).
			Update("trade_no", txPayload.OriginalTransactionId).Error; updateErr != nil {
			logger.Errorf("[IAPReconcile-Fallback] update trade_no error: orderNo=%s err=%v", ord.OrderNo, updateErr)
		}

		// 先将订单状态改为已支付（status=2），activateOrderLogic 要求 status=2 才会处理
		if statusErr := l.svc.OrderModel.UpdateOrderStatus(ctx, ord.OrderNo, 2); statusErr != nil {
			logger.Errorf("[IAPReconcile-Fallback] update order status to paid error: orderNo=%s err=%v", ord.OrderNo, statusErr)
			return
		}
		logger.Infof("[IAPReconcile-Fallback] order status updated to paid: %s", ord.OrderNo)

		// enqueue 激活
		payload, _ := json.Marshal(queueTypes.ForthwithActivateOrderPayload{OrderNo: ord.OrderNo})
		task := asynq.NewTask(queueTypes.ForthwithActivateOrder, payload)
		if _, e := l.svc.Queue.EnqueueContext(ctx, task); e != nil {
			logger.Errorf("[IAPReconcile-Fallback] enqueue activate error: orderNo=%s err=%v", ord.OrderNo, e)
		} else {
			logger.Infof("[IAPReconcile-Fallback] enqueued activate: %s", ord.OrderNo)
		}
		return
	}

	logger.Infof("[IAPReconcile-Fallback] no matching transaction found for orderNo=%s appAccountToken=%s (checked %d transactions)",
		ord.OrderNo, ord.AppAccountToken, len(jwsList))
}

// loadAppleAPIConfig 从 payment 表读取第一个启用的 Apple IAP 支付方式配置
func (l *ReconcileLogic) loadAppleAPIConfig(ctx context.Context) (*iapapple.ServerAPIConfig, error) {
	pays, err := l.svc.PaymentModel.FindListByPlatform(ctx, pkgpayment.AppleIAP.String())
	if err != nil {
		return nil, err
	}
	for _, pay := range pays {
		if pay.Enable == nil || !*pay.Enable || pay.Config == "" {
			continue
		}
		var cfg payment.AppleIAPConfig
		if e := cfg.Unmarshal([]byte(pay.Config)); e != nil {
			continue
		}
		if cfg.KeyID == "" || cfg.IssuerID == "" || cfg.PrivateKey == "" {
			continue
		}
		apiCfg := &iapapple.ServerAPIConfig{
			KeyID:      cfg.KeyID,
			IssuerID:   cfg.IssuerID,
			PrivateKey: fixPEM(cfg.PrivateKey),
			Sandbox:    cfg.Sandbox,
		}
		// 从 site custom data 读取 BundleID
		var customData struct {
			IapBundleId string `json:"iapBundleId"`
		}
		if l.svc.Config.Site.CustomData != "" {
			_ = json.Unmarshal([]byte(l.svc.Config.Site.CustomData), &customData)
			apiCfg.BundleID = customData.IapBundleId
		}
		return apiCfg, nil
	}
	return nil, nil
}

func fixPEM(key string) string {
	if !strings.Contains(key, "\n") && strings.Contains(key, "BEGIN PRIVATE KEY") {
		key = strings.ReplaceAll(key, " ", "\n")
		key = strings.ReplaceAll(key, "-----BEGIN\nPRIVATE\nKEY-----", "-----BEGIN PRIVATE KEY-----")
		key = strings.ReplaceAll(key, "-----END\nPRIVATE\nKEY-----", "-----END PRIVATE KEY-----")
	}
	return key
}
