# Standard Library
from enum import Enum

# Third Party
from ninja import NinjaAPI, Schema

# Alliance Auth (Core)
from allianceauth.services.hooks import get_extension_logger

# Alliance Auth (External Libs)
from eve_sde.models import ItemType
from eve_sde.models.types import TypeEffect

from incursions.app_settings import ALWAYS_CARGO_CATEGORIES, EVECATEGORY_DRONE
from incursions.models.waitlist import ApprovedFitting


class SlotEnum(str, Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    RIG = "rig"
    DRONE = "drone"
    CARGO = "cargo"
    OTHER = "other"


class ModuleSchema(Schema):
    name: str
    category: str
    slot: SlotEnum | None = None


class ModuleInfoRequest(Schema):
    ids: list[int]


logger = get_extension_logger(__name__)
api = NinjaAPI()


def setup(api: NinjaAPI) -> None:
    ModulesAPIEndpoints(api)


def module_slot(module: ItemType) -> str:
    """returns the enum for SlotEnum based on its DogmaEffect, some item Category fallbacks and hard coded cargo logic

    Args:
        module (ItemType): SDE ItemType Object

    Returns:
        str: str from SlotEnum
    """

    type_effects = TypeEffect.objects.filter(item_type_id=module.id)

    if type_effects.filter(dogma_effect_id=11).exists():
        return SlotEnum.LOW
    elif type_effects.filter(dogma_effect_id=13).exists():
        return SlotEnum.MEDIUM
    elif type_effects.filter(dogma_effect_id=12).exists():
        return SlotEnum.HIGH
    elif type_effects.filter(dogma_effect_id=2663).exists():
        return SlotEnum.RIG
    elif type_effects.filter(dogma_effect_id=3772).exists():
        return SlotEnum.OTHER  # Ariel SUBSYSTEMS, check how this appears on the frontend?
    if (module.group is not None
            and module.group.category is not None
            and module.group.category.id in ALWAYS_CARGO_CATEGORIES):
        return SlotEnum.CARGO
    elif (module.group is not None
            and module.group.category is not None
            and module.group.category.id == EVECATEGORY_DRONE):
        return SlotEnum.DRONE

    return SlotEnum.OTHER


class ModulesAPIEndpoints:

    tags = ["Modules"]

    def __init__(self, api: NinjaAPI) -> None:

        @api.post("/module/info", response={200: dict[int, ModuleSchema], 403: dict}, tags=self.tags)
        def module_info(request, payload: ModuleInfoRequest):
            if not request.user.has_perm("incursions.basic_waitlist"):
                logger.warning(f"User {request.user} denied access to module info")
                return 403, {"error": "Permission denied"}

            logger.debug(f"Fetching module info for {len(payload.ids)} type IDs")
            types = ItemType.objects.select_related("group__category").filter(id__in=payload.ids)

            response = {
                type.id: ModuleSchema(
                    name=type.name,
                    category=type.group.category.name if type.group and type.group.category else "",
                    slot=module_slot(type)
                ) for type in types
            }
            logger.info(f"Returning module info for {len(response)} items to user {request.user}")
            return response

        @api.get("/module/preload", response={200: dict[int, ModuleSchema], 403: dict}, tags=self.tags)
        def preload(request):
            if not request.user.has_perm("incursions.basic_waitlist"):
                logger.warning(f"User {request.user} denied access to module preload")
                return 403, {"error": "Permission denied"}

            type_ids: list[int] = []
            for fit in ApprovedFitting.objects.only("dna"):
                for x in fit.dna.split(":"):
                    if x:
                        try:
                            type_ids.append(int(x.split(";")[0]))
                        except ValueError:
                            continue

            logger.debug(f"Preloading module info for {len(type_ids)} extracted type IDs")
            types = ItemType.objects.select_related("group__category").filter(id__in=type_ids)

            response = {
                type.id: ModuleSchema(
                    name=type.name,
                    category=type.group.category.name if type.group and type.group.category else "",
                    slot=module_slot(type)
                ) for type in types
            }
            logger.info(f"Returning preloaded module info for {len(response)} items to user {request.user}")
            return response
