package service

import (
	"fmt"

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

	"gorm.io/gorm"
)

// FavoriteStore FavoriteService 所需的最小仓储接口（ISP）
type FavoriteStore interface {
	// Folder
	CreateFolder(folder *model.Folder) error
	FindFolderByID(id uint) (*model.Folder, error)
	ListFoldersByUser(userID uint) ([]model.Folder, error)
	UpdateFolder(folder *model.Folder) error
	DeleteFolder(id uint) error
	DeleteItemsByFolder(folderID uint) error
	CountByNameAndUser(userID uint, name string, excludeID uint) (int64, error)
	HasDefaultFolder(userID uint) (bool, error)
	// FolderItem
	CreateItem(item *model.FolderItem) error
	DeleteItem(folderID, postID uint) error
	FindItemByUserAndPost(userID, postID uint) (*model.FolderItem, error)
	ListItemsByFolder(folderID uint, offset, limit int) ([]model.FolderItem, int64, error)
	CountItemsByFolder(folderID uint) (int64, error)
	// Post counter
	IncrPostFavoritesCount(postID uint, delta int) error
	// Trend
	AggregateFavoritesByAuthor(userID uint, since string) ([]TrendPoint, error)
	// Tx
	WithTx(tx *gorm.DB) FavoriteStore
}

// FavoriteListResult 收藏夹列表 + 收藏内容
type FavoriteListResult struct {
	Folders []model.Folder `json:"folders"`
}

// FolderItemsResult 收藏夹内容
type FolderItemsResult struct {
	Items      []model.FolderItem `json:"items"`
	Total      int64              `json:"total"`
	Page       int                `json:"page"`
	TotalPages int                `json:"total_pages"`
}

// FavoriteStatus 某文章的收藏状态
type FavoriteStatus struct {
	Favorited bool   `json:"favorited"`
	FolderID  *uint  `json:"folder_id,omitempty"`
	FolderName *string `json:"folder_name,omitempty"`
}

// FavoriteService 收藏夹业务逻辑
type FavoriteService struct {
	db   *gorm.DB
	repo FavoriteStore
}

// NewFavoriteService 构造函数
func NewFavoriteService(db *gorm.DB, repo FavoriteStore) *FavoriteService {
	return &FavoriteService{db: db, repo: repo}
}

// ensureDefaultFolder 确保用户有默认收藏夹（不存在则创建）
func (s *FavoriteService) ensureDefaultFolder(userID uint) (*model.Folder, error) {
	has, err := s.repo.HasDefaultFolder(userID)
	if err != nil {
		return nil, fmt.Errorf("查询默认收藏夹: %w", err)
	}
	if has {
		folders, err := s.repo.ListFoldersByUser(userID)
		if err != nil {
			return nil, fmt.Errorf("查询收藏夹列表: %w", err)
		}
		for _, f := range folders {
			if f.IsDefault {
				return &f, nil
			}
		}
	}

	// 创建默认收藏夹
	f := &model.Folder{
		UserID:      userID,
		Name:        "默认",
		Description: "自动创建的默认收藏夹",
		IsPublic:    false,
		IsDefault:   true,
	}
	if err := s.repo.CreateFolder(f); err != nil {
		return nil, fmt.Errorf("创建默认收藏夹: %w", err)
	}
	return f, nil
}

// ListFolders 获取用户的所有收藏夹
func (s *FavoriteService) ListFolders(userID uint) (*FavoriteListResult, error) {
	folders, err := s.repo.ListFoldersByUser(userID)
	if err != nil {
		return nil, fmt.Errorf("查询收藏夹: %w", err)
	}
	if folders == nil {
		folders = []model.Folder{}
	}
	return &FavoriteListResult{Folders: folders}, nil
}

// CreateFolder 创建收藏夹
func (s *FavoriteService) CreateFolder(userID uint, name, description string, isPublic bool) (*model.Folder, error) {
	if name == "" {
		return nil, fmt.Errorf("收藏夹名称不能为空")
	}
	if len(name) > 50 {
		return nil, fmt.Errorf("收藏夹名称不能超过 50 个字符")
	}

	// 检查名称是否重复
	count, err := s.repo.CountByNameAndUser(userID, name, 0)
	if err != nil {
		return nil, fmt.Errorf("检查名称: %w", err)
	}
	if count > 0 {
		return nil, fmt.Errorf("收藏夹名称已存在")
	}

	f := &model.Folder{
		UserID:      userID,
		Name:        name,
		Description: description,
		IsPublic:    isPublic,
	}
	if err := s.repo.CreateFolder(f); err != nil {
		return nil, fmt.Errorf("创建收藏夹: %w", err)
	}
	return f, nil
}

// UpdateFolder 修改收藏夹（默认收藏夹不可改名/改描述）
func (s *FavoriteService) UpdateFolder(userID, folderID uint, name, description string, isPublic bool) error {
	f, err := s.repo.FindFolderByID(folderID)
	if err != nil {
		return common.ErrPostNotFound // 复用错误哨兵
	}
	if f.UserID != userID {
		return common.ErrPermissionDenied
	}

	if f.IsDefault {
		// 默认收藏夹只允许修改公开性
		f.IsPublic = isPublic
		return s.repo.UpdateFolder(f)
	}

	if name == "" {
		return fmt.Errorf("收藏夹名称不能为空")
	}

	// 检查名称重复
	count, err := s.repo.CountByNameAndUser(userID, name, folderID)
	if err != nil {
		return fmt.Errorf("检查名称: %w", err)
	}
	if count > 0 {
		return fmt.Errorf("收藏夹名称已存在")
	}

	f.Name = name
	f.Description = description
	f.IsPublic = isPublic
	return s.repo.UpdateFolder(f)
}

// DeleteFolder 删除收藏夹（默认不可删）
func (s *FavoriteService) DeleteFolder(userID, folderID uint) error {
	f, err := s.repo.FindFolderByID(folderID)
	if err != nil {
		return common.ErrPostNotFound
	}
	if f.UserID != userID {
		return common.ErrPermissionDenied
	}
	if f.IsDefault {
		return fmt.Errorf("默认收藏夹不可删除")
	}

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

		// 先清理 items 的 fans 计数
		items, _, _ := txRepo.ListItemsByFolder(folderID, 0, 10000)
		for _, item := range items {
			if err := txRepo.IncrPostFavoritesCount(item.PostID, -1); err != nil {
				return fmt.Errorf("更新文章收藏数: %w", err)
			}
		}

		if err := txRepo.DeleteItemsByFolder(folderID); err != nil {
			return fmt.Errorf("删除收藏内容: %w", err)
		}

		return txRepo.DeleteFolder(folderID)
	})
}

// AddToFolder 将文章加入收藏夹（会先移除该文章在其他收藏夹的收藏）
func (s *FavoriteService) AddToFolder(userID, folderID, postID uint) error {
	// 检查收藏夹归属
	f, err := s.repo.FindFolderByID(folderID)
	if err != nil {
		return common.ErrPostNotFound
	}
	if f.UserID != userID {
		return common.ErrPermissionDenied
	}

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

		// 如果该文章已在其他收藏夹中，先移除
		existing, err := txRepo.FindItemByUserAndPost(userID, postID)
		if err == nil && existing.FolderID != folderID {
			if err := txRepo.DeleteItem(existing.FolderID, postID); err != nil {
				return fmt.Errorf("移除旧收藏: %w", err)
			}
			// 旧收藏夹没有增加计数，所以不需要减
		}

		// 检查是否已在目标收藏夹中
		if err == nil && existing.FolderID == folderID {
			return fmt.Errorf("文章已在此收藏夹中")
		}

		item := &model.FolderItem{
			FolderID: folderID,
			PostID:   postID,
			UserID:   userID,
		}
		if err := txRepo.CreateItem(item); err != nil {
			return fmt.Errorf("添加收藏: %w", err)
		}

		return txRepo.IncrPostFavoritesCount(postID, 1)
	})
}

// RemoveFromFolder 从收藏夹移除文章
func (s *FavoriteService) RemoveFromFolder(userID, folderID, postID uint) error {
	f, err := s.repo.FindFolderByID(folderID)
	if err != nil {
		return common.ErrPostNotFound
	}
	if f.UserID != userID {
		return common.ErrPermissionDenied
	}

	return s.db.Transaction(func(tx *gorm.DB) error {
		txRepo := s.repo.WithTx(tx)
		if err := txRepo.DeleteItem(folderID, postID); err != nil {
			return fmt.Errorf("移除收藏: %w", err)
		}
		return txRepo.IncrPostFavoritesCount(postID, -1)
	})
}

// AddFavorite 收藏文章（自动选择或创建默认收藏夹）
func (s *FavoriteService) AddFavorite(userID, postID uint, folderID *uint) error {
	var targetFolderID uint

	if folderID != nil && *folderID > 0 {
		targetFolderID = *folderID
	} else {
		// 使用或创建默认收藏夹
		f, err := s.ensureDefaultFolder(userID)
		if err != nil {
			return err
		}
		targetFolderID = f.ID
	}

	return s.AddToFolder(userID, targetFolderID, postID)
}

// RemoveFavorite 取消收藏文章
func (s *FavoriteService) RemoveFavorite(userID, postID uint) error {
	existing, err := s.repo.FindItemByUserAndPost(userID, postID)
	if err != nil {
		return fmt.Errorf("未收藏该文章")
	}
	return s.RemoveFromFolder(userID, existing.FolderID, postID)
}

// ListFolderItems 列收藏夹内的文章
func (s *FavoriteService) ListFolderItems(userID, folderID uint, page, pageSize int) (*FolderItemsResult, error) {
	f, err := s.repo.FindFolderByID(folderID)
	if err != nil {
		return nil, common.ErrPostNotFound
	}

	// 权限检查：非本人 + 非公开 → 拒绝
	if f.UserID != userID && !f.IsPublic {
		return nil, common.ErrPermissionDenied
	}

	p := common.Pagination{Page: page, PageSize: pageSize}
	p.DefaultPagination()

	items, total, err := s.repo.ListItemsByFolder(folderID, p.Offset(), p.PageSize)
	if err != nil {
		return nil, fmt.Errorf("查询收藏内容: %w", err)
	}
	if items == nil {
		items = []model.FolderItem{}
	}

	return &FolderItemsResult{
		Items:      items,
		Total:      total,
		Page:       p.Page,
		TotalPages: common.PageCount(total, p.PageSize),
	}, nil
}

// GetPostFavoriteStatus 查询文章收藏状态
func (s *FavoriteService) GetPostFavoriteStatus(userID, postID uint) (*FavoriteStatus, error) {
	item, err := s.repo.FindItemByUserAndPost(userID, postID)
	if err != nil {
		return &FavoriteStatus{Favorited: false}, nil
	}

	f, err := s.repo.FindFolderByID(item.FolderID)
	var folderName *string
	if err == nil {
		folderName = &f.Name
	}

	return &FavoriteStatus{
		Favorited:  true,
		FolderID:   &item.FolderID,
		FolderName: folderName,
	}, nil
}

// ToggleFavorite 切换收藏（有则取消，无则加入默认收藏夹）
func (s *FavoriteService) ToggleFavorite(userID, postID uint) (bool, error) {
	existing, err := s.repo.FindItemByUserAndPost(userID, postID)
	if err == nil {
		// 已收藏，取消
		if err := s.RemoveFromFolder(userID, existing.FolderID, postID); err != nil {
			return false, err
		}
		return false, nil
	}

	// 未收藏，加入默认
	if err := s.AddFavorite(userID, postID, nil); err != nil {
		return false, err
	}
	return true, nil
}
