from datetime import datetime

import logging
import mimetypes
import io


from immich_tools.immich.model.Album import Album
from immich_tools.immich.model.Asset import Asset
from immich_tools.immich.model.response.AssetToAlbumResponse import AssetToAlbumResponse
from immich_tools.immich.model.response.AssignTagResponse import AssignTagResponse
from immich_tools.immich.model.Tag import Tag
from immich_tools.immich.model.User import User
from immich_tools.immich.model.response.CreateTagResponse import CreateTagResponse
from immich_tools.immich.model.response.UploadAssetResponse import UploadAssetResponse
from immich_tools.immich.utils.Utils import Utils


class ImmichClient:
    def __init__(self, url, api_key):
        self.log = logging.getLogger("immich-tools")
        self.url = url
        self.api_key = api_key
        self.utils = Utils(url, api_key)

    def get_asset(self, id: str) -> Asset:
        """Returns asset of id \n
        path: /api/asssets/:id

        Parameters:
          id: id of the asset

        Returns:
          asset
        """
        r = self.utils.send_get(f"/api/assets/{id}")
        return self.utils.from_dict(data_class=Asset, data=r.json())

    def get_album(self, id: str) -> Album:
        """Returns album of id \n
        path: /api/albums/:id

        Parameters:
          id: id of the album

        Returns:
          album
        """
        r = self.utils.send_get(f"/api/albums/{id}")
        return self.utils.from_dict(Album, r.json())
      
      
    def get_albums(self) -> list[Album]:
        """Returns album of id \n
        path: /api/albums/:id

        Returns:
          all album
        """
        r = self.utils.send_get(f"/api/albums")
        albums_json = r.json()
        return [self.utils.from_dict(Album, album_json) for album_json in albums_json]

    def get_all_tags(self) -> list[Tag]:
        """Returns all tags \n
        path: /api/tags

        Returns:
          list of tags
        """
        r = self.utils.send_get(f"/api/tags")
        tags_json = r.json()
        return [self.utils.from_dict(Tag, tag_json) for tag_json in tags_json]

    def assign_tag_to_assets(self, tagId: str, assetIds: list[str]) -> list[AssignTagResponse]:
        """assign tags to assets \n
        PUT /api/tags/{tagId}/assets

        Returns:
          Immich Response
        """
        r = self.utils.send_put(f"/api/tags/{tagId}/assets", data={"ids": assetIds})
        responses = r.json()
        return [self.utils.from_dict(AssignTagResponse, response) for response in responses]

    def get_user(self) -> User:
        """Returns owner of the api key \n
        GET /api/users/me

        Returns:
          User
        """
        r = self.utils.send_get(f"/api/users/me")
        return self.utils.from_dict(User, r.json())

    def create_tag(self, name: str, color="", parentId="") -> CreateTagResponse:
        """create tag \n
        POST /api/tags
        """
        data = {"name": name}
        if color and color != "":
            data["color"] = color
        if parentId and parentId != "":
            data["parentId"] = parentId
        r = self.utils.send_post(f"/api/tags", data=data)
        return self.utils.from_dict(CreateTagResponse, r.json())
      
    def upsert_tags(self, names: list[str]) -> list[CreateTagResponse]:
        """create or update tags \n
        PUT /api/tags
        """
        data = {"tags": names}
        r = self.utils.send_put(f"/api/tags", data=data)
        responses = r.json()
        return [self.utils.from_dict(CreateTagResponse, response) for response in responses]

    def get_asset_content(self, assetId: str) -> bytes:
        """Returns owner of the api key \n
        GET /api/assets/{id}/original

        Returns:
          content of asset in bytes
        """
        r = self.utils.send_get(f"/api/assets/{assetId}/original")
        return r.content

    def upload_asset(
        self,
        asset_data: bytes,
        device_asset_id: str,
        device_id: str,
        file_created_at: datetime,
        file_modified_at: datetime,
        filename: str,
    ) -> UploadAssetResponse:
        """upload asset \n
        POST /assets

        Returns:
          UploadAssetResponse
        """
        mime_type, _ = mimetypes.guess_type(filename)
        files = {"assetData": (filename, io.BytesIO(asset_data), mime_type)}
        data = {
            "deviceAssetId": device_asset_id,
            "deviceId": device_id,
            "fileCreatedAt": self.utils.datetime_to_str(file_created_at),
            "fileModifiedAt": self.utils.datetime_to_str(file_modified_at),
        }
        self.log.debug(f"uploading {filename}...")
        r = self.utils.send_multipart("/api/assets", files, data)
        return self.utils.from_dict(UploadAssetResponse, r.json())

    def add_asset_to_album(self, album_id: str, asset_id: str) -> AssetToAlbumResponse:
        """add asset to album \n
        PUT /api/albums/{album_id}/assets

        Returns:
          AddAssetToAlbumResponse
        """
        data = {"ids": [asset_id]}
        r = self.utils.send_put(f"/api/albums/{album_id}/assets", data)
        return self.utils.from_dict(AssetToAlbumResponse, r.json())

    def remove_asset_from_album(self, album_id: str, asset_id: str) -> AssetToAlbumResponse:
        """remove asset from album \n
        DELETE /api/albums/{album_id}/assets

        Returns:
          AssetToAlbumResponse
        """
        data = {"ids": [asset_id]}
        r = self.utils.send_delete(f"/api/albums/{album_id}/assets", data)
        return self.utils.from_dict(AssetToAlbumResponse, r.json())

    def get_original_asset(self, asset_id: str) -> bytes:
        """get original asset \n
        GET /api/assets/{asset_id}/original

        Returns:
          original asset
        """
        r = self.utils.send_get(f"/api/assets/{asset_id}/original")
        return r.content