package admin_agent

import (
	"context"
	"database/sql"
	"time"
	"tydata-server/app/main/model"
	"tydata-server/common/xerr"

	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/stores/sqlx"

	"tydata-server/app/main/api/internal/svc"
	"tydata-server/app/main/api/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

// 审核操作常量
const (
	ReviewActionApprove = 1 // 确认
	ReviewActionReject  = 2 // 拒绝
)

// 状态常量
const (
	StatusPending = 1 // 申请中/处理中
	StatusSuccess = 2 // 成功
	StatusFailed  = 3 // 失败
)

// 提现类型常量
const (
	WithdrawTypeAlipay   = 1 // 支付宝提现
	WithdrawTypeBankCard = 2 // 银行卡提现
)

type AdminReviewBankCardWithdrawalLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewAdminReviewBankCardWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminReviewBankCardWithdrawalLogic {
	return &AdminReviewBankCardWithdrawalLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *AdminReviewBankCardWithdrawalLogic) AdminReviewBankCardWithdrawal(req *types.AdminReviewBankCardWithdrawalReq) (resp *types.AdminReviewBankCardWithdrawalResp, err error) {
	// 验证操作类型
	if req.Action != ReviewActionApprove && req.Action != ReviewActionReject {
		return nil, errors.Wrapf(xerr.NewErrMsg("操作类型不正确"), "操作类型验证失败")
	}

	// 拒绝操作必须填写备注
	if req.Action == ReviewActionReject && req.Remark == "" {
		return nil, errors.Wrapf(xerr.NewErrMsg("拒绝提现必须填写拒绝原因"), "拒绝原因验证失败")
	}

	resp = &types.AdminReviewBankCardWithdrawalResp{
		Success: false,
	}

	// 使用事务处理审核操作
	err = l.svcCtx.AgentModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
		// 获取提现记录
		record, err := l.svcCtx.AgentWithdrawalModel.FindOne(ctx, req.WithdrawalId)
		if err != nil {
			if errors.Is(err, model.ErrNotFound) {
				return errors.Wrapf(xerr.NewErrMsg("提现记录不存在"), "提现记录不存在")
			}
			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询提现记录失败: %v", err)
		}

		// 验证提现记录状态必须是申请中
		if record.Status != StatusPending {
			return errors.Wrapf(xerr.NewErrMsg("该提现记录已处理，无法重复操作"), "状态验证失败")
		}

		// 验证提现类型（支持银行卡和支付宝提现）
		if record.WithdrawType != WithdrawTypeBankCard && record.WithdrawType != WithdrawTypeAlipay {
			return errors.Wrapf(xerr.NewErrMsg("提现类型不正确"), "提现类型验证失败")
		}

		if req.Action == ReviewActionApprove {
			// 确认提现
			return l.approveWithdrawal(ctx, session, record)
		} else {
			// 拒绝提现
			return l.rejectWithdrawal(ctx, session, record, req.Remark)
		}
	})

	if err != nil {
		return nil, err
	}

	resp.Success = true
	return resp, nil
}

// 确认提现
func (l *AdminReviewBankCardWithdrawalLogic) approveWithdrawal(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal) error {
	// 根据提现类型执行不同的操作
	if record.WithdrawType == WithdrawTypeAlipay {
		// 支付宝提现：先调用支付宝转账接口
		return l.approveAlipayWithdrawal(ctx, session, record)
	} else {
		// 银行卡提现：直接更新状态为成功（线下转账）
		return l.approveBankCardWithdrawal(ctx, session, record)
	}
}

// 确认支付宝提现
func (l *AdminReviewBankCardWithdrawalLogic) approveAlipayWithdrawal(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal) error {
	// 同步调用支付宝转账
	transferResp, err := l.svcCtx.AlipayService.AliTransfer(ctx, record.PayeeAccount, record.PayeeName.String, record.ActualAmount, "公司提现", record.WithdrawNo)
	if err != nil {
		l.Logger.Errorf("【支付宝转账失败】withdrawNo:%s error:%v", record.WithdrawNo, err)
		return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "支付宝接口调用失败: %v", err)
	}

	switch {
	case transferResp.Status == "SUCCESS":
		// 立即处理成功状态
		return l.completeWithdrawalSuccess(ctx, session, record)
	case transferResp.Status == "FAIL" || transferResp.SubCode != "":
		// 处理明确失败
		errorMsg := l.mapAlipayError(transferResp.SubCode)
		return l.completeWithdrawalFailure(ctx, session, record, errorMsg)
	case transferResp.Status == "DEALING":
		// 处理中状态，更新为处理中但不标记为最终状态
		record.Remark = sql.NullString{String: "支付宝转账处理中", Valid: true}
		if _, err := l.svcCtx.AgentWithdrawalModel.Update(ctx, session, record); err != nil {
			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提现记录失败: %v", err)
		}
		l.Logger.Infof("支付宝提现审核通过，转账处理中 withdrawalId:%d withdrawNo:%s", record.Id, record.WithdrawNo)
		return nil
	default:
		// 未知状态按失败处理
		return l.completeWithdrawalFailure(ctx, session, record, "支付宝返回未知状态")
	}
}

// 确认银行卡提现
func (l *AdminReviewBankCardWithdrawalLogic) approveBankCardWithdrawal(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal) error {
	// 更新提现记录状态为成功
	record.Status = StatusSuccess
	record.Remark = sql.NullString{String: "管理员确认提现", Valid: true}
	if _, err := l.svcCtx.AgentWithdrawalModel.Update(ctx, session, record); err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提现记录失败: %v", err)
	}

	// 解冻资金并扣除（FrozenBalance -= amount, Balance不变）
	wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(ctx, record.AgentId)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询钱包失败: %v", err)
	}

	// 记录变动前的冻结余额
	frozenBalanceBefore := wallet.FrozenBalance

	// 更新钱包（减少冻结余额）
	wallet.FrozenBalance -= record.Amount
	if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新钱包失败: %v", err)
	}

	// 记录交易流水（提现成功）
	err = l.svcCtx.AgentService.CreateWalletTransaction(
		ctx,
		session,
		wallet.AgentId,
		model.WalletTransactionTypeWithdraw,
		-record.Amount,       // 变动金额（负数表示减少）
		wallet.Balance,       // 变动前余额（不变）
		wallet.Balance,       // 变动后余额（不变）
		frozenBalanceBefore,  // 变动前冻结余额
		wallet.FrozenBalance, // 变动后冻结余额
		record.WithdrawNo,    // 关联交易ID
		0,                    // 关联用户ID
		"提现审核通过",             // 备注
	)
	if err != nil {
		return err
	}

	// 更新扣税记录状态为成功
	taxModel, err := l.svcCtx.AgentWithdrawalTaxModel.FindOneByWithdrawalId(ctx, record.Id)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
	}
	if taxModel.TaxStatus == model.TaxStatusPending {
		taxModel.TaxStatus = model.TaxStatusSuccess // 扣税状态 = 成功
		taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
		if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil {
			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
		}
	}

	// 提现成功后，给上级代理发放提现奖励
	withdrawRewardErr := l.svcCtx.AgentService.GiveWithdrawReward(ctx, record.AgentId, record.Amount, session)
	if withdrawRewardErr != nil {
		l.Logger.Errorf("发放提现奖励失败，代理ID：%d，提现金额：%f，错误：%+v", record.AgentId, record.Amount, withdrawRewardErr)
		// 提现奖励失败不影响主流程，只记录日志
	} else {
		l.Logger.Infof("发放提现奖励成功，代理ID：%d，提现金额：%f", record.AgentId, record.Amount)
	}

	l.Logger.Infof("银行卡提现确认成功 withdrawalId:%d amount:%f", record.Id, record.Amount)
	return nil
}

// 拒绝提现
func (l *AdminReviewBankCardWithdrawalLogic) rejectWithdrawal(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal, remark string) error {
	// 更新提现记录状态为失败
	record.Status = StatusFailed
	record.Remark = sql.NullString{String: "管理员拒绝：" + remark, Valid: true}
	if _, err := l.svcCtx.AgentWithdrawalModel.Update(ctx, session, record); err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提现记录失败: %v", err)
	}

	// 解冻资金（FrozenBalance -= amount, Balance += amount）
	wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(ctx, record.AgentId)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询钱包失败: %v", err)
	}

	// 记录变动前的余额
	balanceBefore := wallet.Balance
	frozenBalanceBefore := wallet.FrozenBalance

	// 更新钱包（余额增加，冻结余额减少）
	wallet.Balance += record.Amount
	wallet.FrozenBalance -= record.Amount
	if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新钱包失败: %v", err)
	}

	// 记录交易流水（解冻）
	err = l.svcCtx.AgentService.CreateWalletTransaction(
		ctx,
		session,
		wallet.AgentId,
		model.WalletTransactionTypeUnfreeze,
		record.Amount,        // 变动金额（正数表示增加）
		balanceBefore,        // 变动前余额
		wallet.Balance,       // 变动后余额
		frozenBalanceBefore,  // 变动前冻结余额
		wallet.FrozenBalance, // 变动后冻结余额
		record.WithdrawNo,    // 关联交易ID
		0,                    // 关联用户ID
		"提现拒绝，解冻资金",          // 备注
	)
	if err != nil {
		return err
	}

	// 更新扣税记录状态为失败
	taxModel, err := l.svcCtx.AgentWithdrawalTaxModel.FindOneByWithdrawalId(ctx, record.Id)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
	}
	if taxModel.TaxStatus == model.TaxStatusPending {
		taxModel.TaxStatus = model.TaxStatusFailed // 扣税状态 = 失败
		taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
		if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil {
			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
		}
	}

	l.Logger.Infof("银行卡提现拒绝 withdrawalId:%d amount:%f reason:%s", record.Id, record.Amount, remark)
	return nil
}

// 完成提现成功（支付宝转账成功后调用）
func (l *AdminReviewBankCardWithdrawalLogic) completeWithdrawalSuccess(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal) error {
	// 更新提现记录状态为成功
	record.Status = StatusSuccess
	record.Remark = sql.NullString{String: "支付宝转账成功", Valid: true}
	if _, err := l.svcCtx.AgentWithdrawalModel.Update(ctx, session, record); err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提现记录失败: %v", err)
	}

	// 解冻资金并扣除（FrozenBalance -= amount, Balance不变）
	wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(ctx, record.AgentId)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询钱包失败: %v", err)
	}

	// 记录变动前的冻结余额
	frozenBalanceBefore := wallet.FrozenBalance

	// 更新钱包（减少冻结余额）
	wallet.FrozenBalance -= record.Amount
	if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新钱包失败: %v", err)
	}

	// 记录交易流水（提现成功）
	err = l.svcCtx.AgentService.CreateWalletTransaction(
		ctx,
		session,
		wallet.AgentId,
		model.WalletTransactionTypeWithdraw,
		-record.Amount,       // 变动金额（负数表示减少）
		wallet.Balance,       // 变动前余额（不变）
		wallet.Balance,       // 变动后余额（不变）
		frozenBalanceBefore,  // 变动前冻结余额
		wallet.FrozenBalance, // 变动后冻结余额
		record.WithdrawNo,    // 关联交易ID
		0,                    // 关联用户ID
		"提现成功",               // 备注
	)
	if err != nil {
		return err
	}

	// 更新扣税记录状态为成功
	taxModel, err := l.svcCtx.AgentWithdrawalTaxModel.FindOneByWithdrawalId(ctx, record.Id)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
	}
	if taxModel.TaxStatus == model.TaxStatusPending {
		taxModel.TaxStatus = model.TaxStatusSuccess // 扣税状态 = 成功
		taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
		if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil {
			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
		}
	}

	// 提现成功后，给上级代理发放提现奖励
	withdrawRewardErr := l.svcCtx.AgentService.GiveWithdrawReward(ctx, record.AgentId, record.Amount, session)
	if withdrawRewardErr != nil {
		l.Logger.Errorf("发放提现奖励失败，代理ID：%d，提现金额：%f，错误：%+v", record.AgentId, record.Amount, withdrawRewardErr)
		// 提现奖励失败不影响主流程，只记录日志
	} else {
		l.Logger.Infof("发放提现奖励成功，代理ID：%d，提现金额：%f", record.AgentId, record.Amount)
	}

	l.Logger.Infof("支付宝提现成功 withdrawalId:%d withdrawNo:%s", record.Id, record.WithdrawNo)
	return nil
}

// 完成提现失败（支付宝转账失败后调用）
func (l *AdminReviewBankCardWithdrawalLogic) completeWithdrawalFailure(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal, errorMsg string) error {
	// 更新提现记录状态为失败
	record.Status = StatusFailed
	record.Remark = sql.NullString{String: errorMsg, Valid: true}
	if _, err := l.svcCtx.AgentWithdrawalModel.Update(ctx, session, record); err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提现记录失败: %v", err)
	}

	// 解冻资金（FrozenBalance -= amount, Balance += amount）
	wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(ctx, record.AgentId)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询钱包失败: %v", err)
	}

	// 记录变动前的余额
	balanceBefore := wallet.Balance
	frozenBalanceBefore := wallet.FrozenBalance

	// 更新钱包（余额增加，冻结余额减少）
	wallet.Balance += record.Amount
	wallet.FrozenBalance -= record.Amount
	if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新钱包失败: %v", err)
	}

	// 记录交易流水（解冻）
	err = l.svcCtx.AgentService.CreateWalletTransaction(
		ctx,
		session,
		wallet.AgentId,
		model.WalletTransactionTypeUnfreeze,
		record.Amount,        // 变动金额（正数表示增加）
		balanceBefore,        // 变动前余额
		wallet.Balance,       // 变动后余额
		frozenBalanceBefore,  // 变动前冻结余额
		wallet.FrozenBalance, // 变动后冻结余额
		record.WithdrawNo,    // 关联交易ID
		0,                    // 关联用户ID
		"提现失败，解冻资金",          // 备注
	)
	if err != nil {
		return err
	}

	// 更新扣税记录状态为失败
	taxModel, err := l.svcCtx.AgentWithdrawalTaxModel.FindOneByWithdrawalId(ctx, record.Id)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
	}
	if taxModel.TaxStatus == model.TaxStatusPending {
		taxModel.TaxStatus = model.TaxStatusFailed // 扣税状态 = 失败
		taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
		if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil {
			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
		}
	}

	l.Logger.Infof("支付宝提现失败 withdrawalId:%d withdrawNo:%s reason:%s", record.Id, record.WithdrawNo, errorMsg)
	return nil
}

// 错误类型映射
func (l *AdminReviewBankCardWithdrawalLogic) mapAlipayError(code string) string {
	errorMapping := map[string]string{
		// 账户存在性错误
		"PAYEE_ACCOUNT_NOT_EXSIT": "收款账户不存在，请检查账号是否正确",
		"PAYEE_NOT_EXIST":         "收款账户不存在或姓名有误，请核实信息",
		"PAYEE_ACC_OCUPIED":       "收款账号存在多个账户，无法确认唯一性",
		"PAYEE_MID_CANNOT_SAME":   "收款方和中间方不能是同一个人，请修改收款方或者中间方信息",

		// 实名认证问题
		"PAYEE_CERTIFY_LEVEL_LIMIT": "收款方未完成实名认证",
		"PAYEE_NOT_RELNAME_CERTIFY": "收款方未完成实名认证",
		"PAYEE_CERT_INFO_ERROR":     "收款方证件信息不匹配",

		// 账户状态异常
		"PAYEE_ACCOUNT_STATUS_ERROR":       "收款账户状态异常，请更换账号",
		"PAYEE_USERINFO_STATUS_ERROR":      "收款账户状态异常，无法收款",
		"PERMIT_LIMIT_PAYEE":               "收款账户异常，请更换账号",
		"BLOCK_USER_FORBBIDEN_RECIEVE":     "账户冻结无法收款",
		"PAYEE_TRUSTEESHIP_ACC_OVER_LIMIT": "收款方托管子户累计收款金额超限",

		// 账户信息错误
		"PAYEE_USERINFO_ERROR":     "收款方姓名或信息不匹配",
		"PAYEE_CARD_INFO_ERROR":    "收款支付宝账号及户名不一致",
		"PAYEE_IDENTITY_NOT_MATCH": "收款方身份信息不匹配",
		"PAYEE_USER_IS_INST":       "收款方为金融机构，不能使用提现功能，请更换收款账号",
		"PAYEE_USER_TYPE_ERROR":    "该支付宝账号类型不支持提现，请更换收款账号",

		// 权限与限制
		"PAYEE_RECEIVE_COUNT_EXCEED_LIMIT":  "收款次数超限，请明日再试",
		"PAYEE_OUT_PERMLIMIT_CHECK_FAILURE": "收款方权限校验不通过",
		"PERMIT_NON_BANK_LIMIT_PAYEE":       "收款方未完善身份信息，无法收款",
	}
	if msg, ok := errorMapping[code]; ok {
		return msg
	}
	return "系统错误，请联系客服"
}
