package service

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

	"gorm.io/gorm"
)

// auditRepo AuditService 所需的最小仓储接口（ISP）
type auditRepo interface {
	Create(audit *model.AuditSubmission) error
	FindByID(id uint) (*model.AuditSubmission, error)
	FindPendingByUserAndType(userID uint, auditType string) (*model.AuditSubmission, error)
	Update(audit *model.AuditSubmission) error
	ListAudits(auditType, status string, offset, limit int) ([]model.AuditSubmission, error)
	CountAudits(auditType, status string) (int64, error)
	FindPendingByUserID(userID uint) ([]model.AuditSubmission, error)
	ExistsPendingByTypeAndValue(auditType, newValue string, excludeUserID uint) (bool, error)
}

// userProfileStore 审核服务所需的最小用户仓储接口（ISP）
type userProfileStore interface {
	FindByID(id uint) (*model.User, error)
	Update(user *model.User) error
	ExistsByUsername(username string) (bool, error)
}

// siteSettingsChecker 审核服务所需的站点设置接口（ISP：仅读取审核开关）
type siteSettingsChecker interface {
	IsAuditEnabled() bool
	IsAuditTypeEnabled(auditType string, defaultVal bool) bool
}

// auditNotifier 审核服务所需的通知接口（ISP：审核通过/拒绝时发送通知）
type auditNotifier interface {
	NotifyAuditApproved(userID uint, auditType string, relatedID uint)
	NotifyAuditRejected(userID uint, auditType, reason string, relatedID uint)
}

// AuditService 审核业务逻辑
type AuditService struct {
	auditRepo    auditRepo
	userRepo     userProfileStore
	settings     siteSettingsChecker
	defaultCfg   config.AuditConfig
	notifier     auditNotifier
}

// NewAuditService 构造函数
func NewAuditService(auditRepo auditRepo, userRepo userProfileStore, settings siteSettingsChecker, cfg config.AuditConfig, notifier auditNotifier) *AuditService {
	return &AuditService{
		auditRepo:  auditRepo,
		userRepo:   userRepo,
		settings:   settings,
		defaultCfg: cfg,
		notifier:   notifier,
	}
}

// ShouldAudit 判断指定用户是否需要走审核流程
// 规则：admin 及以上角色免审
func (s *AuditService) ShouldAudit(userID uint) (bool, error) {
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return false, err
	}
	return !model.HasMinRole(user.Role, model.RoleAdmin), nil
}

// Submit 提交审核
//   - 总开关未开 → 返回 ErrAuditDisabled
//   - 类型开关未开 → 返回 ErrAuditTypeOff
//   - 用户名类型 → 先检查是否已被占用
//   - 若存在同类型 pending → 标记旧记录为 rejected（理由"用户重新提交"），创建新 pending
func (s *AuditService) Submit(userID uint, auditType, newValue string) error {
	// 检查总开关
	if !s.settings.IsAuditEnabled() {
		return common.ErrAuditDisabled
	}

	// 检查类型开关
	if !s.settings.IsAuditTypeEnabled(auditType, s.typeDefault(auditType)) {
		return common.ErrAuditTypeOff
	}

	// 用户名冲突检查（提交时即拦截，避免提交到后台后审核失败）
	if auditType == model.AuditTypeUsername {
		// 1) users 表中已被占用
		exists, err := s.userRepo.ExistsByUsername(newValue)
		if err != nil {
			return err
		}
		if exists {
			return common.ErrUsernameTaken
		}
		// 2) 审核表中已有其他用户提交了同名 pending
		pendingExists, err := s.auditRepo.ExistsPendingByTypeAndValue(auditType, newValue, userID)
		if err != nil {
			return err
		}
		if pendingExists {
			return common.ErrUsernameTaken
		}
	}

	// 覆盖旧的同类型 pending
	existing, err := s.auditRepo.FindPendingByUserAndType(userID, auditType)
	if err == nil {
		reason := "用户重新提交"
		existing.Status = model.AuditStatusRejected
		existing.RejectReason = &reason
		_ = s.auditRepo.Update(existing)
	}

	submission := &model.AuditSubmission{
		UserID:    userID,
		AuditType: auditType,
		NewValue:  newValue,
		Status:    model.AuditStatusPending,
	}
	return s.auditRepo.Create(submission)
}

// SubmitProfileChanges 批量提交资料变更（用户名/签名），每个变更字段独立提交
// 仅提交有变更的字段，无变更的跳过
func (s *AuditService) SubmitProfileChanges(userID uint, currentUser *model.User, newUsername, newBio string) error {
	if newUsername != "" && newUsername != currentUser.Username {
		if err := s.Submit(userID, model.AuditTypeUsername, newUsername); err != nil {
			return err
		}
	}
	if newBio != "" && newBio != currentUser.Bio {
		if err := s.Submit(userID, model.AuditTypeBio, newBio); err != nil {
			return err
		}
	}
	return nil
}

// Approve 通过审核 → 更新 User 表对应字段
// 仅审核人可操作，不可审核自己的提交
func (s *AuditService) Approve(reviewerID uint, submissionID uint) error {
	return s.review(reviewerID, submissionID, true, "")
}

// Reject 拒绝审核 → 记录拒绝理由
func (s *AuditService) Reject(reviewerID uint, submissionID uint, reason string) error {
	return s.review(reviewerID, submissionID, false, reason)
}

// review 通用审核操作
func (s *AuditService) review(reviewerID uint, submissionID uint, approved bool, reason string) error {
	// 1. 查审核记录
	submission, err := s.auditRepo.FindByID(submissionID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return common.ErrAuditNotFound
		}
		return err
	}

	// 2. 必须 pending
	if submission.Status != model.AuditStatusPending {
		return common.ErrAuditNotPending
	}

	// 3. 查审核人信息
	reviewer, err := s.userRepo.FindByID(reviewerID)
	if err != nil {
		return common.ErrUserNotFound
	}

	// 4. 标记审核结果
	submission.ReviewedBy = &reviewerID
	submission.ReviewerName = &reviewer.Username
	if approved {
		submission.Status = model.AuditStatusApproved
		// 更新 User 表对应字段
		if err := s.applyApproval(submission); err != nil {
			return err
		}
		// 通知用户审核通过
		if s.notifier != nil {
			s.notifier.NotifyAuditApproved(submission.UserID, submission.AuditType, submission.ID)
		}
	} else {
		submission.Status = model.AuditStatusRejected
		submission.RejectReason = &reason
		// 通知用户审核被拒
		if s.notifier != nil {
			reasonMsg := reason
			s.notifier.NotifyAuditRejected(submission.UserID, submission.AuditType, reasonMsg, submission.ID)
		}
	}
	return s.auditRepo.Update(submission)
}

// applyApproval 将审核通过的内容写入 User 表
// 用户名审批前再次检查冲突（防止提交到审批期间被其他用户抢占）
func (s *AuditService) applyApproval(submission *model.AuditSubmission) error {
	user, err := s.userRepo.FindByID(submission.UserID)
	if err != nil {
		return common.ErrUserNotFound
	}

	switch submission.AuditType {
	case model.AuditTypeUsername:
		exists, err := s.userRepo.ExistsByUsername(submission.NewValue)
		if err != nil {
			return err
		}
		if exists {
			return common.ErrUsernameTaken
		}
		user.Username = submission.NewValue
	case model.AuditTypeAvatar:
		user.Avatar = submission.NewValue
	case model.AuditTypeBio:
		user.Bio = submission.NewValue
	}
	return s.userRepo.Update(user)
}

// List 分页查询审核列表
func (s *AuditService) List(auditType, status string, page, pageSize int) (*AuditListResult, error) {
	p := common.Pagination{Page: page, PageSize: pageSize}
	p.DefaultPagination()

	total, err := s.auditRepo.CountAudits(auditType, status)
	if err != nil {
		return nil, err
	}

	items, err := s.auditRepo.ListAudits(auditType, status, p.Offset(), p.PageSize)
	if err != nil {
		return nil, err
	}
	if items == nil {
		items = []model.AuditSubmission{}
	}

	return &AuditListResult{
		Items: items,
		Total: total,
		Page:  p.Page,
	}, nil
}

// GetPendingTypes 获取用户所有待审核类型（用于个人中心提示）
func (s *AuditService) GetPendingTypes(userID uint) ([]string, error) {
	submissions, err := s.auditRepo.FindPendingByUserID(userID)
	if err != nil {
		return nil, err
	}
	types := make([]string, 0, len(submissions))
	for _, sub := range submissions {
		types = append(types, sub.AuditType)
	}
	return types, nil
}

// typeDefault 获取某审核类型在 config.yaml 中的默认开关值
func (s *AuditService) typeDefault(auditType string) bool {
	switch auditType {
	case model.AuditTypeUsername:
		return s.defaultCfg.UsernameAudit
	case model.AuditTypeAvatar:
		return s.defaultCfg.AvatarAudit
	case model.AuditTypeBio:
		return s.defaultCfg.BioAudit
	}
	return true
}

// AuditListResult 审核列表查询结果
type AuditListResult struct {
	Items []model.AuditSubmission `json:"items"`
	Total int64                   `json:"total"`
	Page  int                     `json:"page"`
}
