package my_commission

import (
	"context"
	"encoding/json"
	"fmt"
	"math/rand"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"gorm.io/gorm"
)

type Service struct {
	db                               *gorm.DB
	shopStore                        *postgres.ShopStore
	walletStore                      *postgres.WalletStore
	commissionWithdrawalRequestStore *postgres.CommissionWithdrawalRequestStore
	commissionWithdrawalSettingStore *postgres.CommissionWithdrawalSettingStore
	commissionRecordStore            *postgres.CommissionRecordStore
	walletTransactionStore           *postgres.WalletTransactionStore
}

func New(
	db *gorm.DB,
	shopStore *postgres.ShopStore,
	walletStore *postgres.WalletStore,
	commissionWithdrawalRequestStore *postgres.CommissionWithdrawalRequestStore,
	commissionWithdrawalSettingStore *postgres.CommissionWithdrawalSettingStore,
	commissionRecordStore *postgres.CommissionRecordStore,
	walletTransactionStore *postgres.WalletTransactionStore,
) *Service {
	return &Service{
		db:                               db,
		shopStore:                        shopStore,
		walletStore:                      walletStore,
		commissionWithdrawalRequestStore: commissionWithdrawalRequestStore,
		commissionWithdrawalSettingStore: commissionWithdrawalSettingStore,
		commissionRecordStore:            commissionRecordStore,
		walletTransactionStore:           walletTransactionStore,
	}
}

// GetCommissionSummary 获取我的佣金概览
func (s *Service) GetCommissionSummary(ctx context.Context) (*dto.MyCommissionSummaryResp, error) {
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType != constants.UserTypeAgent {
		return nil, errors.New(errors.CodeForbidden, "仅代理商用户可访问")
	}

	shopID := middleware.GetShopIDFromContext(ctx)
	if shopID == 0 {
		return nil, errors.New(errors.CodeForbidden, "无法获取店铺信息")
	}

	shop, err := s.shopStore.GetByID(ctx, shopID)
	if err != nil {
		return nil, errors.New(errors.CodeShopNotFound, "店铺不存在")
	}

	// 使用 GetShopCommissionWallet 获取店铺佣金钱包
	wallet, err := s.walletStore.GetShopCommissionWallet(ctx, shopID)
	if err != nil {
		// 钱包不存在时返回空数据
		return &dto.MyCommissionSummaryResp{
			ShopID:   shopID,
			ShopName: shop.ShopName,
		}, nil
	}

	// 计算累计佣金（当前余额 + 冻结余额 + 已提现金额）
	// 由于 Wallet 模型没有 TotalIncome、TotalWithdrawn 字段，
	// 我们需要从 WalletTransaction 表计算或简化处理
	var totalWithdrawn int64
	s.db.WithContext(ctx).Model(&model.CommissionWithdrawalRequest{}).
		Where("shop_id = ? AND status IN ?", shopID, []int{2, 4}). // 已通过或已到账
		Select("COALESCE(SUM(actual_amount), 0)").Scan(&totalWithdrawn)

	totalCommission := wallet.Balance + wallet.FrozenBalance + totalWithdrawn

	return &dto.MyCommissionSummaryResp{
		ShopID:                shopID,
		ShopName:              shop.ShopName,
		TotalCommission:       totalCommission,
		WithdrawnCommission:   totalWithdrawn,
		UnwithdrawCommission:  wallet.Balance + wallet.FrozenBalance,
		FrozenCommission:      wallet.FrozenBalance,
		WithdrawingCommission: wallet.FrozenBalance, // 提现中的金额等于冻结金额
		AvailableCommission:   wallet.Balance,
	}, nil
}

// CreateWithdrawalRequest 发起提现申请
func (s *Service) CreateWithdrawalRequest(ctx context.Context, req *dto.CreateMyWithdrawalReq) (*dto.CreateMyWithdrawalResp, error) {
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType != constants.UserTypeAgent {
		return nil, errors.New(errors.CodeForbidden, "仅代理商用户可访问")
	}

	shopID := middleware.GetShopIDFromContext(ctx)
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if shopID == 0 || currentUserID == 0 {
		return nil, errors.New(errors.CodeForbidden, "无法获取用户信息")
	}

	// 获取提现配置
	setting, err := s.commissionWithdrawalSettingStore.GetCurrent(ctx)
	if err != nil {
		return nil, errors.New(errors.CodeInvalidParam, "暂未开放提现功能")
	}

	// 验证最低提现金额
	if req.Amount < setting.MinWithdrawalAmount {
		return nil, errors.New(errors.CodeInvalidParam, fmt.Sprintf("提现金额不能低于 %.2f 元", float64(setting.MinWithdrawalAmount)/100))
	}

	// 获取钱包
	wallet, err := s.walletStore.GetShopCommissionWallet(ctx, shopID)
	if err != nil {
		return nil, errors.New(errors.CodeInsufficientBalance, "钱包不存在")
	}

	// 验证余额
	if req.Amount > wallet.Balance {
		return nil, errors.New(errors.CodeInsufficientBalance, "可提现余额不足")
	}

	// 验证今日提现次数
	today := time.Now().Format("2006-01-02")
	todayStart := today + " 00:00:00"
	todayEnd := today + " 23:59:59"
	var todayCount int64
	s.db.WithContext(ctx).Model(&model.CommissionWithdrawalRequest{}).
		Where("shop_id = ? AND created_at >= ? AND created_at <= ?", shopID, todayStart, todayEnd).
		Count(&todayCount)
	if int(todayCount) >= setting.DailyWithdrawalLimit {
		return nil, errors.New(errors.CodeInvalidParam, "今日提现次数已达上限")
	}

	// 计算手续费
	fee := req.Amount * setting.FeeRate / 10000
	actualAmount := req.Amount - fee

	// 生成提现单号
	withdrawalNo := generateWithdrawalNo()

	// 构建账户信息 JSON
	accountInfo := map[string]string{
		"account_name":   req.AccountName,
		"account_number": req.AccountNumber,
	}
	accountInfoJSON, _ := json.Marshal(accountInfo)

	var withdrawalRequest *model.CommissionWithdrawalRequest

	err = s.db.Transaction(func(tx *gorm.DB) error {
		// 冻结余额
		if err := tx.WithContext(ctx).Model(&model.Wallet{}).
			Where("id = ? AND balance >= ?", wallet.ID, req.Amount).
			Updates(map[string]interface{}{
				"balance":        gorm.Expr("balance - ?", req.Amount),
				"frozen_balance": gorm.Expr("frozen_balance + ?", req.Amount),
			}).Error; err != nil {
			return errors.Wrap(errors.CodeInternalError, err, "冻结余额失败")
		}

		// 创建提现申请
		withdrawalRequest = &model.CommissionWithdrawalRequest{
			WithdrawalNo:     withdrawalNo,
			ShopID:           shopID,
			ApplicantID:      currentUserID,
			Amount:           req.Amount,
			FeeRate:          setting.FeeRate,
			Fee:              fee,
			ActualAmount:     actualAmount,
			WithdrawalMethod: req.WithdrawalMethod,
			AccountInfo:      accountInfoJSON,
			Status:           1, // 待审核
		}
		withdrawalRequest.Creator = currentUserID
		withdrawalRequest.Updater = currentUserID

		if err := tx.WithContext(ctx).Create(withdrawalRequest).Error; err != nil {
			return errors.Wrap(errors.CodeInternalError, err, "创建提现申请失败")
		}

		// 创建钱包流水记录
		remark := fmt.Sprintf("提现冻结，单号：%s", withdrawalNo)
		refType := constants.ReferenceTypeWithdrawal
		transaction := &model.WalletTransaction{
			WalletID:        wallet.ID,
			UserID:          currentUserID,
			TransactionType: constants.TransactionTypeWithdrawal,
			Amount:          -req.Amount, // 冻结为负数
			BalanceBefore:   wallet.Balance,
			BalanceAfter:    wallet.Balance - req.Amount,
			Status:          constants.TransactionStatusProcessing, // 处理中
			ReferenceType:   &refType,
			ReferenceID:     &withdrawalRequest.ID,
			Remark:          &remark,
			Creator:         currentUserID,
		}

		if err := tx.WithContext(ctx).Create(transaction).Error; err != nil {
			return errors.Wrap(errors.CodeInternalError, err, "创建钱包流水失败")
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return &dto.CreateMyWithdrawalResp{
		ID:           withdrawalRequest.ID,
		WithdrawalNo: withdrawalRequest.WithdrawalNo,
		Amount:       withdrawalRequest.Amount,
		FeeRate:      withdrawalRequest.FeeRate,
		Fee:          withdrawalRequest.Fee,
		ActualAmount: withdrawalRequest.ActualAmount,
		Status:       withdrawalRequest.Status,
		StatusName:   getWithdrawalStatusName(withdrawalRequest.Status),
		CreatedAt:    withdrawalRequest.CreatedAt.Format("2006-01-02 15:04:05"),
	}, nil
}

// ListMyWithdrawalRequests 查询我的提现记录
func (s *Service) ListMyWithdrawalRequests(ctx context.Context, req *dto.MyWithdrawalListReq) (*dto.WithdrawalRequestPageResult, error) {
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType != constants.UserTypeAgent {
		return nil, errors.New(errors.CodeForbidden, "仅代理商用户可访问")
	}

	shopID := middleware.GetShopIDFromContext(ctx)
	if shopID == 0 {
		return nil, errors.New(errors.CodeForbidden, "无法获取店铺信息")
	}

	page := req.Page
	pageSize := req.PageSize
	if page == 0 {
		page = 1
	}
	if pageSize == 0 {
		pageSize = constants.DefaultPageSize
	}

	query := s.db.WithContext(ctx).Model(&model.CommissionWithdrawalRequest{}).
		Where("shop_id = ?", shopID)

	if req.Status != nil {
		query = query.Where("status = ?", *req.Status)
	}
	if req.StartTime != "" {
		query = query.Where("created_at >= ?", req.StartTime)
	}
	if req.EndTime != "" {
		query = query.Where("created_at <= ?", req.EndTime)
	}

	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "统计提现记录失败")
	}

	var requests []model.CommissionWithdrawalRequest
	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&requests).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询提现记录失败")
	}

	items := make([]dto.WithdrawalRequestItem, 0, len(requests))
	for _, r := range requests {
		// 解析账户信息
		accountName, accountNumber := parseAccountInfo(r.AccountInfo)

		items = append(items, dto.WithdrawalRequestItem{
			ID:               r.ID,
			WithdrawalNo:     r.WithdrawalNo,
			ShopID:           r.ShopID,
			Amount:           r.Amount,
			FeeRate:          r.FeeRate,
			Fee:              r.Fee,
			ActualAmount:     r.ActualAmount,
			WithdrawalMethod: r.WithdrawalMethod,
			AccountName:      accountName,
			AccountNumber:    accountNumber,
			Status:           r.Status,
			StatusName:       getWithdrawalStatusName(r.Status),
			CreatedAt:        r.CreatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	return &dto.WithdrawalRequestPageResult{
		Items: items,
		Total: total,
		Page:  page,
		Size:  pageSize,
	}, nil
}

// ListMyCommissionRecords 查询我的佣金明细
func (s *Service) ListMyCommissionRecords(ctx context.Context, req *dto.MyCommissionRecordListReq) (*dto.MyCommissionRecordPageResult, error) {
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType != constants.UserTypeAgent {
		return nil, errors.New(errors.CodeForbidden, "仅代理商用户可访问")
	}

	shopID := middleware.GetShopIDFromContext(ctx)
	if shopID == 0 {
		return nil, errors.New(errors.CodeForbidden, "无法获取店铺信息")
	}

	page := req.Page
	pageSize := req.PageSize
	if page == 0 {
		page = 1
	}
	if pageSize == 0 {
		pageSize = constants.DefaultPageSize
	}

	query := s.db.WithContext(ctx).Model(&model.CommissionRecord{}).
		Where("shop_id = ?", shopID)

	if req.CommissionSource != nil {
		query = query.Where("commission_source = ?", *req.CommissionSource)
	}

	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "统计佣金记录失败")
	}

	var records []model.CommissionRecord
	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询佣金记录失败")
	}

	items := make([]dto.MyCommissionRecordItem, 0, len(records))
	for _, r := range records {
		items = append(items, dto.MyCommissionRecordItem{
			ID:               r.ID,
			ShopID:           r.ShopID,
			OrderID:          r.OrderID,
			CommissionSource: r.CommissionSource,
			Amount:           r.Amount,
			Status:           r.Status,
			StatusName:       getCommissionStatusName(r.Status),
			CreatedAt:        r.CreatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	return &dto.MyCommissionRecordPageResult{
		Items: items,
		Total: total,
		Page:  page,
		Size:  pageSize,
	}, nil
}

func (s *Service) GetStats(ctx context.Context, req *dto.CommissionStatsRequest) (*dto.CommissionStatsResponse, error) {
	shopID, err := s.getShopIDFromContext(ctx)
	if err != nil {
		return nil, err
	}

	filters := &postgres.CommissionRecordListFilters{
		ShopID:    shopID,
		StartTime: req.StartTime,
		EndTime:   req.EndTime,
	}

	stats, err := s.commissionRecordStore.GetStats(ctx, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取佣金统计失败")
	}

	if stats == nil {
		return &dto.CommissionStatsResponse{}, nil
	}

	var costDiffPercent, oneTimePercent int64
	if stats.TotalAmount > 0 {
		costDiffPercent = stats.CostDiffAmount * 1000 / stats.TotalAmount
		oneTimePercent = stats.OneTimeAmount * 1000 / stats.TotalAmount
	}

	return &dto.CommissionStatsResponse{
		TotalAmount:     stats.TotalAmount,
		CostDiffAmount:  stats.CostDiffAmount,
		OneTimeAmount:   stats.OneTimeAmount,
		CostDiffPercent: costDiffPercent,
		OneTimePercent:  oneTimePercent,
		TotalCount:      stats.TotalCount,
		CostDiffCount:   stats.CostDiffCount,
		OneTimeCount:    stats.OneTimeCount,
	}, nil
}

func (s *Service) GetDailyStats(ctx context.Context, req *dto.DailyCommissionStatsRequest) ([]*dto.DailyCommissionStatsResponse, error) {
	shopID, err := s.getShopIDFromContext(ctx)
	if err != nil {
		return nil, err
	}

	days := 30
	if req.Days != nil && *req.Days > 0 {
		days = *req.Days
	}

	filters := &postgres.CommissionRecordListFilters{
		ShopID:    shopID,
		StartTime: req.StartDate,
		EndTime:   req.EndDate,
	}

	dailyStats, err := s.commissionRecordStore.GetDailyStats(ctx, filters, days)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取每日佣金统计失败")
	}

	result := make([]*dto.DailyCommissionStatsResponse, 0, len(dailyStats))
	for _, stat := range dailyStats {
		result = append(result, &dto.DailyCommissionStatsResponse{
			Date:        stat.Date,
			TotalAmount: stat.TotalAmount,
			TotalCount:  stat.TotalCount,
		})
	}

	return result, nil
}

func (s *Service) getShopIDFromContext(ctx context.Context) (uint, error) {
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType != constants.UserTypeAgent {
		return 0, errors.New(errors.CodeForbidden, "仅代理商用户可访问")
	}

	shopID := middleware.GetShopIDFromContext(ctx)
	if shopID == 0 {
		return 0, errors.New(errors.CodeForbidden, "无法获取店铺信息")
	}

	return shopID, nil
}

// generateWithdrawalNo 生成提现单号
func generateWithdrawalNo() string {
	now := time.Now()
	return fmt.Sprintf("W%s%04d", now.Format("20060102150405"), rand.Intn(10000))
}

// getWithdrawalStatusName 获取提现状态名称
func getWithdrawalStatusName(status int) string {
	switch status {
	case 1:
		return "待审核"
	case 2:
		return "已通过"
	case 3:
		return "已拒绝"
	case 4:
		return "已到账"
	default:
		return "未知"
	}
}

// getCommissionStatusName 获取佣金状态名称
func getCommissionStatusName(status int) string {
	switch status {
	case 1:
		return "已冻结"
	case 2:
		return "解冻中"
	case 3:
		return "已发放"
	case 4:
		return "已失效"
	default:
		return "未知"
	}
}

// parseAccountInfo 解析账户信息 JSON
func parseAccountInfo(data []byte) (accountName, accountNumber string) {
	if len(data) == 0 {
		return "", ""
	}
	var info map[string]string
	if err := json.Unmarshal(data, &info); err != nil {
		return "", ""
	}
	return info["account_name"], info["account_number"]
}
