package service

import (
	"errors"
	"fmt"

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

	"gorm.io/gorm"
)

// PostService 帖子业务逻辑
type PostService struct {
	repo                postStore
	ss                  *config.SiteSettings
	notifier            postNotifier
	userRepo            userExpReader
	onHomePageChanged   func()
}

// NewPostService 构造函数
func NewPostService(repo postStore, ss *config.SiteSettings, notifier postNotifier, userRepo userExpReader) *PostService {
	return &PostService{
		repo:     repo,
		ss:       ss,
		notifier: notifier,
		userRepo: userRepo,
	}
}

// WithHomePageInvalidator 注入首页缓存失效回调（文章变更时触发）
func (s *PostService) WithHomePageInvalidator(fn func()) {
	s.onHomePageChanged = fn
}

// auditEnabled 审核是否开启
func (s *PostService) auditEnabled() bool {
	return s.ss.IsAuditEnabled()
}

// findPost 按 ID 查找帖子，区分"未找到"和"数据库错误"
func (s *PostService) findPost(id uint) (*model.Post, error) {
	post, err := s.repo.FindByID(id)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, common.ErrPostNotFound
		}
		return nil, fmt.Errorf("查询帖子失败: %w", err)
	}
	return post, nil
}

// findPostWithAuthor 按 ID 查找帖子（含作者名），区分"未找到"和"数据库错误"
func (s *PostService) findPostWithAuthor(id uint) (*model.Post, error) {
	post, err := s.repo.FindByIDWithAuthor(id)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, common.ErrPostNotFound
		}
		return nil, fmt.Errorf("查询帖子失败: %w", err)
	}
	return post, nil
}

// Create 创建帖子
// body 为 Vditor 输出的 Markdown，后端直接存储不做 HTML 消毒
// MD 是纯文本，无 XSS 注入风险；前端渲染时由 Vditor 转 HTML
func (s *PostService) Create(userID uint, title, body string) (*model.Post, error) {
	status := model.PostStatusApproved
	if s.auditEnabled() {
		status = model.PostStatusDraft
	}

	post := &model.Post{
		Title:        title,
		Body:         body,
		Excerpt:      generateExcerpt(body),
		UserID:       userID,
		Status:       status,
		AllowComment: true,
	}
	if err := s.repo.Create(post); err != nil {
		return nil, err
	}
	s.invalidateHomeCache()
	return post, nil
}

// GetByID 按 ID 获取帖子（含作者名，仅 approved 公开可见）
func (s *PostService) GetByID(id uint) (*model.Post, error) {
	return s.findPostWithAuthor(id)
}

// listPageable 分页查询公共逻辑：参数规范化 + nil 转空切片
func (s *PostService) listPageable(page, pageSize int, fn func(offset, limit int) ([]model.Post, int64, error)) ([]model.Post, int64, error) {
	p := common.Pagination{Page: page, PageSize: pageSize}
	p.DefaultPagination()
	posts, total, err := fn(p.Offset(), p.PageSize)
	if posts == nil {
		posts = []model.Post{}
	}
	return posts, total, err
}

// List 公开帖子列表（仅 approved）
func (s *PostService) List(keyword string, page, pageSize int) ([]model.Post, int64, error) {
	return s.listPageable(page, pageSize, func(offset, limit int) ([]model.Post, int64, error) {
		return s.repo.FindPageable(keyword, offset, limit)
	})
}

// ListAdmin 管理后台帖子列表（全状态）
func (s *PostService) ListAdmin(keyword, status string, page, pageSize int) ([]model.Post, int64, error) {
	return s.listPageable(page, pageSize, func(offset, limit int) ([]model.Post, int64, error) {
		return s.repo.FindAdminPageable(keyword, status, offset, limit)
	})
}

// ListByUser 查询某用户指定状态的帖子（空 status=全状态）
func (s *PostService) ListByUser(userID uint, status string, page, pageSize int) ([]model.Post, int64, error) {
	return s.listPageable(page, pageSize, func(offset, limit int) ([]model.Post, int64, error) {
		return s.repo.FindByUserIDAndStatus(userID, status, offset, limit)
	})
}

// StudioOverview 创作中心数据概览
type StudioOverview struct {
	TotalPosts   int64 `json:"total_posts"`
	DraftCount   int64 `json:"draft_count"`
	PendingCount int64 `json:"pending_count"`
	ApprovedCount int64 `json:"approved_count"`
	RejectedCount int64 `json:"rejected_count"`
	TotalViews   int64 `json:"total_views"`
}

// GetOverview 获取创作中心数据概览（单次 GROUP BY 查询）
func (s *PostService) GetOverview(userID uint) (*StudioOverview, error) {
	totalPosts, draftCount, pendingCount, approvedCount, rejectedCount, totalViews, err := s.repo.GetOverviewByUserID(userID)
	if err != nil {
		return nil, err
	}
	return &StudioOverview{
		TotalPosts:    totalPosts,
		DraftCount:    draftCount,
		PendingCount:  pendingCount,
		ApprovedCount: approvedCount,
		RejectedCount: rejectedCount,
		TotalViews:    totalViews,
	}, nil
}

// IsPostAccessible 检查用户是否有权限访问/操作帖子（作者或 moderator+）
func (s *PostService) IsPostAccessible(userID uint, role string, postUserID uint) bool {
	return userID == postUserID || model.HasMinRole(role, model.RoleModerator)
}

// CanCreatePost 检查用户是否可以创建帖子（LV0 用户不允许投稿）
func (s *PostService) CanCreatePost(userID uint) bool {
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return false
	}
	return user.Exp >= 1
}

// invalidateHomeCache 失效首页缓存（异步安全调用）
func (s *PostService) invalidateHomeCache() {
	if s.onHomePageChanged != nil {
		s.onHomePageChanged()
	}
}

// RecordRead 记录已登录用户阅读文章（已登录去重 + 防刷冷却）
func (s *PostService) RecordRead(userID, postID uint) {
	firstRead, err := s.repo.RecordRead(userID, postID)
	if err != nil || !firstRead {
		return
	}
	_ = s.repo.IncrementViewsCount(postID)
}

// RecordGuestRead 记录访客阅读文章（Cookie 标识去重 + 防刷冷却）
func (s *PostService) RecordGuestRead(visitorID string, postID uint) {
	firstRead, err := s.repo.RecordGuestRead(visitorID, postID)
	if err != nil || !firstRead {
		return
	}
	_ = s.repo.IncrementViewsCount(postID)
}
