package usecase

import (
	"backend/pkg/permission/domain/permission"
	"backend/pkg/permission/domain/repository"
	"backend/pkg/permission/domain/usecase"
	"context"

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

type RolePermissionUseCaseParam struct {
	PermRepo     repository.PermissionRepository
	RolePermRepo repository.RolePermissionRepository
	RoleRepo     repository.RoleRepository
	UserRoleRepo repository.UserRoleRepository
	PermUseCase  usecase.PermissionUseCase
	AdminRoleUID string // 管理員角色 UID
}

type rolePermissionUseCase struct {
	RolePermissionUseCaseParam
}

// NewRolePermissionUseCase 建立角色權限 UseCase
func NewRolePermissionUseCase(param RolePermissionUseCaseParam) usecase.RolePermissionUseCase {
	return &rolePermissionUseCase{
		RolePermissionUseCaseParam: param,
	}
}

func (uc *rolePermissionUseCase) GetByRoleUID(ctx context.Context, roleUID string) (permission.Permissions, error) {
	// 檢查是否為管理員
	if uc.AdminRoleUID != "" && roleUID == uc.AdminRoleUID {
		return uc.getAllPermissions(ctx)
	}

	// 取得角色
	role, err := uc.RoleRepo.GetByUID(ctx, roleUID)
	if err != nil {
		return nil, err
	}

	// 取得角色權限關聯
	roleID := ConvertOIDToInt64(role.ID)
	rolePerms, err := uc.RolePermRepo.GetByRoleID(ctx, roleID)
	if err != nil {
		return nil, err
	}

	if len(rolePerms) == 0 {
		return make(permission.Permissions), nil
	}

	// 取得權限樹並建立權限集合
	perms, err := uc.PermRepo.ListActive(ctx)
	if err != nil {
		return nil, err
	}

	tree := NewPermissionTree(perms)

	// 取得權限 ObjectID 列表
	permOIDs := make([]bson.ObjectID, len(rolePerms))
	for i, rp := range rolePerms {
		permOIDs[i] = rp.PermissionID
	}

	// 建立權限集合 (包含父權限)
	permissions := tree.BuildPermissionsFromIDs(permOIDs)

	return permissions, nil
}

func (uc *rolePermissionUseCase) GetByUserUID(ctx context.Context, userUID string) (*usecase.UserPermissionResponse, error) {
	// 取得使用者角色
	userRole, err := uc.UserRoleRepo.Get(ctx, userUID)
	if err != nil {
		return nil, err
	}

	// 取得角色
	role, err := uc.RoleRepo.GetByUID(ctx, userRole.RoleID)
	if err != nil {
		return nil, err
	}

	// 取得角色權限
	permissions, err := uc.GetByRoleUID(ctx, userRole.RoleID)
	if err != nil {
		return nil, err
	}

	resp := &usecase.UserPermissionResponse{
		UserUID:     userUID,
		RoleUID:     role.UID,
		RoleName:    role.Name,
		Permissions: permissions,
	}

	return resp, nil
}

func (uc *rolePermissionUseCase) UpdateRolePermissions(ctx context.Context, roleUID string, permissions permission.Permissions) error {
	// 取得角色
	role, err := uc.RoleRepo.GetByUID(ctx, roleUID)
	if err != nil {
		return err
	}

	// 展開權限 (包含父權限)
	var expandedPerms permission.Permissions
	if uc.PermUseCase != nil {
		expandedPerms, err = uc.PermUseCase.ExpandPermissions(ctx, permissions)
		if err != nil {
			return err
		}
	} else {
		expandedPerms = permissions
	}

	// 取得權限樹並轉換為 ID
	perms, err := uc.PermRepo.ListActive(ctx)
	if err != nil {
		return err
	}

	tree := NewPermissionTree(perms)
	permOIDs, err := tree.GetPermissionIDs(expandedPerms)
	if err != nil {
		return err
	}

	// 轉換 ObjectID 為 int64
	permIDs := make([]int64, len(permOIDs))
	for i, oid := range permOIDs {
		permIDs[i] = ConvertOIDToInt64(oid)
	}

	// 更新角色權限
	roleID := ConvertOIDToInt64(role.ID)
	if err := uc.RolePermRepo.Update(ctx, roleID, permIDs); err != nil {
		return err
	}

	return nil
}

func (uc *rolePermissionUseCase) CheckPermission(ctx context.Context, roleUID, path, method string) (*usecase.PermissionCheckResponse, error) {
	// 檢查是否為管理員
	if uc.AdminRoleUID != "" && roleUID == uc.AdminRoleUID {
		return &usecase.PermissionCheckResponse{
			Allowed:   true,
			PlainCode: true,
		}, nil
	}

	// 取得角色權限
	permissions, err := uc.GetByRoleUID(ctx, roleUID)
	if err != nil {
		return nil, err
	}

	// 取得 API 權限
	perm, err := uc.PermRepo.FindByHTTP(ctx, path, method)
	if err != nil {
		// 如果找不到對應的權限定義，預設拒絕
		return &usecase.PermissionCheckResponse{
			Allowed: false,
		}, nil
	}

	// 檢查是否有權限
	allowed := permissions.HasPermission(perm.Name)

	resp := &usecase.PermissionCheckResponse{
		Allowed:        allowed,
		PermissionName: perm.Name,
		PlainCode:      false,
	}

	// 檢查是否有 plain_code 權限 (特殊邏輯)
	if allowed && method == "GET" {
		plainCodePermName := perm.Name + ".plain_code"
		resp.PlainCode = permissions.HasPermission(plainCodePermName)
	}

	return resp, nil
}

// getAllPermissions 取得所有權限 (管理員用)
func (uc *rolePermissionUseCase) getAllPermissions(ctx context.Context) (permission.Permissions, error) {
	perms, err := uc.PermRepo.ListActive(ctx)
	if err != nil {
		return nil, err
	}

	permissions := make(permission.Permissions)
	for _, perm := range perms {
		permissions.AddPermission(perm.Name)
	}

	return permissions, nil
}
