import os
from functools import lru_cache
from pathlib import Path
from typing import Any, Dict, List, Union

from fastapi import APIRouter, Depends, Query, Security
from fastapi.responses import FileResponse

from server.data.definitions import API_SUB_PATH, Paths, ECP_WORK_FILES_DIR, WEBUI_WORK_FILES_DIR, Groups
from server.models.error import Error
from server.models.extra_models import TokenModel  # noqa: F401
from server.models.file import File
from server.security_api import get_token_ApiKeyAuth, checkTokenCapabilities

from server.services.FileService import FileService
from server.repositories.FileRepository import FileRepository
from server.apis import appData

router = APIRouter(prefix=API_SUB_PATH)

# Directories
PATH_ECP_WORK_DIR = os.environ.get(ECP_WORK_FILES_DIR, Paths.DEFAULT_ECP_WORK_DIR.value)
PATH_ECP_LOGS_DIR = f"{PATH_ECP_WORK_DIR}/{Paths.ECP_LOGS_SUBDIR.value}"

PATH_WEBUI_WORK_DIR = os.environ.get(WEBUI_WORK_FILES_DIR, Paths.DEFAULT_WEBUI_WORK_DIR.value)
PATH_WEBUI_LOGS_DIR = f"{PATH_WEBUI_WORK_DIR}/{Paths.WEBUI_LOGS_SUBDIR.value}"

# Files
PATH_ECP_STATISTICS_FILE = f"{PATH_ECP_WORK_DIR}/{Paths.ECP_DATA_SUBDIR.value}/Statistics.json"

# Logs api specific path variables
BASE_PATHS: List[str | Path] = [PATH_ECP_LOGS_DIR, PATH_WEBUI_LOGS_DIR, PATH_ECP_STATISTICS_FILE]

# TODO: move this getter to a generic location like `server/core/di.py` and generate a factory for different apis
@lru_cache()
def getFileService() -> FileService:
    repo = FileRepository(BASE_PATHS)
    return FileService(repo=repo, appData=appData)


@router.get(
    "/logs",
    responses={
        200: {"model": Union[Dict, Any], "description": "Gets all log files."},
        400: {"model": Error, "description": "Bad request."},
        401: {"model": Error, "description": "Unauthorized."},
    },
    tags=["logs"],
    response_model_by_alias=True,
)
async def logs_get(
    onlyList: bool = Query(False, description="The boolean for activating only list mode."),
    token_ApiKeyAuth: TokenModel = Security(get_token_ApiKeyAuth),
    service: FileService = Depends(getFileService),
) -> Union[List, Any]:
    await checkTokenCapabilities(token=token_ApiKeyAuth, group=Groups.DOWNLOAD_LOGS.value)
    if onlyList:
        return await service.listIds()
    return await service.zipMany(label="logs")


@router.delete(
    "/logs/{logFile}",
    responses={
        200: {"model": File, "description": "Deleted the log file."},
        400: {"model": Error, "description": "Bad request."},
        401: {"model": Error, "description": "Unauthorized."},
        404: {"model": Error, "description": "File not found."},
    },
    tags=["logs"],
    response_model_by_alias=True,
)
async def logs_log_file_delete(
    logFile: str = Path(description="The name of the log file."),
    token_ApiKeyAuth: TokenModel = Security(get_token_ApiKeyAuth),
    service: FileService = Depends(getFileService),
) -> File:
    await checkTokenCapabilities(token=token_ApiKeyAuth, group=Groups.DOWNLOAD_LOGS.value)
    result = await service.deleteOne(logFile)
    return File(fileName=result["deleted"], content=None, datatype="log")


@router.get(
    "/logs/{logFile}",
    responses={
        200: {"model": File, "description": "Gets the log file."},
        400: {"model": Error, "description": "Bad request."},
        401: {"model": Error, "description": "Unauthorized."},
        404: {"model": Error, "description": "File not found."},
    },
    tags=["logs"],
    response_model_by_alias=True,
)
async def logs_log_file_get(
    logFile: str = Path(description="The name of the log file."),
    token_ApiKeyAuth: TokenModel = Security(get_token_ApiKeyAuth),
    service: FileService = Depends(getFileService),
) -> FileResponse:
    await checkTokenCapabilities(token=token_ApiKeyAuth, group=Groups.DOWNLOAD_LOGS.value)
    return await service.zipOne(logFile)
