package repository

import (
	"time"

	"metazone.cc/metalab/internal/model"
	"metazone.cc/metalab/internal/service"

	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

// EnergyRepo 域能数据访问
type EnergyRepo struct {
	db *gorm.DB
}

// NewEnergyRepo 构造函数
func NewEnergyRepo(db *gorm.DB) *EnergyRepo {
	return &EnergyRepo{db: db}
}

// WithTx 基于给定事务连接创建新的 EnergyRepo（确保事务内操作原子性）
func (r *EnergyRepo) WithTx(tx *gorm.DB) service.EnergyStore {
	return &EnergyRepo{db: tx}
}

// FindUserByID 查找用户（获取能量余额等）
func (r *EnergyRepo) FindUserByID(userID uint) (*model.User, error) {
	var user model.User
	err := r.db.First(&user, userID).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// FindPostByID 查找帖子
func (r *EnergyRepo) FindPostByID(postID uint) (*model.Post, error) {
	var post model.Post
	err := r.db.First(&post, postID).Error
	if err != nil {
		return nil, err
	}
	return &post, nil
}

// AddEnergy 原子增减用户域能余额（amount 可为正负）
func (r *EnergyRepo) AddEnergy(userID uint, amount int) error {
	return r.db.Model(&model.User{}).
		Where("uid = ?", userID).
		UpdateColumn("energy", gorm.Expr("energy + ?", amount)).Error
}

// IncrPostEnergy 原子增减文章累计被赋能域能
func (r *EnergyRepo) IncrPostEnergy(postID uint, amount int) error {
	return r.db.Model(&model.Post{}).
		Where("id = ?", postID).
		UpdateColumn("total_energy_received", gorm.Expr("total_energy_received + ?", amount)).Error
}

// CreateEnergyLog 创建域能流水
func (r *EnergyRepo) CreateEnergyLog(log *model.EnergyLog) error {
	return r.db.Create(log).Error
}

// SumUserPostEnergy 统计某用户对某文章累计赋能总量（用于 ≤ 20 检查）
func (r *EnergyRepo) SumUserPostEnergy(userID, postID uint) (int, error) {
	var total int
	err := r.db.Model(&model.PostEnergizeLog{}).
		Where("user_id = ? AND post_id = ?", userID, postID).
		Select("COALESCE(SUM(amount), 0)").
		Scan(&total).Error
	return total, err
}

// CreateEnergizeLog 创建赋能记录
func (r *EnergyRepo) CreateEnergizeLog(log *model.PostEnergizeLog) error {
	return r.db.Create(log).Error
}

// GetDailyEnergizeExp 获取用户当日通过赋能获得的经验值
// 无记录时返回 nil, nil（调用方当作 exp=0 处理）
func (r *EnergyRepo) GetDailyEnergizeExp(userID uint, date time.Time) (*model.DailyExpSummary, error) {
	var summaries []model.DailyExpSummary
	err := r.db.Where("user_id = ? AND date = ?", userID, date).Limit(1).Find(&summaries).Error
	if err != nil {
		return nil, err
	}
	if len(summaries) == 0 {
		return nil, nil
	}
	return &summaries[0], nil
}

// UpsertDailyExp 创建或更新每日经验汇总
func (r *EnergyRepo) UpsertDailyExp(summary *model.DailyExpSummary) error {
	return r.db.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "user_id"}, {Name: "date"}},
		DoUpdates: clause.AssignmentColumns([]string{"exp_earned", "updated_at"}),
	}).Create(summary).Error
}

// AddDailyExp 原子增加每日赋能经验值
func (r *EnergyRepo) AddDailyExp(userID uint, date time.Time, delta int) error {
	return r.db.Model(&model.DailyExpSummary{}).
		Where("user_id = ? AND date = ?", userID, date).
		UpdateColumn("exp_earned", gorm.Expr("exp_earned + ?", delta)).Error
}

// ListEnergyLogsByUser 分页查询用户域能流水（近 N 天）
func (r *EnergyRepo) ListEnergyLogsByUser(userID uint, days int, offset, limit int) ([]model.EnergyLog, error) {
	var logs []model.EnergyLog
	query := r.db.Where("user_id = ?", userID).Order("created_at DESC")
	if days > 0 {
		since := time.Now().AddDate(0, 0, -days)
		query = query.Where("created_at >= ?", since)
	}
	err := query.Offset(offset).Limit(limit).Find(&logs).Error
	return logs, err
}

// CountEnergyLogsByUser 统计用户域能流水总数
func (r *EnergyRepo) CountEnergyLogsByUser(userID uint, days int) (int64, error) {
	var count int64
	query := r.db.Model(&model.EnergyLog{}).Where("user_id = ?", userID)
	if days > 0 {
		since := time.Now().AddDate(0, 0, -days)
		query = query.Where("created_at >= ?", since)
	}
	err := query.Count(&count).Error
	return count, err
}

// ListAllEnergyLogs 查询全部域能流水（后台，支持筛选）
func (r *EnergyRepo) ListAllEnergyLogs(energyType string, offset, limit int) ([]model.EnergyLog, int64, error) {
	query := r.db.Model(&model.EnergyLog{})
	if energyType != "" {
		query = query.Where("type = ?", energyType)
	}
	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	var logs []model.EnergyLog
	err := query.Order("created_at DESC").Offset(offset).Limit(limit).Find(&logs).Error
	return logs, total, err
}
