// Package permission 提供权限管理的业务逻辑服务
// 包含权限创建、查询、更新、删除、权限检查等功能
package permission

import (
	"context"
	"encoding/json"
	"regexp"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/internal/store"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

// permCodeRegex 权限编码格式验证正则（module:action）
var permCodeRegex = regexp.MustCompile(`^[a-z][a-z0-9_]*:[a-z][a-z0-9_]*$`)

type AccountServiceInterface interface {
	GetRoleIDsForAccount(ctx context.Context, accountID uint) ([]uint, error)
}

// Service 权限业务服务
type Service struct {
	permissionStore  *postgres.PermissionStore
	accountRoleStore *postgres.AccountRoleStore
	rolePermStore    *postgres.RolePermissionStore
	accountService   AccountServiceInterface
	redisClient      *redis.Client
}

// New 创建权限服务
func New(
	permissionStore *postgres.PermissionStore,
	accountRoleStore *postgres.AccountRoleStore,
	rolePermStore *postgres.RolePermissionStore,
	accountService AccountServiceInterface,
	redisClient *redis.Client,
) *Service {
	return &Service{
		permissionStore:  permissionStore,
		accountRoleStore: accountRoleStore,
		rolePermStore:    rolePermStore,
		accountService:   accountService,
		redisClient:      redisClient,
	}
}

// Create 创建权限
func (s *Service) Create(ctx context.Context, req *dto.CreatePermissionRequest) (*model.Permission, error) {
	// 获取当前用户 ID
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	// 验证权限编码格式
	if !permCodeRegex.MatchString(req.PermCode) {
		return nil, errors.New(errors.CodeInvalidPermCode, "权限编码格式不正确（应为 module:action 格式）")
	}

	// 检查权限编码唯一性
	existing, err := s.permissionStore.GetByCode(ctx, req.PermCode)
	if err == nil && existing != nil {
		return nil, errors.New(errors.CodePermCodeExists, "权限编码已存在")
	}

	// 验证 parent_id 存在（如果提供）
	if req.ParentID != nil {
		parent, err := s.permissionStore.GetByID(ctx, *req.ParentID)
		if err != nil || parent == nil {
			return nil, errors.New(errors.CodeNotFound, "上级权限不存在")
		}
	}

	// 创建权限
	permission := &model.Permission{
		PermName: req.PermName,
		PermCode: req.PermCode,
		PermType: req.PermType,
		Platform: req.Platform,
		URL:      req.URL,
		ParentID: req.ParentID,
		Sort:     req.Sort,
		Status:   constants.StatusEnabled,
	}

	// 如果未指定 platform，默认为 all
	if permission.Platform == "" {
		permission.Platform = constants.PlatformAll
	}

	if err := s.permissionStore.Create(ctx, permission); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "创建权限失败")
	}

	return permission, nil
}

// Get 获取权限
func (s *Service) Get(ctx context.Context, id uint) (*model.Permission, error) {
	permission, err := s.permissionStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodePermissionNotFound, "权限不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取权限失败")
	}
	return permission, nil
}

// Update 更新权限
func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdatePermissionRequest) (*model.Permission, error) {
	// 获取当前用户 ID
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	// 获取现有权限
	permission, err := s.permissionStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodePermissionNotFound, "权限不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取权限失败")
	}

	// 更新字段
	if req.PermName != nil {
		permission.PermName = *req.PermName
	}
	if req.PermCode != nil {
		// 验证权限编码格式
		if !permCodeRegex.MatchString(*req.PermCode) {
			return nil, errors.New(errors.CodeInvalidPermCode, "权限编码格式不正确（应为 module:action 格式）")
		}
		// 检查新权限编码唯一性
		existing, err := s.permissionStore.GetByCode(ctx, *req.PermCode)
		if err == nil && existing != nil && existing.ID != id {
			return nil, errors.New(errors.CodePermCodeExists, "权限编码已存在")
		}
		permission.PermCode = *req.PermCode
	}
	if req.Platform != nil {
		permission.Platform = *req.Platform
	}
	if req.URL != nil {
		permission.URL = *req.URL
	}
	if req.ParentID != nil {
		// 验证 parent_id 存在
		parent, err := s.permissionStore.GetByID(ctx, *req.ParentID)
		if err != nil || parent == nil {
			return nil, errors.New(errors.CodeNotFound, "上级权限不存在")
		}
		permission.ParentID = req.ParentID
	}
	if req.Sort != nil {
		permission.Sort = *req.Sort
	}
	if req.Status != nil {
		permission.Status = *req.Status
	}

	permission.Updater = currentUserID

	if err := s.permissionStore.Update(ctx, permission); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "更新权限失败")
	}

	return permission, nil
}

// Delete 软删除权限
func (s *Service) Delete(ctx context.Context, id uint) error {
	// 检查权限存在
	_, err := s.permissionStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodePermissionNotFound, "权限不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取权限失败")
	}

	if err := s.permissionStore.Delete(ctx, id); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "删除权限失败")
	}

	return nil
}

// List 查询权限列表
func (s *Service) List(ctx context.Context, req *dto.PermissionListRequest) ([]*model.Permission, int64, error) {
	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "sort ASC, id ASC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := make(map[string]interface{})
	if req.PermName != "" {
		filters["perm_name"] = req.PermName
	}
	if req.PermCode != "" {
		filters["perm_code"] = req.PermCode
	}
	if req.PermType != nil {
		filters["perm_type"] = *req.PermType
	}
	if req.Platform != "" {
		filters["platform"] = req.Platform
	}
	if req.AvailableForRoleType != nil {
		filters["available_for_role_type"] = *req.AvailableForRoleType
	}
	if req.ParentID != nil {
		filters["parent_id"] = *req.ParentID
	}
	if req.Status != nil {
		filters["status"] = *req.Status
	}

	return s.permissionStore.List(ctx, opts, filters)
}

// GetTree 获取权限树
func (s *Service) GetTree(ctx context.Context, req *dto.PermissionTreeRequest) ([]*dto.PermissionTreeNode, error) {
	permissions, err := s.permissionStore.GetAll(ctx, req.AvailableForRoleType, req.Status)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取权限列表失败")
	}

	return buildPermissionTree(permissions), nil
}

// buildPermissionTree 构建权限树
func buildPermissionTree(permissions []*model.Permission) []*dto.PermissionTreeNode {
	nodeMap := make(map[uint]*dto.PermissionTreeNode)
	for _, p := range permissions {
		nodeMap[p.ID] = &dto.PermissionTreeNode{
			ID:                    p.ID,
			PermName:              p.PermName,
			PermCode:              p.PermCode,
			PermType:              p.PermType,
			Platform:              p.Platform,
			AvailableForRoleTypes: p.AvailableForRoleTypes,
			URL:                   p.URL,
			Sort:                  p.Sort,
			Status:                p.Status,
			Children:              make([]*dto.PermissionTreeNode, 0),
		}
	}

	var roots []*dto.PermissionTreeNode
	for _, p := range permissions {
		node := nodeMap[p.ID]
		if p.ParentID == nil || *p.ParentID == 0 {
			roots = append(roots, node)
		} else if parent, ok := nodeMap[*p.ParentID]; ok {
			parent.Children = append(parent.Children, node)
		} else {
			roots = append(roots, node)
		}
	}

	return roots
}

// permissionCacheItem 权限缓存项
type permissionCacheItem struct {
	PermCode string `json:"perm_code"`
	Platform string `json:"platform"`
}

// CheckPermission 检查用户是否拥有指定权限（实现 PermissionChecker 接口）
// userID: 用户ID
// permCode: 权限编码
// platform: 端口类型 (all/web/h5)
func (s *Service) CheckPermission(ctx context.Context, userID uint, permCode string, platform string) (bool, error) {
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType == constants.UserTypeSuperAdmin {
		return true, nil
	}

	cacheKey := constants.RedisUserPermissionsKey(userID)

	cachedData, err := s.redisClient.Get(ctx, cacheKey).Result()
	if err == nil && cachedData != "" {
		var permissions []permissionCacheItem
		if err := json.Unmarshal([]byte(cachedData), &permissions); err == nil {
			return s.matchPermission(permissions, permCode, platform), nil
		}
	}

	roleIDs, err := s.accountService.GetRoleIDsForAccount(ctx, userID)
	if err != nil {
		return false, errors.Wrap(errors.CodeInternalError, err, "查询用户角色失败")
	}
	if len(roleIDs) == 0 {
		return false, nil
	}

	permIDs, err := s.rolePermStore.GetPermIDsByRoleIDs(ctx, roleIDs)
	if err != nil {
		return false, errors.Wrap(errors.CodeInternalError, err, "查询角色权限失败")
	}
	if len(permIDs) == 0 {
		return false, nil
	}

	permissions, err := s.permissionStore.GetByIDs(ctx, permIDs)
	if err != nil {
		return false, errors.Wrap(errors.CodeInternalError, err, "查询权限详情失败")
	}

	cacheItems := make([]permissionCacheItem, 0, len(permissions))
	for _, perm := range permissions {
		cacheItems = append(cacheItems, permissionCacheItem{
			PermCode: perm.PermCode,
			Platform: perm.Platform,
		})
	}

	if cacheData, err := json.Marshal(cacheItems); err == nil {
		s.redisClient.Set(ctx, cacheKey, cacheData, 30*time.Minute)
	}

	return s.matchPermission(cacheItems, permCode, platform), nil
}

func (s *Service) matchPermission(permissions []permissionCacheItem, permCode string, platform string) bool {
	for _, perm := range permissions {
		if perm.PermCode == permCode {
			if perm.Platform == constants.PlatformAll || perm.Platform == platform {
				return true
			}
		}
	}
	return false
}
