"""ESI data providers """

from esi.exceptions import HTTPNotModified
from esi.models import Token
from esi.openapi_clients import ESIClientProvider

from allianceauth.services.hooks import get_extension_logger

from dens import __version__, app_name, compatibility_date, repo_url
from dens.app_settings import DENS_USE_ETAGS
from dens.esi.exceptions import MissingTokenError, NotModified
from dens.esi.models import (
    CharactersCharacterIdAssetsGetItem,
    CharactersCharacterIdAssetsLocationsPostItem,
    CharactersCharacterIdNotificationsGetItem,
)
from dens.models import DenOwner

MERCENARY_DENS_TYPE_IDS = [
    85230,
    85980,
]
TEMPERATE_PLANET_TYPE_ID = 11


esi = ESIClientProvider(
    ua_appname=app_name,
    ua_version=__version__,
    ua_url=repo_url,
    compatibility_date=compatibility_date,
    operations=[
        "GetCharactersCharacterIdAssets",
        "PostCharactersCharacterIdAssetsLocations",
        "GetCharactersCharacterIdNotifications",
    ],
)

logger = get_extension_logger(__name__)


def get_character_assets_from_esi(
    owner: DenOwner,
    *,
    use_etag: bool = True,
) -> list[CharactersCharacterIdAssetsGetItem]:
    """Returns all character assets from the ESI"""
    logger.info(
        "Fetching esi asset for user id '%s' (use etags: '%s')", owner.id, use_etag
    )

    use_etag = use_etag and DENS_USE_ETAGS

    try:
        assets = esi.client.Assets.GetCharactersCharacterIdAssets(
            character_id=owner.character_id,
            token=owner.fetch_token(),
        ).results(
            use_etag=use_etag,
            store_cache=False,
        )
    except Token.DoesNotExist as e:
        logger.error("Missing ESI token for owner id '%s'", owner.id)
        raise MissingTokenError("Missing ESI token when fetching owner assets") from e

    except HTTPNotModified as e:
        raise NotModified("get_character_assets", [owner.character_id]) from e

    logger.debug(assets)

    return [asset.model_dump() for asset in assets]


def get_owner_anchored_dens_from_esi(
    owner: DenOwner,
    *,
    use_etag: bool = True,
) -> list[CharactersCharacterIdAssetsGetItem]:
    """Return all dens locations from the ESI"""

    den_assets = [
        asset
        for asset in get_character_assets_from_esi(owner, use_etag=use_etag)
        if asset["type_id"] in MERCENARY_DENS_TYPE_IDS
        and asset["location_type"] == "solar_system"
    ]

    return den_assets


def get_esi_asset_location(
    owner: DenOwner, item_id: int, *, use_etag: bool = True
) -> tuple[int, int, int]:
    """Returns the position of an item"""
    logger.info(
        "Fetching item id '%s' location from owner '%s' esi information (use etag: '%s')",
        item_id,
        owner,
        use_etag,
    )

    use_etag = not (use_etag and DENS_USE_ETAGS)

    try:
        result: CharactersCharacterIdAssetsLocationsPostItem = (
            esi.client.Assets.PostCharactersCharacterIdAssetsLocations(
                character_id=owner.character_id,
                body=[item_id],
                token=owner.fetch_token(),
            )
            .result(
                use_etag=use_etag,
                store_cache=False,
            )[0]
            .model_dump()
        )
        position = result["position"]
    except Token.DoesNotExist as e:
        logger.error("Missing ESI token for owner id '%s'", owner.id)
        raise MissingTokenError(
            "Missing ESI token when fetching owner asset location"
        ) from e

    logger.debug(position)

    return position["x"], position["y"], position["z"]


def get_owner_notifications(
    owner: DenOwner,
    *,
    use_etag: bool = True,
) -> list[CharactersCharacterIdNotificationsGetItem]:
    """Returns notifications from an owner"""
    logger.info(
        "Fetching notifications for den owner id '%s' with use_etag set to '%s'",
        owner.id,
        use_etag,
    )
    use_etag = use_etag and DENS_USE_ETAGS
    try:
        notifications = esi.client.Character.GetCharactersCharacterIdNotifications(
            character_id=owner.character_id,
            token=owner.fetch_token(),
        ).results(use_etag=use_etag, store_cache=False)
    except Token.DoesNotExist as e:
        logger.error("Missing ESI token for owner '%s'", owner.id)
        raise MissingTokenError(
            "Missing ESI token when fetching owner notifications"
        ) from e
    except HTTPNotModified as e:
        raise NotModified("get_character_notifications", [owner.character_id]) from e

    logger.debug(notifications)

    return [notification.model_dump() for notification in notifications]


def get_owner_mercenarydenreinforced_notifications_from_esi(
    owner: DenOwner,
    *,
    use_etag: bool = True,
) -> list[CharactersCharacterIdNotificationsGetItem]:
    """Returns only the `MercenaryDenReinforced` notifications from this owner"""

    return [
        notification
        for notification in get_owner_notifications(owner, use_etag=use_etag)
        if notification["type"] == "MercenaryDenReinforced"
    ]
