package service

import (
	"context"
	"errors"

	"gorm.io/gorm"

	"github.com/user-management-system/internal/domain"
	"github.com/user-management-system/internal/repository"
)

// RoleService 角色服务
type RoleService struct {
	roleRepo           *repository.RoleRepository
	rolePermissionRepo *repository.RolePermissionRepository
}

// NewRoleService 创建角色服务
func NewRoleService(
	roleRepo *repository.RoleRepository,
	rolePermissionRepo *repository.RolePermissionRepository,
) *RoleService {
	return &RoleService{
		roleRepo:           roleRepo,
		rolePermissionRepo: rolePermissionRepo,
	}
}

// CreateRoleRequest 创建角色请求
type CreateRoleRequest struct {
	Name        string `json:"name" binding:"required"`
	Code        string `json:"code" binding:"required"`
	Description string `json:"description"`
	ParentID    *int64 `json:"parent_id"`
}

// UpdateRoleRequest 更新角色请求
type UpdateRoleRequest struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	ParentID    *int64 `json:"parent_id"`
}

// CreateRole 创建角色
func (s *RoleService) CreateRole(ctx context.Context, req *CreateRoleRequest) (*domain.Role, error) {
	// 检查角色代码是否已存在
	exists, err := s.roleRepo.ExistsByCode(ctx, req.Code)
	if err != nil {
		return nil, err
	}
	if exists {
		return nil, errors.New("角色代码已存在")
	}

	// 设置角色层级
	level := 1
	if req.ParentID != nil {
		parentRole, err := s.roleRepo.GetByID(ctx, *req.ParentID)
		if err != nil {
			return nil, errors.New("父角色不存在")
		}
		level = parentRole.Level + 1
	}

	// 创建角色
	role := &domain.Role{
		Name:        req.Name,
		Code:        req.Code,
		Description: req.Description,
		ParentID:    req.ParentID,
		Level:       level,
		Status:      domain.RoleStatusEnabled,
	}

	if err := s.roleRepo.Create(ctx, role); err != nil {
		return nil, err
	}

	return role, nil
}

const maxRoleDepth = 5 // 角色继承深度上限，可配置

// UpdateRole 更新角色
func (s *RoleService) UpdateRole(ctx context.Context, roleID int64, req *UpdateRoleRequest) (*domain.Role, error) {
	role, err := s.roleRepo.GetByID(ctx, roleID)
	if err != nil {
		return nil, errors.New("角色不存在")
	}

	// 检查父角色是否存在
	if req.ParentID != nil {
		if *req.ParentID == roleID {
			return nil, errors.New("不能将角色设置为自己的父角色")
		}
		// 检测循环继承：检查新父角色的祖先链是否包含当前角色
		if err := s.checkCircularInheritance(ctx, roleID, *req.ParentID); err != nil {
			return nil, err
		}
		// 检测继承深度：计算新父角色的深度 + 1
		if err := s.checkInheritanceDepth(ctx, *req.ParentID, maxRoleDepth-1); err != nil {
			return nil, err
		}
		role.ParentID = req.ParentID
	}

	// 更新字段
	if req.Name != "" {
		role.Name = req.Name
	}
	if req.Description != "" {
		role.Description = req.Description
	}

	if err := s.roleRepo.Update(ctx, role); err != nil {
		return nil, err
	}

	return role, nil
}

// checkCircularInheritance 检测循环继承
// 如果将 childID 的父角色设为 parentID，检查 parentID 的祖先链是否包含 childID
func (s *RoleService) checkCircularInheritance(ctx context.Context, childID, parentID int64) error {
	ancestorIDs, err := s.roleRepo.GetAncestorIDs(ctx, parentID)
	if err != nil {
		return err
	}
	for _, ancestorID := range ancestorIDs {
		if ancestorID == childID {
			return errors.New("检测到循环继承，操作被拒绝")
		}
	}
	return nil
}

// checkInheritanceDepth 检测继承深度是否超限
func (s *RoleService) checkInheritanceDepth(ctx context.Context, roleID int64, maxDepth int) error {
	if maxDepth <= 0 {
		return errors.New("继承深度超限，最大支持5层")
	}

	depth := 0
	currentID := roleID
	for {
		role, err := s.roleRepo.GetByID(ctx, currentID)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				break
			}
			return err
		}
		if role.ParentID == nil {
			break
		}
		depth++
		if depth > maxDepth {
			return errors.New("继承深度超限，最大支持5层")
		}
		currentID = *role.ParentID
	}
	return nil
}

// DeleteRole 删除角色
func (s *RoleService) DeleteRole(ctx context.Context, roleID int64) error {
	role, err := s.roleRepo.GetByID(ctx, roleID)
	if err != nil {
		return errors.New("角色不存在")
	}

	// 系统角色不能删除
	if role.IsSystem {
		return errors.New("系统角色不能删除")
	}

	// 检查是否有子角色
	children, err := s.roleRepo.ListByParentID(ctx, roleID)
	if err == nil && len(children) > 0 {
		return errors.New("存在子角色，无法删除")
	}

	// 级联删除角色及其权限关联（在事务中执行）
	return s.roleRepo.DeleteCascade(ctx, roleID)
}

// GetRole 获取角色信息
func (s *RoleService) GetRole(ctx context.Context, roleID int64) (*domain.Role, error) {
	return s.roleRepo.GetByID(ctx, roleID)
}

// ListRoles 获取角色列表
type ListRoleRequest struct {
	Page     int    `json:"page"`
	PageSize int    `json:"page_size"`
	Status   int    `json:"status"`
	Keyword  string `json:"keyword"`
}

func (s *RoleService) ListRoles(ctx context.Context, req *ListRoleRequest) ([]*domain.Role, int64, error) {
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 20
	}
	offset := (req.Page - 1) * req.PageSize

	if req.Keyword != "" {
		return s.roleRepo.Search(ctx, req.Keyword, offset, req.PageSize)
	}

	// Status > 0 表示按状态过滤；0 表示不过滤（查全部）
	if req.Status > 0 {
		return s.roleRepo.ListByStatus(ctx, domain.RoleStatus(req.Status), offset, req.PageSize)
	}

	return s.roleRepo.List(ctx, offset, req.PageSize)
}

// UpdateRoleStatus 更新角色状态
func (s *RoleService) UpdateRoleStatus(ctx context.Context, roleID int64, status domain.RoleStatus) error {
	role, err := s.roleRepo.GetByID(ctx, roleID)
	if err != nil {
		return errors.New("角色不存在")
	}

	// 系统角色不能禁用
	if role.IsSystem && status == domain.RoleStatusDisabled {
		return errors.New("系统角色不能禁用")
	}

	return s.roleRepo.UpdateStatus(ctx, roleID, status)
}

// GetRolePermissions 获取角色权限（包含继承的父角色权限）
func (s *RoleService) GetRolePermissions(ctx context.Context, roleID int64) ([]*domain.Permission, error) {
	// 收集所有角色ID（包括当前角色和所有父角色）
	allRoleIDs := []int64{roleID}
	ancestorIDs, err := s.roleRepo.GetAncestorIDs(ctx, roleID)
	if err != nil {
		return nil, err
	}
	allRoleIDs = append(allRoleIDs, ancestorIDs...)

	// 批量获取所有角色的权限ID
	permissionIDs, err := s.rolePermissionRepo.GetPermissionIDsByRoleIDs(ctx, allRoleIDs)
	if err != nil {
		return nil, err
	}

	// 批量获取权限详情
	permissions, err := s.rolePermissionRepo.GetPermissionsByIDs(ctx, permissionIDs)
	if err != nil {
		return nil, err
	}

	return permissions, nil
}

// AssignPermissions 分配权限
func (s *RoleService) AssignPermissions(ctx context.Context, roleID int64, permissionIDs []int64) error {
	// 删除原有权限
	if err := s.rolePermissionRepo.DeleteByRoleID(ctx, roleID); err != nil {
		return err
	}

	// 创建新权限关联
	var rolePermissions []*domain.RolePermission
	for _, permissionID := range permissionIDs {
		rolePermissions = append(rolePermissions, &domain.RolePermission{
			RoleID:       roleID,
			PermissionID: permissionID,
		})
	}

	return s.rolePermissionRepo.BatchCreate(ctx, rolePermissions)
}
