package shop_commission

import (
	"context"
	"encoding/json"
	"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"
	"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"
)

type Service struct {
	shopStore                    *postgres.ShopStore
	accountStore                 *postgres.AccountStore
	walletStore                  *postgres.WalletStore
	commissionWithdrawalReqStore *postgres.CommissionWithdrawalRequestStore
	commissionRecordStore        *postgres.CommissionRecordStore
}

func New(
	shopStore *postgres.ShopStore,
	accountStore *postgres.AccountStore,
	walletStore *postgres.WalletStore,
	commissionWithdrawalReqStore *postgres.CommissionWithdrawalRequestStore,
	commissionRecordStore *postgres.CommissionRecordStore,
) *Service {
	return &Service{
		shopStore:                    shopStore,
		accountStore:                 accountStore,
		walletStore:                  walletStore,
		commissionWithdrawalReqStore: commissionWithdrawalReqStore,
		commissionRecordStore:        commissionRecordStore,
	}
}

func (s *Service) ListShopCommissionSummary(ctx context.Context, req *dto.ShopCommissionSummaryListReq) (*dto.ShopCommissionSummaryPageResult, error) {
	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "created_at DESC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := make(map[string]interface{})
	if req.ShopName != "" {
		filters["shop_name"] = req.ShopName
	}

	shops, total, err := s.shopStore.List(ctx, opts, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询店铺列表失败")
	}

	if len(shops) == 0 {
		return &dto.ShopCommissionSummaryPageResult{
			Items: []dto.ShopCommissionSummaryItem{},
			Total: 0,
			Page:  opts.Page,
			Size:  opts.PageSize,
		}, nil
	}

	shopIDs := make([]uint, 0, len(shops))
	for _, shop := range shops {
		shopIDs = append(shopIDs, shop.ID)
	}

	walletSummaries, err := s.walletStore.GetShopCommissionSummaryBatch(ctx, shopIDs)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询店铺钱包汇总失败")
	}

	withdrawnAmounts, err := s.commissionWithdrawalReqStore.SumAmountByShopIDsAndStatus(ctx, shopIDs, constants.WithdrawalStatusApproved)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询已提现金额失败")
	}

	withdrawingAmounts, err := s.commissionWithdrawalReqStore.SumAmountByShopIDsAndStatus(ctx, shopIDs, constants.WithdrawalStatusPending)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询提现中金额失败")
	}

	primaryAccounts, err := s.accountStore.GetPrimaryAccountsByShopIDs(ctx, shopIDs)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询主账号失败")
	}

	accountMap := make(map[uint]*model.Account)
	for _, acc := range primaryAccounts {
		if acc.ShopID != nil {
			accountMap[*acc.ShopID] = acc
		}
	}

	items := make([]dto.ShopCommissionSummaryItem, 0, len(shops))
	for _, shop := range shops {
		if req.Username != "" {
			acc := accountMap[shop.ID]
			if acc == nil || !containsSubstring(acc.Username, req.Username) {
				total--
				continue
			}
		}

		item := s.buildCommissionSummaryItem(shop, walletSummaries[shop.ID], withdrawnAmounts[shop.ID], withdrawingAmounts[shop.ID], accountMap[shop.ID])
		items = append(items, item)
	}

	return &dto.ShopCommissionSummaryPageResult{
		Items: items,
		Total: total,
		Page:  opts.Page,
		Size:  opts.PageSize,
	}, nil
}

func (s *Service) buildCommissionSummaryItem(shop *model.Shop, walletSummary *postgres.ShopCommissionSummary, withdrawnAmount, withdrawingAmount int64, account *model.Account) dto.ShopCommissionSummaryItem {
	var balance, frozenBalance int64
	if walletSummary != nil {
		balance = walletSummary.Balance
		frozenBalance = walletSummary.FrozenBalance
	}

	totalCommission := balance + frozenBalance + withdrawnAmount
	unwithdrawCommission := totalCommission - withdrawnAmount
	availableCommission := balance - withdrawingAmount
	if availableCommission < 0 {
		availableCommission = 0
	}

	var username, phone string
	if account != nil {
		username = account.Username
		phone = account.Phone
	}

	return dto.ShopCommissionSummaryItem{
		ShopID:                shop.ID,
		ShopName:              shop.ShopName,
		ShopCode:              shop.ShopCode,
		Username:              username,
		Phone:                 phone,
		TotalCommission:       totalCommission,
		WithdrawnCommission:   withdrawnAmount,
		UnwithdrawCommission:  unwithdrawCommission,
		FrozenCommission:      frozenBalance,
		WithdrawingCommission: withdrawingAmount,
		AvailableCommission:   availableCommission,
		CreatedAt:             shop.CreatedAt.Format("2006-01-02 15:04:05"),
	}
}

func (s *Service) ListShopWithdrawalRequests(ctx context.Context, shopID uint, req *dto.ShopWithdrawalRequestListReq) (*dto.ShopWithdrawalRequestPageResult, error) {
	_, err := s.shopStore.GetByID(ctx, shopID)
	if err != nil {
		return nil, errors.New(errors.CodeShopNotFound, "店铺不存在")
	}

	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "created_at DESC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := &postgres.WithdrawalRequestListFilters{
		ShopID:       shopID,
		WithdrawalNo: req.WithdrawalNo,
	}

	if req.StartTime != "" {
		t, err := time.Parse("2006-01-02 15:04:05", req.StartTime)
		if err == nil {
			filters.StartTime = &t
		}
	}
	if req.EndTime != "" {
		t, err := time.Parse("2006-01-02 15:04:05", req.EndTime)
		if err == nil {
			filters.EndTime = &t
		}
	}

	requests, total, err := s.commissionWithdrawalReqStore.ListByShopID(ctx, opts, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询提现记录失败")
	}

	shop, _ := s.shopStore.GetByID(ctx, shopID)
	shopHierarchy := s.buildShopHierarchyPath(ctx, shop)

	applicantIDs := make([]uint, 0)
	processorIDs := make([]uint, 0)
	for _, r := range requests {
		if r.ApplicantID > 0 {
			applicantIDs = append(applicantIDs, r.ApplicantID)
		}
		if r.ProcessorID > 0 {
			processorIDs = append(processorIDs, r.ProcessorID)
		}
	}

	applicantMap := make(map[uint]string)
	processorMap := make(map[uint]string)

	if len(applicantIDs) > 0 {
		accounts, _ := s.accountStore.GetByIDs(ctx, applicantIDs)
		for _, acc := range accounts {
			applicantMap[acc.ID] = acc.Username
		}
	}
	if len(processorIDs) > 0 {
		accounts, _ := s.accountStore.GetByIDs(ctx, processorIDs)
		for _, acc := range accounts {
			processorMap[acc.ID] = acc.Username
		}
	}

	items := make([]dto.ShopWithdrawalRequestItem, 0, len(requests))
	for _, r := range requests {
		item := s.buildWithdrawalRequestItem(r, shop.ShopName, shopHierarchy, applicantMap, processorMap)
		items = append(items, item)
	}

	return &dto.ShopWithdrawalRequestPageResult{
		Items: items,
		Total: total,
		Page:  opts.Page,
		Size:  opts.PageSize,
	}, nil
}

func (s *Service) buildWithdrawalRequestItem(r *model.CommissionWithdrawalRequest, shopName, shopHierarchy string, applicantMap, processorMap map[uint]string) dto.ShopWithdrawalRequestItem {
	var processorID *uint
	if r.ProcessorID > 0 {
		processorID = &r.ProcessorID
	}

	var accountName, accountNumber, bankName string
	if len(r.AccountInfo) > 0 {
		var info map[string]interface{}
		if err := json.Unmarshal(r.AccountInfo, &info); err == nil {
			if v, ok := info["account_name"].(string); ok {
				accountName = v
			}
			if v, ok := info["account_number"].(string); ok {
				accountNumber = v
			}
			if v, ok := info["bank_name"].(string); ok {
				bankName = v
			}
		}
	}

	var processedAt, paidAt string
	if r.ProcessedAt != nil {
		processedAt = r.ProcessedAt.Format("2006-01-02 15:04:05")
	}
	if r.PaidAt != nil {
		paidAt = r.PaidAt.Format("2006-01-02 15:04:05")
	}

	return dto.ShopWithdrawalRequestItem{
		ID:               r.ID,
		WithdrawalNo:     r.WithdrawalNo,
		Amount:           r.Amount,
		FeeRate:          r.FeeRate,
		Fee:              r.Fee,
		ActualAmount:     r.ActualAmount,
		Status:           r.Status,
		StatusName:       getWithdrawalStatusName(r.Status),
		ShopID:           r.ShopID,
		ShopName:         shopName,
		ShopHierarchy:    shopHierarchy,
		ApplicantID:      r.ApplicantID,
		ApplicantName:    applicantMap[r.ApplicantID],
		ProcessorID:      processorID,
		ProcessorName:    processorMap[r.ProcessorID],
		WithdrawalMethod: r.WithdrawalMethod,
		PaymentType:      r.PaymentType,
		AccountName:      accountName,
		AccountNumber:    accountNumber,
		BankName:         bankName,
		RejectReason:     r.RejectReason,
		Remark:           r.Remark,
		CreatedAt:        r.CreatedAt.Format("2006-01-02 15:04:05"),
		ProcessedAt:      processedAt,
		PaidAt:           paidAt,
	}
}

func (s *Service) buildShopHierarchyPath(ctx context.Context, shop *model.Shop) string {
	if shop == nil {
		return ""
	}

	path := shop.ShopName
	current := shop
	depth := 0

	for current.ParentID != nil && depth < 2 {
		parent, err := s.shopStore.GetByID(ctx, *current.ParentID)
		if err != nil {
			break
		}
		path = parent.ShopName + "_" + path
		current = parent
		depth++
	}

	return path
}

func (s *Service) ListShopCommissionRecords(ctx context.Context, shopID uint, req *dto.ShopCommissionRecordListReq) (*dto.ShopCommissionRecordPageResult, error) {
	_, err := s.shopStore.GetByID(ctx, shopID)
	if err != nil {
		return nil, errors.New(errors.CodeShopNotFound, "店铺不存在")
	}

	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "created_at DESC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := &postgres.CommissionRecordListFilters{
		ShopID:           shopID,
		CommissionSource: req.CommissionSource,
		ICCID:            req.ICCID,
		DeviceNo:         req.DeviceNo,
		OrderNo:          req.OrderNo,
	}

	records, total, err := s.commissionRecordStore.ListByShopID(ctx, opts, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询佣金明细失败")
	}

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

	return &dto.ShopCommissionRecordPageResult{
		Items: items,
		Total: total,
		Page:  opts.Page,
		Size:  opts.PageSize,
	}, nil
}

func getWithdrawalStatusName(status int) string {
	switch status {
	case constants.WithdrawalStatusPending:
		return "待审核"
	case constants.WithdrawalStatusApproved:
		return "已通过"
	case constants.WithdrawalStatusRejected:
		return "已拒绝"
	case constants.WithdrawalStatusPaid:
		return "已到账"
	default:
		return "未知"
	}
}

func getCommissionStatusName(status int) string {
	switch status {
	case constants.CommissionStatusFrozen:
		return "已冻结"
	case constants.CommissionStatusUnfreezing:
		return "解冻中"
	case constants.CommissionStatusReleased:
		return "已发放"
	case constants.CommissionStatusInvalid:
		return "已失效"
	default:
		return "未知"
	}
}

func containsSubstring(s, substr string) bool {
	return len(s) >= len(substr) && (s == substr || len(substr) == 0 || (len(s) > 0 && len(substr) > 0 && contains(s, substr)))
}

func contains(s, substr string) bool {
	for i := 0; i <= len(s)-len(substr); i++ {
		if s[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}
