package service

import (
	"fmt"
	"time"

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

	"gorm.io/gorm"
)

// ReactionType 反应类型
type ReactionType string

const (
	ReactionNone    ReactionType = "none"
	ReactionLiked   ReactionType = "liked"
	ReactionDisliked ReactionType = "disliked"
)

// ReactionService 赞/踩业务逻辑
type ReactionService struct {
	db   *gorm.DB
	repo ReactionStore
}

// NewReactionService 构造函数
func NewReactionService(db *gorm.DB, repo ReactionStore) *ReactionService {
	return &ReactionService{db: db, repo: repo}
}

// ToggleLike 切换点赞（含踩互斥逻辑）
// 返回：当前是否已点赞
func (s *ReactionService) ToggleLike(userID, postID uint) (bool, error) {
	var isLiked bool

	err := s.db.Transaction(func(tx *gorm.DB) error {
		txRepo := s.repo.WithTx(tx)

		// 查当前状态
		_, likeErr := txRepo.FindLike(userID, postID)
		hasLike := likeErr == nil

		_, dislikeErr := txRepo.FindDislike(userID, postID)
		hasDislike := dislikeErr == nil

		if hasLike {
			// 已赞 → 取消赞
			if err := txRepo.DeleteLike(userID, postID); err != nil {
				return fmt.Errorf("取消点赞失败: %w", err)
			}
			if err := txRepo.IncrPostLikes(postID, -1); err != nil {
				return fmt.Errorf("更新点赞计数失败: %w", err)
			}
			isLiked = false
		} else {
			// 无赞 → 加赞（若已有踩，先移除踩）
			if hasDislike {
				if err := txRepo.DeleteDislike(userID, postID); err != nil {
					return fmt.Errorf("移除踩记录失败: %w", err)
				}
				if err := txRepo.IncrPostDislikes(postID, -1); err != nil {
					return fmt.Errorf("更新踩计数失败: %w", err)
				}
			}

			if err := txRepo.CreateLike(&model.PostLike{UserID: userID, PostID: postID}); err != nil {
				return fmt.Errorf("创建点赞记录失败: %w", err)
			}
			if err := txRepo.IncrPostLikes(postID, 1); err != nil {
				return fmt.Errorf("更新点赞计数失败: %w", err)
			}
			isLiked = true
		}
		return nil
	})

	if err == nil && isLiked {
		// 新赞 → 记录到每日点赞汇总（非关键路径）
		s.recordLikeForAggregation(postID, userID)
	}

	return isLiked, err
}

// recordLikeForAggregation 记录点赞到每日汇总（非关键路径，失败不阻塞）
func (s *ReactionService) recordLikeForAggregation(postID uint, likerID uint) {
	authorID, err := s.repo.GetPostAuthorID(postID)
	if err != nil {
		return
	}
	// 不记录自己赞自己
	if authorID == likerID {
		return
	}
	date := time.Now().Format("2006-01-02")
	likerUID := fmt.Sprintf("%d", likerID)
	_ = s.repo.UpsertDailyLikeSummary(authorID, date, likerUID)
}

// ToggleDislike 切换踩（含赞互斥逻辑）
// 返回：当前是否已踩
func (s *ReactionService) ToggleDislike(userID, postID uint) (bool, error) {
	var isDisliked bool

	err := s.db.Transaction(func(tx *gorm.DB) error {
		txRepo := s.repo.WithTx(tx)

		// 查当前状态
		_, likeErr := txRepo.FindLike(userID, postID)
		hasLike := likeErr == nil

		_, dislikeErr := txRepo.FindDislike(userID, postID)
		hasDislike := dislikeErr == nil

		if hasDislike {
			// 已踩 → 取消踩
			if err := txRepo.DeleteDislike(userID, postID); err != nil {
				return fmt.Errorf("取消踩失败: %w", err)
			}
			if err := txRepo.IncrPostDislikes(postID, -1); err != nil {
				return fmt.Errorf("更新踩计数失败: %w", err)
			}
			isDisliked = false
		} else {
			// 无踩 → 加踩（若已有赞，先移除赞）
			if hasLike {
				if err := txRepo.DeleteLike(userID, postID); err != nil {
					return fmt.Errorf("移除点赞记录失败: %w", err)
				}
				if err := txRepo.IncrPostLikes(postID, -1); err != nil {
					return fmt.Errorf("更新点赞计数失败: %w", err)
				}
			}

			if err := txRepo.CreateDislike(&model.PostDislike{UserID: userID, PostID: postID}); err != nil {
				return fmt.Errorf("创建踩记录失败: %w", err)
			}
			if err := txRepo.IncrPostDislikes(postID, 1); err != nil {
				return fmt.Errorf("更新踩计数失败: %w", err)
			}
			isDisliked = true
		}
		return nil
	})

	return isDisliked, err
}

// GetReaction 查询用户对文章的反应状态
func (s *ReactionService) GetReaction(userID, postID uint) (ReactionType, error) {
	_, likeErr := s.repo.FindLike(userID, postID)
	if likeErr == nil {
		return ReactionLiked, nil
	}

	_, dislikeErr := s.repo.FindDislike(userID, postID)
	if dislikeErr == nil {
		return ReactionDisliked, nil
	}

	return ReactionNone, nil
}

// GetPostLikesCount 查询文章点赞数（公开展示）
func (s *ReactionService) GetPostLikesCount(postID uint) (int, error) {
	var post model.Post
	if err := s.db.Select("likes_count").First(&post, postID).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return 0, common.ErrPostNotFound
		}
		return 0, fmt.Errorf("查询文章失败: %w", err)
	}
	return post.LikesCount, nil
}
