package usecase

import (
	"backend/pkg/permission/domain/entity"
	"backend/pkg/permission/domain/permission"
	"backend/pkg/permission/domain/repository"
	"backend/pkg/permission/domain/usecase"
	"context"
	"fmt"
	"sync"
	"time"

	"go.mongodb.org/mongo-driver/v2/bson"
)

type PermissionUseCaseParam struct {
	PermRepo     repository.PermissionRepository
	RolePermRepo repository.RolePermissionRepository
	RoleRepo     repository.RoleRepository
	UserRoleRepo repository.UserRoleRepository
}

type permissionUseCase struct {
	PermissionUseCaseParam

	// 權限樹快取 (in-memory)
	treeMutex sync.RWMutex
	tree      *PermissionTree
}

// NewPermissionUseCase 建立權限 UseCase
func NewPermissionUseCase(param PermissionUseCaseParam) usecase.PermissionUseCase {
	return &permissionUseCase{
		PermissionUseCaseParam: param,
	}
}

func (uc *permissionUseCase) GetAll(ctx context.Context) ([]*usecase.PermissionResponse, error) {
	perms, err := uc.PermRepo.ListActive(ctx)
	if err != nil {
		return nil, err
	}

	result := make([]*usecase.PermissionResponse, 0, len(perms))
	for _, perm := range perms {
		result = append(result, uc.toResponse(perm))
	}

	return result, nil
}

func (uc *permissionUseCase) GetTree(ctx context.Context) (*usecase.PermissionTreeNode, error) {
	tree, err := uc.getOrBuildTree(ctx)
	if err != nil {
		return nil, err
	}

	roots := tree.ToTree()
	if len(roots) == 0 {
		return nil, fmt.Errorf("no permissions found")
	}

	// 如果有多個根節點，包裝成一個虛擬根節點
	if len(roots) == 1 {
		return roots[0], nil
	}

	return &usecase.PermissionTreeNode{
		PermissionResponse: &usecase.PermissionResponse{
			Name: "root",
		},
		Children: roots,
	}, nil
}

func (uc *permissionUseCase) GetByHTTP(ctx context.Context, path, method string) (*usecase.PermissionResponse, error) {
	perm, err := uc.PermRepo.FindByHTTP(ctx, path, method)
	if err != nil {
		return nil, err
	}

	return uc.toResponse(perm), nil
}

func (uc *permissionUseCase) ExpandPermissions(ctx context.Context, permissions permission.Permissions) (permission.Permissions, error) {
	tree, err := uc.getOrBuildTree(ctx)
	if err != nil {
		return nil, err
	}

	return tree.ExpandPermissions(permissions)
}

func (uc *permissionUseCase) GetUsersByPermission(ctx context.Context, permissionNames []string) ([]string, error) {
	// 取得權限
	perms, err := uc.PermRepo.GetByNames(ctx, permissionNames)
	if err != nil {
		return nil, err
	}

	if len(perms) == 0 {
		return []string{}, nil
	}

	// 取得權限 ID
	permIDs := make([]int64, len(perms))
	for i, perm := range perms {
		// Convert ObjectID to int64 (timestamp-based)
		permIDs[i] = perm.ID.Timestamp().Unix()
	}

	// 取得擁有這些權限的角色
	rolePerms, err := uc.RolePermRepo.GetByPermissionIDs(ctx, permIDs)
	if err != nil {
		return nil, err
	}

	// 取得角色 ID
	roleIDMap := make(map[int64]bool)
	for _, rp := range rolePerms {
		// Convert ObjectID to int64
		roleID := rp.RoleID.Timestamp().Unix()
		roleIDMap[roleID] = true
	}

	roleIDs := make([]int64, 0, len(roleIDMap))
	for roleID := range roleIDMap {
		roleIDs = append(roleIDs, roleID)
	}

	// 批量取得角色
	roles, err := uc.RoleRepo.List(ctx, repository.RoleFilter{})
	if err != nil {
		return nil, err
	}

	roleUIDMap := make(map[int64]string)
	for _, role := range roles {
		roleID := role.ID.Timestamp().Unix()
		if roleIDMap[roleID] {
			roleUIDMap[roleID] = role.UID
		}
	}

	// 取得使用這些角色的使用者
	userUIDs := make([]string, 0)
	for _, roleUID := range roleUIDMap {
		userRoles, err := uc.UserRoleRepo.GetByRoleID(ctx, roleUID)
		if err != nil {
			continue
		}

		for _, ur := range userRoles {
			userUIDs = append(userUIDs, ur.UID)
		}
	}

	return userUIDs, nil
}

// getOrBuildTree 取得或建立權限樹 (帶快取)
func (uc *permissionUseCase) getOrBuildTree(ctx context.Context) (*PermissionTree, error) {
	// 先檢查 in-memory 快取
	uc.treeMutex.RLock()
	if uc.tree != nil {
		uc.treeMutex.RUnlock()
		return uc.tree, nil
	}
	uc.treeMutex.RUnlock()

	// 從資料庫建立
	perms, err := uc.PermRepo.ListActive(ctx)
	if err != nil {
		return nil, err
	}

	tree := NewPermissionTree(perms)

	// 檢測循環依賴
	if err := tree.DetectCircularDependency(); err != nil {
		return nil, err
	}

	// 更新快取
	uc.treeMutex.Lock()
	uc.tree = tree
	uc.treeMutex.Unlock()

	return tree, nil
}

// InvalidateTreeCache 清除權限樹快取
func (uc *permissionUseCase) InvalidateTreeCache(ctx context.Context) error {
	uc.treeMutex.Lock()
	uc.tree = nil
	uc.treeMutex.Unlock()

	return nil
}

func (uc *permissionUseCase) toResponse(perm *entity.Permission) *usecase.PermissionResponse {
	status := permission.Open
	if !perm.State.IsActive() {
		status = permission.Close
	}

	parentID := ""
	if !perm.ParentID.IsZero() {
		parentID = perm.ParentID.Hex()
	}

	return &usecase.PermissionResponse{
		ID:         perm.ID.Hex(),
		ParentID:   parentID,
		Name:       perm.Name,
		HTTPPath:   perm.HTTPPath,
		HTTPMethod: perm.HTTPMethod,
		Status:     status,
		Type:       perm.Type,
	}
}

// ConvertOIDToInt64 輔助函數：將 ObjectID 轉換為 int64
func ConvertOIDToInt64(oid bson.ObjectID) int64 {
	if oid.IsZero() {
		return 0
	}
	return oid.Timestamp().Unix()
}

// ConvertInt64ToOID 輔助函數：將 int64 轉換為 ObjectID (基於時間戳)
func ConvertInt64ToOID(id int64) bson.ObjectID {
	if id == 0 {
		return bson.ObjectID{}
	}
	return bson.NewObjectIDFromTimestamp(time.Unix(id, 0))
}
