package model

import (
	"errors"
	"fmt"
	"strings"

	"github.com/QuantumNous/new-api/common"

	"gorm.io/gorm"
)

// AffInviteProfitShareLog 利润分成模式下，单次请求结算产生的分销入账流水。
type AffInviteProfitShareLog struct {
	Id               int    `json:"id" gorm:"primaryKey;autoIncrement"`
	InviterId        int    `json:"inviter_id" gorm:"not null;index:idx_aff_ps_inv_inv,priority:1"`
	InviteeUserId    int    `json:"invitee_user_id" gorm:"not null;index:idx_aff_ps_inv_inv,priority:2;index"`
	ChannelId        int    `json:"channel_id" gorm:"not null;column:channel_id"`
	RouteSlug        string `json:"route_slug,omitempty" gorm:"-"`
	ModelName        string `json:"model_name" gorm:"type:varchar(255);not null;default:'';column:model_name"`
	UserQuotaCharged int    `json:"user_quota_charged" gorm:"not null;column:user_quota_charged"`
	MarkupSliceQuota int    `json:"markup_slice_quota" gorm:"not null;column:markup_slice_quota"`
	RewardQuota      int    `json:"reward_quota" gorm:"not null;column:reward_quota"`
	// CommissionBps 本条结算适用的代理分润比例（万分之一，与 AffiliateDefaultCommissionBps / EffectiveAffiliateCommissionBps 同单位）。
	CommissionBps int   `json:"commission_bps" gorm:"not null;default:0;column:commission_bps"`
	CreatedAt     int64 `json:"created_at" gorm:"bigint;index"`
}

func (AffInviteProfitShareLog) TableName() string {
	return "aff_invite_profit_share_logs"
}

// CreditDistributorProfitShare 将利润分成「入账额度」记入邀请人 aff_quota，并累计关系表 profit_share_earned_quota。
// markupSliceQuota：用户扣费中的加价切片（分润基数）；rewardQuota：基数 × 生效分润比例后的入账额度（rewardQuota <= markupSliceQuota）。
// commissionBps：本条入账采用的万分之一比例（记入流水供明细展示）。
func CreditDistributorProfitShare(inviterId, inviteeUserId, channelId int, modelName string, userQuotaCharged, markupSliceQuota, rewardQuota, commissionBps int) error {
	if inviterId <= 0 || inviteeUserId <= 0 || rewardQuota <= 0 {
		return nil
	}
	if markupSliceQuota < 0 {
		markupSliceQuota = 0
	}
	reward := rewardQuota
	modelName = strings.TrimSpace(modelName)
	ts := common.GetTimestamp()

	return DB.Transaction(func(tx *gorm.DB) error {
		up := tx.Model(&User{}).Where("id = ?", inviterId).Updates(map[string]interface{}{
			"aff_quota":   gorm.Expr("aff_quota + ?", reward),
			"aff_history": gorm.Expr("aff_history + ?", reward),
		})
		if up.Error != nil {
			return up.Error
		}
		if up.RowsAffected == 0 {
			return fmt.Errorf("inviter user not found: %d", inviterId)
		}
		res := tx.Model(&AffInviteRelation{}).
			Where("inviter_id = ? AND invitee_user_id = ?", inviterId, inviteeUserId).
			UpdateColumn("profit_share_earned_quota", gorm.Expr("profit_share_earned_quota + ?", reward))
		if res.Error != nil {
			return res.Error
		}
		if commissionBps < 0 {
			commissionBps = 0
		}
		if commissionBps > maxAffiliateCommissionBps {
			commissionBps = maxAffiliateCommissionBps
		}
		row := AffInviteProfitShareLog{
			InviterId:        inviterId,
			InviteeUserId:    inviteeUserId,
			ChannelId:        channelId,
			ModelName:        modelName,
			UserQuotaCharged: userQuotaCharged,
			MarkupSliceQuota: markupSliceQuota,
			RewardQuota:      reward,
			CommissionBps:    commissionBps,
			CreatedAt:        ts,
		}
		return tx.Create(&row).Error
	})
}

// ListAffInviteProfitShareLogs 分页返回某邀请人对某一被邀请人的利润分成明细。
func ListAffInviteProfitShareLogs(inviterId, inviteeUserId int, pageInfo *common.PageInfo) ([]AffInviteProfitShareLog, int64, error) {
	if inviterId <= 0 || inviteeUserId <= 0 {
		return nil, 0, errors.New("invalid id")
	}
	var total int64
	base := DB.Model(&AffInviteProfitShareLog{}).Where("inviter_id = ? AND invitee_user_id = ?", inviterId, inviteeUserId)
	if err := base.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	var rows []AffInviteProfitShareLog
	err := DB.Where("inviter_id = ? AND invitee_user_id = ?", inviterId, inviteeUserId).
		Order("created_at DESC").
		Limit(pageInfo.GetPageSize()).
		Offset(pageInfo.GetStartIdx()).
		Find(&rows).Error
	if err != nil {
		return nil, 0, err
	}
	if rows == nil {
		rows = []AffInviteProfitShareLog{}
	}
	attachProfitShareLogRouteSlugs(rows)
	return rows, total, nil
}

func attachProfitShareLogRouteSlugs(rows []AffInviteProfitShareLog) {
	if len(rows) == 0 {
		return
	}
	ids := make([]int, 0, len(rows))
	seen := make(map[int]struct{}, len(rows))
	for i := range rows {
		cid := rows[i].ChannelId
		if cid <= 0 {
			continue
		}
		if _, ok := seen[cid]; ok {
			continue
		}
		seen[cid] = struct{}{}
		ids = append(ids, cid)
	}
	slugMap := GetRouteSlugsByChannelIDs(ids)
	for i := range rows {
		cid := rows[i].ChannelId
		if cid <= 0 {
			continue
		}
		slug := ""
		if slugMap != nil {
			slug = strings.TrimSpace(slugMap[cid])
		}
		if slug == "" {
			slug = DefaultRouteSlugFromChannelID(int64(cid))
		}
		rows[i].RouteSlug = slug
	}
}
