package callback

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	"github.com/gofiber/fiber/v2"
	"github.com/valyala/fasthttp/fasthttpadaptor"
	"go.uber.org/zap"

	"github.com/break/junhong_cmp_fiber/internal/model"
	orderService "github.com/break/junhong_cmp_fiber/internal/service/order"
	rechargeService "github.com/break/junhong_cmp_fiber/internal/service/recharge"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/fuiou"
	"github.com/break/junhong_cmp_fiber/pkg/wechat"
)

// AgentRechargeServiceInterface 代理充值服务接口
type AgentRechargeServiceInterface interface {
	HandlePaymentCallback(ctx context.Context, rechargeNo string, paymentMethod string, paymentTransactionID string) error
}

// WechatConfigServiceInterface 支付配置服务接口
type WechatConfigServiceInterface interface {
	GetActiveConfig(ctx context.Context) (*model.WechatConfig, error)
	GetConfigForCallback(ctx context.Context, orderNo string) (*model.WechatConfig, error)
}

type PaymentHandler struct {
	orderService         *orderService.Service
	rechargeService      *rechargeService.Service
	agentRechargeService AgentRechargeServiceInterface
	wechatPayment        wechat.PaymentServiceInterface
	wechatConfigService  WechatConfigServiceInterface
	logger               *zap.Logger
}

func NewPaymentHandler(
	orderService *orderService.Service,
	rechargeService *rechargeService.Service,
	agentRechargeService AgentRechargeServiceInterface,
	wechatPayment wechat.PaymentServiceInterface,
	wechatConfigService WechatConfigServiceInterface,
	logger *zap.Logger,
) *PaymentHandler {
	return &PaymentHandler{
		orderService:         orderService,
		rechargeService:      rechargeService,
		agentRechargeService: agentRechargeService,
		wechatPayment:        wechatPayment,
		wechatConfigService:  wechatConfigService,
		logger:               logger,
	}
}

// WechatPayCallback 微信支付回调（带签名验证）
// POST /api/callback/wechat-pay
func (h *PaymentHandler) WechatPayCallback(c *fiber.Ctx) error {
	body := c.Body()
	ctx := context.Background()

	// 预解析订单号（不验签），用于按 payment_config_id 加载创建订单时所用的配置
	orderNo, err := wechat.PeekOrderNo(body)
	if err != nil {
		h.logger.Error("微信回调：预解析订单号失败", zap.Error(err))
		return errors.New(errors.CodeWechatCallbackInvalid, "回调数据格式错误")
	}

	cfg, err := h.wechatConfigService.GetConfigForCallback(ctx, orderNo)
	if err != nil || cfg == nil {
		h.logger.Error("微信回调：加载支付配置失败",
			zap.String("order_no", orderNo),
			zap.Error(err),
		)
		return errors.New(errors.CodeWechatCallbackInvalid, "微信支付服务未配置")
	}

	switch cfg.ProviderType {
	case model.ProviderTypeWechatV2:
		paymentSvc := wechat.NewPaymentV2Service(cfg.OaAppID, cfg.WxMchID, cfg.WxAPIV2Key, cfg.WxNotifyURL, h.logger)
		result, err := paymentSvc.VerifyCallback(body)
		if err != nil {
			return errors.Wrap(errors.CodeWechatCallbackInvalid, err, "微信 v2 回调验签失败")
		}
		if result.TradeState != "SUCCESS" {
			return h.wechatV2SuccessResponse(c)
		}
		if err := h.dispatchWechatCallback(ctx, result.OutTradeNo, result.TransactionID); err != nil {
			return errors.Wrap(errors.CodeWechatCallbackInvalid, err, "处理微信支付回调失败")
		}

	case model.ProviderTypeWechat:
		if h.wechatPayment == nil {
			return errors.New(errors.CodeWechatCallbackInvalid, "微信 v3 支付未初始化")
		}
		var httpReq http.Request
		fasthttpadaptor.ConvertRequest(c.Context(), &httpReq, true)
		_, err := h.wechatPayment.HandlePaymentNotify(&httpReq, func(result *wechat.PaymentNotifyResult) error {
			if result.TradeState != "SUCCESS" {
				return nil
			}
			return h.dispatchWechatCallback(ctx, result.OutTradeNo, result.TransactionID)
		})
		if err != nil {
			return errors.Wrap(errors.CodeWechatCallbackInvalid, err, "处理微信支付回调失败")
		}

	default:
		return errors.New(errors.CodeWechatCallbackInvalid, "不支持的支付渠道类型")
	}

	return h.wechatV2SuccessResponse(c)
}

// dispatchWechatCallback 按订单号前缀将支付结果分发到对应业务
func (h *PaymentHandler) dispatchWechatCallback(ctx context.Context, outTradeNo, transactionID string) error {
	switch {
	case strings.HasPrefix(outTradeNo, "ORD"):
		return h.orderService.HandlePaymentCallback(ctx, outTradeNo, model.PaymentMethodWechat)
	case strings.HasPrefix(outTradeNo, constants.AssetRechargeOrderPrefix):
		return h.rechargeService.HandlePaymentCallback(ctx, outTradeNo, model.PaymentMethodWechat, transactionID)
	case strings.HasPrefix(outTradeNo, constants.AgentRechargeOrderPrefix):
		if h.agentRechargeService != nil {
			return h.agentRechargeService.HandlePaymentCallback(ctx, outTradeNo, model.PaymentMethodWechat, transactionID)
		}
		return fmt.Errorf("代理充值服务未配置，无法处理订单: %s", outTradeNo)
	default:
		return fmt.Errorf("未知订单号前缀: %s", outTradeNo)
	}
}

// wechatV2SuccessResponse 返回微信 v2 要求的 XML 格式成功响应
// v2 API 要求 XML 格式的 return_code=SUCCESS，否则微信会持续重试回调
func (h *PaymentHandler) wechatV2SuccessResponse(c *fiber.Ctx) error {
	c.Set("Content-Type", "text/xml; charset=utf-8")
	return c.SendString(`<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>`)
}

type AlipayCallbackRequest struct {
	OrderNo string `json:"out_trade_no" form:"out_trade_no"`
}

// AlipayCallback 支付宝回调
// POST /api/callback/alipay
func (h *PaymentHandler) AlipayCallback(c *fiber.Ctx) error {
	var req AlipayCallbackRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
	}

	if req.OrderNo == "" {
		return errors.New(errors.CodeInvalidParam, "订单号不能为空")
	}

	ctx := c.UserContext()

	// 按订单号前缀分发
	switch {
	case strings.HasPrefix(req.OrderNo, "ORD"):
		if err := h.orderService.HandlePaymentCallback(ctx, req.OrderNo, model.PaymentMethodAlipay); err != nil {
			return err
		}
	case strings.HasPrefix(req.OrderNo, constants.AssetRechargeOrderPrefix):
		if err := h.rechargeService.HandlePaymentCallback(ctx, req.OrderNo, model.PaymentMethodAlipay, ""); err != nil {
			return err
		}
	case strings.HasPrefix(req.OrderNo, constants.AgentRechargeOrderPrefix):
		if h.agentRechargeService != nil {
			if err := h.agentRechargeService.HandlePaymentCallback(ctx, req.OrderNo, model.PaymentMethodAlipay, ""); err != nil {
				return err
			}
		}
	default:
		return errors.New(errors.CodeInvalidParam, "未知订单号前缀")
	}

	return c.SendString("success")
}

// FuiouPayCallback 富友支付回调（带签名验证）
// POST /api/callback/fuiou-pay
func (h *PaymentHandler) FuiouPayCallback(c *fiber.Ctx) error {
	body := c.Body()
	if len(body) == 0 {
		return errors.New(errors.CodeFuiouCallbackInvalid, "回调请求体为空")
	}

	ctx := c.UserContext()
	c.Set("Content-Type", "text/xml; charset=gbk")

	// 预解析订单号（不验签），用于按 payment_config_id 加载创建订单时所用的配置
	preNotify, err := fuiou.ParseNotify(body)
	if err != nil {
		h.logger.Error("富友回调：预解析失败", zap.Error(err))
		return c.Send(fuiou.BuildNotifyFailResponse("parse failed"))
	}

	cfg, err := h.wechatConfigService.GetConfigForCallback(ctx, preNotify.MchntOrderNo)
	if err != nil || cfg == nil {
		h.logger.Error("富友回调：加载支付配置失败",
			zap.String("order_no", preNotify.MchntOrderNo),
			zap.Error(err),
		)
		return c.Send(fuiou.BuildNotifyFailResponse("payment config unavailable"))
	}

	client, err := fuiou.NewClient(
		cfg.FyInsCd,
		cfg.FyMchntCd,
		cfg.FyTermID,
		cfg.FyAPIURL,
		cfg.FyNotifyURL,
		cfg.FyPrivateKey,
		cfg.FyPublicKey,
		h.logger,
	)
	if err != nil {
		h.logger.Error("富友回调：构造客户端失败", zap.Error(err))
		return c.Send(fuiou.BuildNotifyFailResponse("client init failed"))
	}

	notify, err := client.VerifyNotify(body)
	if err != nil {
		if notify != nil {
			h.logger.Warn("富友回调：非成功结果",
				zap.String("result_code", notify.ResultCode),
				zap.String("result_msg", notify.ResultMsg))
			return c.Send(fuiou.BuildNotifySuccessResponse())
		}
		h.logger.Error("富友回调：验签或解析失败", zap.Error(err))
		return c.Send(fuiou.BuildNotifyFailResponse(err.Error()))
	}

	orderNo := notify.MchntOrderNo
	switch {
	case strings.HasPrefix(orderNo, "ORD"):
		if err := h.orderService.HandlePaymentCallback(ctx, orderNo, "fuiou"); err != nil {
			return c.Send(fuiou.BuildNotifyFailResponse(err.Error()))
		}
	case strings.HasPrefix(orderNo, constants.AssetRechargeOrderPrefix):
		if err := h.rechargeService.HandlePaymentCallback(ctx, orderNo, "fuiou", notify.TransactionId); err != nil {
			return c.Send(fuiou.BuildNotifyFailResponse(err.Error()))
		}
	case strings.HasPrefix(orderNo, constants.AgentRechargeOrderPrefix):
		if h.agentRechargeService != nil {
			if err := h.agentRechargeService.HandlePaymentCallback(ctx, orderNo, "fuiou", notify.TransactionId); err != nil {
				return c.Send(fuiou.BuildNotifyFailResponse(err.Error()))
			}
		}
	default:
		return c.Send(fuiou.BuildNotifyFailResponse("unknown order prefix"))
	}

	return c.Send(fuiou.BuildNotifySuccessResponse())
}
