from typing import Annotated
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, Query
from lfx.log.logger import logger

from langflow.api.utils import CurrentActiveUser, check_langflow_version
from langflow.services.auth import utils as auth_utils
from langflow.services.deps import get_settings_service, get_store_service
from langflow.services.store.exceptions import CustomError
from langflow.services.store.schema import (
    CreateComponentResponse,
    DownloadComponentResponse,
    ListComponentResponseModel,
    StoreComponentCreate,
    TagResponse,
    UsersLikesResponse,
)

router = APIRouter(prefix="/store", tags=["Components Store"], include_in_schema=False)


def get_user_store_api_key(user: CurrentActiveUser):
    if not user.store_api_key:
        raise HTTPException(status_code=400, detail="You must have a store API key set.")
    try:
        return auth_utils.decrypt_api_key(user.store_api_key)
    except Exception as e:
        raise HTTPException(status_code=500, detail="Failed to decrypt API key. Please set a new one.") from e


def get_optional_user_store_api_key(user: CurrentActiveUser):
    if not user.store_api_key:
        return None
    try:
        return auth_utils.decrypt_api_key(user.store_api_key)
    except Exception:  # noqa: BLE001
        logger.exception("Failed to decrypt API key")
        return user.store_api_key


@router.get("/check/")
async def check_if_store_is_enabled():
    return {
        "enabled": get_settings_service().settings.store,
    }


@router.get("/check/api_key")
async def check_if_store_has_api_key(
    api_key: Annotated[str | None, Depends(get_optional_user_store_api_key)],
):
    if api_key is None:
        return {"has_api_key": False, "is_valid": False}

    try:
        is_valid = await get_store_service().check_api_key(api_key)
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e)) from e

    return {"has_api_key": api_key is not None, "is_valid": is_valid}


@router.post("/components/", status_code=201)
async def share_component(
    component: StoreComponentCreate,
    store_api_key: Annotated[str, Depends(get_user_store_api_key)],
) -> CreateComponentResponse:
    try:
        await check_langflow_version(component)
        return await get_store_service().upload(store_api_key, component)
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.patch("/components/{component_id}", status_code=201)
async def update_shared_component(
    component_id: UUID,
    component: StoreComponentCreate,
    store_api_key: Annotated[str, Depends(get_user_store_api_key)],
) -> CreateComponentResponse:
    try:
        await check_langflow_version(component)
        return await get_store_service().update(store_api_key, component_id, component)
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/components/")
async def get_components(
    *,
    component_id: Annotated[str | None, Query()] = None,
    search: Annotated[str | None, Query()] = None,
    private: Annotated[bool | None, Query()] = None,
    is_component: Annotated[bool | None, Query()] = None,
    tags: Annotated[list[str] | None, Query()] = None,
    sort: Annotated[list[str] | None, Query()] = None,
    liked: Annotated[bool, Query()] = False,
    filter_by_user: Annotated[bool, Query()] = False,
    fields: Annotated[list[str] | None, Query()] = None,
    page: int = 1,
    limit: int = 10,
    store_api_key: Annotated[str | None, Depends(get_optional_user_store_api_key)],
) -> ListComponentResponseModel:
    try:
        return await get_store_service().get_list_component_response_model(
            component_id=component_id,
            search=search,
            private=private,
            is_component=is_component,
            fields=fields,
            tags=tags,
            sort=sort,
            liked=liked,
            filter_by_user=filter_by_user,
            page=page,
            limit=limit,
            store_api_key=store_api_key,
        )
    except CustomError as exc:
        raise HTTPException(status_code=exc.status_code, detail=str(exc)) from exc
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc)) from exc


@router.get("/components/{component_id}")
async def download_component(
    component_id: UUID,
    store_api_key: Annotated[str, Depends(get_user_store_api_key)],
) -> DownloadComponentResponse:
    try:
        component = await get_store_service().download(store_api_key, component_id)
    except CustomError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc)) from exc

    if component is None:
        raise HTTPException(status_code=400, detail="Component not found")

    return component


@router.get("/tags", response_model=list[TagResponse])
async def get_tags():
    try:
        return await get_store_service().get_tags()
    except CustomError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc)) from exc


@router.get("/users/likes", response_model=list[UsersLikesResponse])
async def get_list_of_components_liked_by_user(
    store_api_key: Annotated[str, Depends(get_user_store_api_key)],
):
    try:
        return await get_store_service().get_user_likes(store_api_key)
    except CustomError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc)) from exc


@router.post("/users/likes/{component_id}")
async def like_component(
    component_id: UUID,
    store_api_key: Annotated[str, Depends(get_user_store_api_key)],
) -> UsersLikesResponse:
    try:
        store_service = get_store_service()
        result = await store_service.like_component(store_api_key, str(component_id))
        likes_count = await store_service.get_component_likes_count(str(component_id), store_api_key)

        return UsersLikesResponse(likes_count=likes_count, liked_by_user=result)
    except CustomError as exc:
        raise HTTPException(status_code=exc.status_code, detail=str(exc)) from exc
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc)) from exc
