import uuid
from collections.abc import Mapping
from dataclasses import dataclass
from typing import Any, override

from ai.backend.common.data.permission.types import EntityType, ScopeType
from ai.backend.common.types import (
    AccessKey,
    KernelId,
    QuotaScopeID,
    VFolderUsageMode,
)
from ai.backend.manager.actions.action import BaseAction
from ai.backend.manager.actions.action.scope import BaseScopeAction, BaseScopeActionResult
from ai.backend.manager.actions.action.single_entity import (
    BaseSingleEntityAction,
    BaseSingleEntityActionResult,
)
from ai.backend.manager.actions.action.types import FieldData
from ai.backend.manager.actions.types import ActionOperationType
from ai.backend.manager.data.vfolder.types import VFolderData
from ai.backend.manager.models.user import UserRole
from ai.backend.manager.models.vfolder import (
    VFolderOperationStatus,
    VFolderOwnershipType,
    VFolderPermission,
    VFolderRow,
)
from ai.backend.manager.repositories.base.rbac.entity_purger import RBACEntityPurger
from ai.backend.manager.repositories.base.updater import Updater
from ai.backend.manager.services.vfolder.types import (
    VFolderBaseInfo,
    VFolderOwnershipInfo,
    VFolderUsageInfo,
)


class VFolderAction(BaseAction):
    @override
    @classmethod
    def entity_type(cls) -> EntityType:
        return EntityType.VFOLDER


class VFolderFileAction(VFolderAction):
    @override
    @classmethod
    def entity_type(cls) -> EntityType:
        return EntityType.VFOLDER_FILE


class VFolderDirectoryAction(VFolderAction):
    @override
    @classmethod
    def entity_type(cls) -> EntityType:
        return EntityType.VFOLDER_DIRECTORY


class VFolderScopeAction(BaseScopeAction):
    @override
    @classmethod
    def entity_type(cls) -> EntityType:
        return EntityType.VFOLDER


class VFolderScopeActionResult(BaseScopeActionResult):
    pass


class VFolderSingleEntityAction(BaseSingleEntityAction):
    @override
    @classmethod
    def entity_type(cls) -> EntityType:
        return EntityType.VFOLDER

    @override
    def field_data(self) -> FieldData | None:
        return None


class VFolderSingleEntityActionResult(BaseSingleEntityActionResult):
    pass


@dataclass
class CreateVFolderAction(VFolderScopeAction):
    name: str

    keypair_resource_policy: Mapping[str, Any]
    domain_name: str
    group_id_or_name: str | uuid.UUID | None
    folder_host: str | None
    unmanaged_path: str | None
    mount_permission: VFolderPermission
    usage_mode: VFolderUsageMode
    cloneable: bool

    _scope_id: str
    _scope_type: ScopeType

    # User identifier
    # TODO: Distinguish between creator and owner
    user_uuid: uuid.UUID
    user_role: UserRole
    creator_email: str

    @override
    def entity_id(self) -> str | None:
        return None

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.CREATE

    @override
    def scope_type(self) -> ScopeType:
        return self._scope_type

    @override
    def scope_id(self) -> str:
        return self._scope_id


@dataclass
class CreateVFolderActionResult(VFolderScopeActionResult):
    id: uuid.UUID
    name: str
    quota_scope_id: QuotaScopeID
    host: str
    unmanaged_path: str | None
    mount_permission: VFolderPermission
    usage_mode: VFolderUsageMode
    creator_email: str
    ownership_type: VFolderOwnershipType
    user_uuid: uuid.UUID | None
    group_uuid: uuid.UUID | None
    cloneable: bool
    status: VFolderOperationStatus

    @override
    def entity_id(self) -> str | None:
        return str(self.id)

    @override
    def scope_type(self) -> ScopeType:
        return ScopeType(self.quota_scope_id.scope_type.value)

    @override
    def scope_id(self) -> str:
        return str(self.quota_scope_id.scope_id)


@dataclass
class UpdateVFolderAttributeAction(VFolderSingleEntityAction):
    user_uuid: uuid.UUID
    vfolder_uuid: uuid.UUID
    updater: Updater[VFolderRow]

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.UPDATE

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class UpdateVFolderAttributeActionResult(VFolderSingleEntityActionResult):
    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class GetVFolderAction(VFolderSingleEntityAction):
    user_uuid: uuid.UUID
    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.GET

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class GetVFolderActionResult(VFolderSingleEntityActionResult):
    user_uuid: uuid.UUID
    base_info: VFolderBaseInfo
    ownership_info: VFolderOwnershipInfo
    usage_info: VFolderUsageInfo

    @override
    def entity_id(self) -> str | None:
        return str(self.user_uuid)

    @override
    def target_entity_id(self) -> str:
        return str(self.base_info.id)


@dataclass
class ListVFolderAction(VFolderScopeAction):
    user_uuid: uuid.UUID
    _scope_type: ScopeType
    _scope_id: str

    @override
    def entity_id(self) -> str | None:
        return str(self.user_uuid)

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.SEARCH

    @override
    def scope_type(self) -> ScopeType:
        return self._scope_type

    @override
    def scope_id(self) -> str:
        return self._scope_id


@dataclass
class ListVFolderActionResult(VFolderScopeActionResult):
    user_uuid: uuid.UUID
    vfolders: list[tuple[VFolderBaseInfo, VFolderOwnershipInfo]]
    _scope_type: ScopeType
    _scope_id: str

    @override
    def entity_id(self) -> str | None:
        return str(self.user_uuid)

    @override
    def scope_type(self) -> ScopeType:
        return self._scope_type

    @override
    def scope_id(self) -> str:
        return str(self._scope_id)


@dataclass
class MoveToTrashVFolderAction(VFolderSingleEntityAction):
    user_uuid: uuid.UUID
    keypair_resource_policy: Mapping[str, Any]

    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.DELETE

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class MoveToTrashVFolderActionResult(VFolderSingleEntityActionResult):
    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class RestoreVFolderFromTrashAction(VFolderSingleEntityAction):
    user_uuid: uuid.UUID

    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.UPDATE

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class RestoreVFolderFromTrashActionResult(VFolderSingleEntityActionResult):
    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class DeleteForeverVFolderAction(VFolderSingleEntityAction):
    user_uuid: uuid.UUID

    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.PURGE

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class DeleteForeverVFolderActionResult(VFolderSingleEntityActionResult):
    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class PurgeVFolderAction(VFolderSingleEntityAction):
    purger: RBACEntityPurger[VFolderRow]

    @override
    def entity_id(self) -> str | None:
        return str(self.purger.pk_value)

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.PURGE

    @override
    def target_entity_id(self) -> str:
        return str(self.purger.pk_value)


@dataclass
class PurgeVFolderActionResult(VFolderSingleEntityActionResult):
    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class ForceDeleteVFolderAction(VFolderSingleEntityAction):
    """
    This action transits the state of vfolder from ready to delete-forever directly.
    """

    user_uuid: uuid.UUID

    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.PURGE

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class ForceDeleteVFolderActionResult(VFolderSingleEntityActionResult):
    vfolder_uuid: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class CloneVFolderAction(VFolderSingleEntityAction):
    requester_user_uuid: uuid.UUID

    source_vfolder_uuid: uuid.UUID
    target_name: str
    target_host: str | None
    cloneable: bool
    usage_mode: VFolderUsageMode
    mount_permission: VFolderPermission

    @override
    def entity_id(self) -> str | None:
        return str(self.source_vfolder_uuid)

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.CREATE

    @override
    def target_entity_id(self) -> str:
        return str(self.source_vfolder_uuid)


@dataclass
class CloneVFolderActionResult(VFolderSingleEntityActionResult):
    vfolder_uuid: uuid.UUID

    target_vfolder_id: uuid.UUID
    target_vfolder_name: str
    target_vfolder_host: str
    usage_mode: VFolderUsageMode
    mount_permission: VFolderPermission
    creator_email: str
    ownership_type: VFolderOwnershipType
    owner_user_uuid: uuid.UUID | None
    owner_group_uuid: uuid.UUID | None
    cloneable: bool
    bgtask_id: uuid.UUID

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_uuid)

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_uuid)


@dataclass
class GetTaskLogsAction(VFolderSingleEntityAction):
    user_id: uuid.UUID
    domain_name: str
    user_role: UserRole
    kernel_id: KernelId
    owner_access_key: AccessKey

    # TODO: Remove this.
    request: Any

    @override
    def entity_id(self) -> str | None:
        return None

    @override
    @classmethod
    def operation_type(cls) -> ActionOperationType:
        return ActionOperationType.GET

    @override
    def target_entity_id(self) -> str:
        return str(self.kernel_id)


@dataclass
class GetTaskLogsActionResult(VFolderSingleEntityActionResult):
    # TODO: Add proper type
    response: Any
    vfolder_data: VFolderData

    @override
    def entity_id(self) -> str | None:
        return str(self.vfolder_data.id)

    @override
    def target_entity_id(self) -> str:
        return str(self.vfolder_data.id)
