package repository

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

	"gorm.io/gorm"
)

// ReactionRepo 赞/踩数据访问
type ReactionRepo struct {
	db *gorm.DB
}

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

// WithTx 基于给定事务连接创建新的 ReactionRepo
func (r *ReactionRepo) WithTx(tx *gorm.DB) service.ReactionStore {
	return &ReactionRepo{db: tx}
}

// FindLike 查找点赞记录
func (r *ReactionRepo) FindLike(userID, postID uint) (*model.PostLike, error) {
	var like model.PostLike
	err := r.db.Where("user_id = ? AND post_id = ?", userID, postID).First(&like).Error
	if err != nil {
		return nil, err
	}
	return &like, nil
}

// CreateLike 创建点赞记录
func (r *ReactionRepo) CreateLike(like *model.PostLike) error {
	return r.db.Create(like).Error
}

// DeleteLike 删除点赞记录
func (r *ReactionRepo) DeleteLike(userID, postID uint) error {
	return r.db.Where("user_id = ? AND post_id = ?", userID, postID).Delete(&model.PostLike{}).Error
}

// FindDislike 查找踩记录
func (r *ReactionRepo) FindDislike(userID, postID uint) (*model.PostDislike, error) {
	var dislike model.PostDislike
	err := r.db.Where("user_id = ? AND post_id = ?", userID, postID).First(&dislike).Error
	if err != nil {
		return nil, err
	}
	return &dislike, nil
}

// CreateDislike 创建踩记录
func (r *ReactionRepo) CreateDislike(dislike *model.PostDislike) error {
	return r.db.Create(dislike).Error
}

// DeleteDislike 删除踩记录
func (r *ReactionRepo) DeleteDislike(userID, postID uint) error {
	return r.db.Where("user_id = ? AND post_id = ?", userID, postID).Delete(&model.PostDislike{}).Error
}

// IncrPostLikes 原子增加文章点赞数
func (r *ReactionRepo) IncrPostLikes(postID uint, delta int) error {
	return r.db.Model(&model.Post{}).
		Where("id = ?", postID).
		UpdateColumn("likes_count", gorm.Expr("likes_count + ?", delta)).Error
}

// IncrPostDislikes 原子增加文章踩数
func (r *ReactionRepo) IncrPostDislikes(postID uint, delta int) error {
	return r.db.Model(&model.Post{}).
		Where("id = ?", postID).
		UpdateColumn("dislikes_count", gorm.Expr("dislikes_count + ?", delta)).Error
}

// GetPostAuthorID 查询文章作者ID
func (r *ReactionRepo) GetPostAuthorID(postID uint) (uint, error) {
	var post model.Post
	err := r.db.Select("user_id").First(&post, postID).Error
	return post.UserID, err
}

// UpsertDailyLikeSummary 追加或创建每日点赞汇总
func (r *ReactionRepo) UpsertDailyLikeSummary(authorUID uint, date string, likerUID string) error {
	var existing model.DailyLikeSummary
	err := r.db.Where("author_uid = ? AND date = ?", authorUID, date).First(&existing).Error
	if err == gorm.ErrRecordNotFound {
		return r.db.Create(&model.DailyLikeSummary{
			AuthorUID: authorUID,
			Date:      date,
			LikerUIDs: likerUID,
			Notified:  false,
		}).Error
	}
	if err != nil {
		return err
	}
	// 追加 likerUID
	newUids := existing.LikerUIDs
	if newUids == "" {
		newUids = likerUID
	} else {
		newUids = newUids + "," + likerUID
	}
	return r.db.Model(&existing).Update("liker_uids", newUids).Error
}

// GetUnnotifiedSummaries 查询未通知的每日点赞汇总
func (r *ReactionRepo) GetUnnotifiedSummaries(userID uint) ([]model.DailyLikeSummary, error) {
	var summaries []model.DailyLikeSummary
	err := r.db.Where("author_uid = ? AND notified = ?", userID, false).Find(&summaries).Error
	return summaries, err
}

// MarkSummaryNotified 标记汇总已通知
func (r *ReactionRepo) MarkSummaryNotified(id uint) error {
	return r.db.Model(&model.DailyLikeSummary{}).Where("id = ?", id).Update("notified", true).Error
}

// AggregateLikesByAuthor 按日期聚合点赞量（作者所有文章在时间段内的点赞）
func (r *ReactionRepo) AggregateLikesByAuthor(userID uint, since string) ([]service.TrendPoint, error) {
	var results []service.TrendPoint
	err := r.db.Table("post_likes").
		Select("TO_CHAR(post_likes.created_at, 'YYYY-MM-DD') AS date, COUNT(*) AS value").
		Joins("JOIN posts ON posts.id = post_likes.post_id").
		Where("posts.user_id = ? AND post_likes.created_at >= ?", userID, since).
		Group("TO_CHAR(post_likes.created_at, 'YYYY-MM-DD')").
		Order("date ASC").
		Scan(&results).Error
	if results == nil {
		results = []service.TrendPoint{}
	}
	return results, err
}
