package agent

import (
	"context"
	"fmt"
	"time"
	"qnc-server/app/main/model"
	"qnc-server/common/ctxdata"
	"qnc-server/common/globalkey"
	"qnc-server/common/xerr"
	"qnc-server/pkg/lzkit/lzUtils"

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

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

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

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

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

func (l *ApplyWithdrawalLogic) ApplyWithdrawal(req *types.ApplyWithdrawalReq) (resp *types.ApplyWithdrawalResp, err error) {
	userID, err := ctxdata.GetUidFromCtx(l.ctx)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
	}

	// 1. 获取代理信息
	agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
	if err != nil {
		if errors.Is(err, model.ErrNotFound) {
			return nil, errors.Wrapf(xerr.NewErrMsg("您不是代理"), "")
		}
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
	}

	// 2. 验证实名认证
	realName, err := l.svcCtx.AgentRealNameModel.FindOneByAgentId(l.ctx, agent.Id)
	if err != nil {
		if errors.Is(err, model.ErrNotFound) {
			return nil, errors.Wrapf(xerr.NewErrMsg("请先完成实名认证"), "")
		}
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询实名认证失败, %v", err)
	}
	// 检查是否已通过三要素核验（verify_time不为空表示已通过）
	if !realName.VerifyTime.Valid {
		return nil, errors.Wrapf(xerr.NewErrMsg("请先完成实名认证"), "")
	}

	// 3. 验证提现金额
	if req.Amount <= 0 {
		return nil, errors.Wrapf(xerr.NewErrMsg("提现金额必须大于0"), "")
	}

	// 4. 获取钱包信息
	wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(l.ctx, agent.Id)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询钱包失败, %v", err)
	}

	// 5. 验证余额
	if wallet.Balance < req.Amount {
		return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("余额不足，当前余额：%.2f", wallet.Balance)), "")
	}

	// 6. 计算税费
	yearMonth := int64(time.Now().Year()*100 + int(time.Now().Month()))
	taxInfo, err := l.calculateTax(l.ctx, agent.Id, req.Amount, yearMonth)
	if err != nil {
		return nil, errors.Wrapf(err, "计算税费失败")
	}

	// 7. 生成提现单号
	withdrawNo := fmt.Sprintf("WD%d%d", time.Now().Unix(), agent.Id)

	// 8. 使用事务处理提现申请
	var withdrawalId string
	err = l.svcCtx.AgentWalletModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
		// 8.1 冻结余额
		wallet.FrozenBalance += req.Amount
		wallet.Balance -= req.Amount
		if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet); err != nil {
			return errors.Wrapf(err, "冻结余额失败")
		}

		// 8.2 创建提现记录
		withdrawal := &model.AgentWithdrawal{
			Id:           uuid.New().String(),
			AgentId:      agent.Id,
			WithdrawNo:   withdrawNo,
			PayeeAccount: req.PayeeAccount,
			PayeeName:    req.PayeeName,
			Amount:       req.Amount,
			ActualAmount: taxInfo.ActualAmount,
			TaxAmount:    taxInfo.TaxAmount,
			Status:       1, // 处理中（待审核）
		}

		_, err := l.svcCtx.AgentWithdrawalModel.Insert(transCtx, session, withdrawal)
		if err != nil {
			return errors.Wrapf(err, "创建提现记录失败")
		}
		withdrawalId = withdrawal.Id

		// 8.3 创建扣税记录
		taxRecord := &model.AgentWithdrawalTax{
			AgentId:          agent.Id,
			WithdrawalId:     withdrawalId,
			YearMonth:        yearMonth,
			WithdrawalAmount: req.Amount,
			TaxableAmount:    taxInfo.TaxableAmount,
			TaxRate:          taxInfo.TaxRate,
			TaxAmount:        taxInfo.TaxAmount,
			ActualAmount:     taxInfo.ActualAmount,
			TaxStatus:        1, // 待扣税
			Remark:           lzUtils.StringToNullString("提现申请"),
		}
		if _, err := l.svcCtx.AgentWithdrawalTaxModel.Insert(transCtx, session, taxRecord); err != nil {
			return errors.Wrapf(err, "创建扣税记录失败")
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return &types.ApplyWithdrawalResp{
		WithdrawalId: withdrawalId,
		WithdrawalNo: withdrawNo,
	}, nil
}

// TaxInfo 税费信息
type TaxInfo struct {
	TaxableAmount float64 // 应税金额
	TaxRate       float64 // 税率
	TaxAmount     float64 // 税费金额
	ActualAmount  float64 // 实际到账金额
}

// calculateTax 计算税费
func (l *ApplyWithdrawalLogic) calculateTax(ctx context.Context, agentId string, amount float64, yearMonth int64) (*TaxInfo, error) {
	// 获取税率配置（默认6%）
	taxRate := 0.06
	config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(ctx, "tax_rate")
	if err == nil {
		if parsedRate, parseErr := l.parseFloat(config.ConfigValue); parseErr == nil {
			taxRate = parsedRate
		}
	}

	// 查询本月已提现金额
	builder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
		Where("agent_id = ? AND year_month = ? AND del_state = ?", agentId, yearMonth, globalkey.DelStateNo)
	taxRecords, err := l.svcCtx.AgentWithdrawalTaxModel.FindAll(ctx, builder, "")
	if err != nil {
		return nil, errors.Wrapf(err, "查询月度提现记录失败")
	}

	// 计算本月累计提现金额
	monthlyTotal := 0.0
	for _, record := range taxRecords {
		monthlyTotal += record.WithdrawalAmount
	}

	// 获取免税额度配置（默认0，即无免税额度）
	exemptionAmount := 0.0
	exemptionConfig, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(ctx, "tax_exemption_amount")
	if err == nil {
		if parsedAmount, parseErr := l.parseFloat(exemptionConfig.ConfigValue); parseErr == nil {
			exemptionAmount = parsedAmount
		}
	}

	// 计算应税金额
	// 如果本月累计 + 本次提现金额 <= 免税额度，则本次提现免税
	// 否则，应税金额 = 本次提现金额 - (免税额度 - 本月累计)（如果免税额度 > 本月累计）
	taxableAmount := amount
	if exemptionAmount > 0 {
		remainingExemption := exemptionAmount - monthlyTotal
		if remainingExemption > 0 {
			if amount <= remainingExemption {
				// 本次提现完全免税
				taxableAmount = 0
			} else {
				// 部分免税
				taxableAmount = amount - remainingExemption
			}
		}
	}

	// 计算税费
	taxAmount := taxableAmount * taxRate
	actualAmount := amount - taxAmount

	return &TaxInfo{
		TaxableAmount: taxableAmount,
		TaxRate:       taxRate,
		TaxAmount:     taxAmount,
		ActualAmount:  actualAmount,
	}, nil
}

// parseFloat 解析浮点数
func (l *ApplyWithdrawalLogic) parseFloat(s string) (float64, error) {
	var result float64
	_, err := fmt.Sscanf(s, "%f", &result)
	return result, err
}
