from __future__ import annotations

from typing import Optional

from aiohttp import ClientSession  # type: ignore[import-not-found]

from immich.client.api_client import ApiClient
from immich.client.configuration import Configuration

from immich.client.api.activities_api import ActivitiesApi
from immich.client.api.albums_api import AlbumsApi
from immich.client.api.api_keys_api import APIKeysApi
from immich.client_wrapper.assets_api_wrapped import AssetsApiWrapped
from immich.client.api.authentication_admin_api import AuthenticationAdminApi
from immich.client.api.authentication_api import AuthenticationApi
from immich.client.api.deprecated_api import DeprecatedApi
from immich.client_wrapper.download_api_wrapped import DownloadApiWrapped
from immich.client.api.duplicates_api import DuplicatesApi
from immich.client.api.faces_api import FacesApi
from immich.client.api.jobs_api import JobsApi
from immich.client.api.libraries_api import LibrariesApi
from immich.client.api.maintenance_admin_api import MaintenanceAdminApi
from immich.client.api.map_api import MapApi
from immich.client.api.memories_api import MemoriesApi
from immich.client.api.notifications_admin_api import NotificationsAdminApi
from immich.client.api.notifications_api import NotificationsApi
from immich.client.api.partners_api import PartnersApi
from immich.client.api.people_api import PeopleApi
from immich.client.api.plugins_api import PluginsApi
from immich.client.api.queues_api import QueuesApi
from immich.client.api.search_api import SearchApi
from immich.client.api.server_api import ServerApi
from immich.client.api.sessions_api import SessionsApi
from immich.client.api.shared_links_api import SharedLinksApi
from immich.client.api.stacks_api import StacksApi
from immich.client.api.sync_api import SyncApi
from immich.client.api.system_config_api import SystemConfigApi
from immich.client.api.system_metadata_api import SystemMetadataApi
from immich.client.api.tags_api import TagsApi
from immich.client.api.timeline_api import TimelineApi
from immich.client.api.trash_api import TrashApi
from immich.client.api.users_admin_api import UsersAdminApi
from immich.client_wrapper.users_api_wrapped import UsersApiWrapped
from immich.client.api.views_api import ViewsApi
from immich.client.api.workflows_api import WorkflowsApi


def _normalize_base_url(base_url: str) -> str:
    return base_url.rstrip("/")


def _build_configuration(
    *,
    api_key: Optional[str],
    bearer_token: Optional[str],
    cookie: Optional[str],
    base_url: str,
) -> Configuration:
    config = Configuration(host=_normalize_base_url(base_url))
    if api_key:
        # Security scheme name is `api_key` (header: x-api-key)
        config.api_key["api_key"] = api_key
    if cookie:
        # Security scheme name is `cookie` (cookie: immich_access_token)
        config.api_key["cookie"] = cookie
    if bearer_token:
        # JWT access token (Authorization: Bearer <token>)
        config.access_token = bearer_token
    return config


class AsyncClient:
    """
    Async client for the Immich API.
    """

    activities: ActivitiesApi
    """An activity is a like or a comment made by a user on an asset or album.

    https://api.immich.app/endpoints/activities
    """

    albums: AlbumsApi
    """An album is a collection of assets that can be shared with other users or via shared links.

    https://api.immich.app/endpoints/albums
    """

    api_keys: APIKeysApi
    """An api key can be used to programmatically access the Immich API.

    https://api.immich.app/endpoints/api-keys
    """

    assets: AssetsApiWrapped
    """An asset is an image or video that has been uploaded to Immich.

    https://api.immich.app/endpoints/assets
    """

    authentication: AuthenticationApi
    """Endpoints related to user authentication, including OAuth.

    https://api.immich.app/endpoints/authentication
    """

    authentication_admin: AuthenticationAdminApi
    """Administrative endpoints related to authentication.

    https://api.immich.app/endpoints/authentication-(admin)
    """

    deprecated: DeprecatedApi
    """Deprecated endpoints that are planned for removal in the next major release.

    https://api.immich.app/endpoints/deprecated
    """

    download: DownloadApiWrapped
    """Endpoints for downloading assets or collections of assets.

    https://api.immich.app/endpoints/download
    """

    duplicates: DuplicatesApi
    """Endpoints for managing and identifying duplicate assets.

    https://api.immich.app/endpoints/duplicates
    """

    faces: FacesApi
    """A face is a detected human face within an asset, which can be associated with a person. Faces are normally detected via machine learning, but can also be created via manually.

    https://api.immich.app/endpoints/faces
    """

    jobs: JobsApi
    """Queues and background jobs are used for processing tasks asynchronously. Queues can be paused and resumed as needed.

    https://api.immich.app/endpoints/jobs
    """

    libraries: LibrariesApi
    """An external library is made up of input file paths or expressions that are scanned for asset files. Discovered files are automatically imported. Assets much be unique within a library, but can be duplicated across libraries. Each user has a default upload library, and can have one or more external libraries.

    https://api.immich.app/endpoints/libraries
    """

    maintenance_admin: MaintenanceAdminApi
    """Maintenance mode allows you to put Immich in a read-only state to perform various operations.

    https://api.immich.app/endpoints/maintenance-(admin)
    """

    map: MapApi
    """Map endpoints include supplemental functionality related to geolocation, such as reverse geocoding and retrieving map markers for assets with geolocation data.

    https://api.immich.app/endpoints/map
    """

    memories: MemoriesApi
    """A memory is a specialized collection of assets with dedicated viewing implementations in the web and mobile clients. A memory includes fields related to visibility and are automatically generated per user via a background job.

    https://api.immich.app/endpoints/memories
    """

    notifications: NotificationsApi
    """A notification is a specialized message sent to users to inform them of important events. Currently, these notifications are only shown in the Immich web application.

    https://api.immich.app/endpoints/notifications
    """

    notifications_admin: NotificationsAdminApi
    """Notification administrative endpoints.

    https://api.immich.app/endpoints/notifications-(admin)
    """

    partners: PartnersApi
    """A partner is a link with another user that allows sharing of assets between two users.

    https://api.immich.app/endpoints/partners
    """

    people: PeopleApi
    """A person is a collection of faces, which can be favorited and named. A person can also be merged into another person. People are automatically created via the face recognition job.

    https://api.immich.app/endpoints/people
    """

    plugins: PluginsApi
    """A plugin is an installed module that makes filters and actions available for the workflow feature.

    https://api.immich.app/endpoints/plugins
    """

    queues: QueuesApi
    """Queues and background jobs are used for processing tasks asynchronously. Queues can be paused and resumed as needed.

    https://api.immich.app/endpoints/queues
    """

    search: SearchApi
    """Endpoints related to searching assets via text, smart search, optical character recognition (OCR), and other filters like person, album, and other metadata. Search endpoints usually support pagination and sorting.

    https://api.immich.app/endpoints/search
    """

    server: ServerApi
    """Information about the current server deployment, including version and build information, available features, supported media types, and more.

    https://api.immich.app/endpoints/server
    """

    sessions: SessionsApi
    """A session represents an authenticated login session for a user. Sessions also appear in the web application as "Authorized devices".

    https://api.immich.app/endpoints/sessions
    """

    shared_links: SharedLinksApi
    """A shared link is a public url that provides access to a specific album, asset, or collection of assets. A shared link can be protected with a password, include a specific slug, allow or disallow downloads, and optionally include an expiration date.

    https://api.immich.app/endpoints/shared-links
    """

    stacks: StacksApi
    """A stack is a group of related assets. One asset is the "primary" asset, and the rest are "child" assets. On the main timeline, stack parents are included by default, while child assets are hidden.

    https://api.immich.app/endpoints/stacks
    """

    sync: SyncApi
    """A collection of endpoints for the new mobile synchronization implementation.

    https://api.immich.app/endpoints/sync
    """

    system_config: SystemConfigApi
    """Endpoints to view, modify, and validate the system configuration settings.

    https://api.immich.app/endpoints/system-config
    """

    system_metadata: SystemMetadataApi
    """Endpoints to view, modify, and validate the system metadata, which includes information about things like admin onboarding status.

    https://api.immich.app/endpoints/system-metadata
    """

    tags: TagsApi
    """A tag is a user-defined label that can be applied to assets for organizational purposes. Tags can also be hierarchical, allowing for parent-child relationships between tags.

    https://api.immich.app/endpoints/tags
    """

    timeline: TimelineApi
    """Specialized endpoints related to the timeline implementation used in the web application. External applications or tools should not use or rely on these endpoints, as they are subject to change without notice.

    https://api.immich.app/endpoints/timeline
    """

    trash: TrashApi
    """Endpoints for managing the trash can, which includes assets that have been discarded. Items in the trash are automatically deleted after a configured amount of time.

    https://api.immich.app/endpoints/trash
    """

    users_admin: UsersAdminApi
    """Administrative endpoints for managing users, including creating, updating, deleting, and restoring users. Also includes endpoints for resetting passwords and PIN codes.

    https://api.immich.app/endpoints/users-(admin)
    """

    users: UsersApiWrapped
    """Endpoints for viewing and updating the current users, including product key information, profile picture data, onboarding progress, and more.

    https://api.immich.app/endpoints/users
    """

    views: ViewsApi
    """Endpoints for specialized views, such as the folder view.

    https://api.immich.app/endpoints/views
    """

    workflows: WorkflowsApi
    """A workflow is a set of actions that run whenever a triggering event occurs. Workflows also can include filters to further limit execution.

    https://api.immich.app/endpoints/workflows
    """

    def __init__(
        self,
        *,
        api_key: Optional[str] = None,
        bearer_token: Optional[str] = None,
        cookie: Optional[str] = None,
        base_url: str,
        http_client: Optional[ClientSession] = None,
    ) -> None:
        self._owns_http_client = http_client is None
        self._injected_http_client = http_client
        self.config = _build_configuration(
            api_key=api_key,
            bearer_token=bearer_token,
            cookie=cookie,
            base_url=base_url,
        )
        self.base_client = ApiClient(configuration=self.config)
        self.base_client.user_agent = "immich-python-client"

        # Allow caller to inject a pre-configured aiohttp session.
        if http_client is not None:
            self.base_client.rest_client.pool_manager = http_client

        # API groups (single upstream API, not microservices)
        self.activities = ActivitiesApi(self.base_client)
        self.albums = AlbumsApi(self.base_client)
        self.api_keys = APIKeysApi(self.base_client)
        self.assets = AssetsApiWrapped(self.base_client)
        self.authentication = AuthenticationApi(self.base_client)
        self.authentication_admin = AuthenticationAdminApi(self.base_client)
        self.deprecated = DeprecatedApi(self.base_client)
        self.download = DownloadApiWrapped(self.base_client)
        self.duplicates = DuplicatesApi(self.base_client)
        self.faces = FacesApi(self.base_client)
        self.jobs = JobsApi(self.base_client)
        self.libraries = LibrariesApi(self.base_client)
        self.maintenance_admin = MaintenanceAdminApi(self.base_client)
        self.map = MapApi(self.base_client)
        self.memories = MemoriesApi(self.base_client)
        self.notifications = NotificationsApi(self.base_client)
        self.notifications_admin = NotificationsAdminApi(self.base_client)
        self.partners = PartnersApi(self.base_client)
        self.people = PeopleApi(self.base_client)
        self.plugins = PluginsApi(self.base_client)
        self.queues = QueuesApi(self.base_client)
        self.search = SearchApi(self.base_client)
        self.server = ServerApi(self.base_client)
        self.sessions = SessionsApi(self.base_client)
        self.shared_links = SharedLinksApi(self.base_client)
        self.stacks = StacksApi(self.base_client)
        self.sync = SyncApi(self.base_client)
        self.system_config = SystemConfigApi(self.base_client)
        self.system_metadata = SystemMetadataApi(self.base_client)
        self.tags = TagsApi(self.base_client)
        self.timeline = TimelineApi(self.base_client)
        self.trash = TrashApi(self.base_client)
        self.users = UsersApiWrapped(self.base_client)
        self.users_admin = UsersAdminApi(self.base_client)
        self.views = ViewsApi(self.base_client)
        self.workflows = WorkflowsApi(self.base_client)

    async def close(self) -> None:
        # If the caller injected the aiohttp session, don't close it.
        if not self._owns_http_client and self._injected_http_client is not None:
            self.base_client.rest_client.pool_manager = None
        await self.base_client.close()

    async def __aenter__(self) -> "AsyncClient":
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
        await self.close()
