"""Настройка приложения FastAPI для проекта IOC Checker."""

from __future__ import annotations

import logging
from typing import Any

from fastapi import APIRouter, FastAPI, HTTPException, status
from pydantic import BaseModel, Field

from ioc_checker.config import configure_logging, settings
from ioc_checker.main import parse_text
from ioc_checker.queue import get_queue_load
from ioc_checker.services import (
    DuplicateTaskError,
    MissingTokenError,
    NoIocsProvidedError,
    enqueue_task as enqueue_task_service,
    get_status as get_task_status,
)
from ioc_checker.startup import bootstrap, shutdown

logger = logging.getLogger(__name__)


class ParseTextRequest(BaseModel):
    """Тело запроса для разбора текста."""

    text: str = Field(
        ...,
        min_length=1,
        description="Исходный текст, содержащий потенциальные IOC",
    )


class ParseResponse(BaseModel):
    """Стандартная схема ответа для операций парсинга."""

    matches: dict[str, list[str]] = Field(
        default_factory=dict,
        description="Найденные IOC, сгруппированные по типу",
    )


class TaskRequest(BaseModel):
    """Тело запроса для постановки IOC на сканирование."""

    text: str = Field(
        ...,
        min_length=1,
        description="Исходный текст, содержащий потенциальные IOC",
    )


class TaskDescriptor(BaseModel):
    """Описание задания, поставленного в очередь."""

    id: str
    iocs: list[str]
    input_text: str | None = None


class TaskResponse(BaseModel):
    """Ответ, возвращаемый после постановки задания в очередь."""

    task: TaskDescriptor


class IndicatorVerdictPayload(BaseModel):
    """Схема вердикта, возвращаемого API."""

    verdicts: list[str] = Field(default_factory=list)
    reasons: list[dict[str, Any]] = Field(default_factory=list)
    tags: list[str] = Field(default_factory=list)


class TaskStatusResponse(BaseModel):
    """Структура ответа со статусом задания."""

    status: str | None = None
    verdicts: dict[str, IndicatorVerdictPayload] | None = None
    error: str | None = None
    task: str
    iocs: list[str] | None = None
    processed: list[str] | None = None
    pending: list[str] | None = None
    analysis: dict[str, dict[str, Any]] | None = None
    input_text: str | None = None


class HealthResponse(BaseModel):
    """Информация о состоянии API и очереди."""

    status: str
    queued_tasks: int
    queued_iocs: int


router = APIRouter(prefix="/api")


def _handle_scan_error(error: Exception) -> HTTPException:
    """Преобразовать ошибки сервиса сканирования в единый HTTP-ответ."""

    logger.error("Запрос на сканирование завершился ошибкой: %s", error)
    return HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(error))


@router.post("/parse/text", response_model=ParseResponse)
async def parse_text_endpoint(payload: ParseTextRequest) -> ParseResponse:
    """Разобрать IOC из текстового ввода."""

    logger.info("Получен запрос на разбор текста")
    matches = await parse_text(payload.text)
    logger.debug("Парсер вернул %d групп IOC", len(matches))
    return ParseResponse(matches=matches)


@router.post("/tasks", response_model=TaskResponse)
async def enqueue_task_endpoint(payload: TaskRequest) -> TaskResponse:
    """Поставить IOC на сканирование через сервисный слой."""

    logger.info("Получен запрос на постановку в очередь сырого текста")
    try:
        result = await enqueue_task_service(payload.text)
    except (DuplicateTaskError, MissingTokenError, NoIocsProvidedError) as exc:
        raise _handle_scan_error(exc) from exc
    logger.debug("Задание %s принято в обработку", result["task"]["id"])
    return TaskResponse.model_validate(result)


@router.get("/tasks/{task_id}", response_model=TaskStatusResponse)
async def get_task(task_id: str) -> TaskStatusResponse:
    """Получить статус поставленного задания."""

    logger.info("Запрошен статус задания %s", task_id)
    result = await get_task_status(task_id)
    if result.get("error") == "неизвестное задание":
        logger.warning("Задание %s не найдено", task_id)
        raise HTTPException(
            status.HTTP_404_NOT_FOUND,
            detail="Задание не найдено",
        )
    logger.debug(
        "Возвращаем статус задания %s со состоянием %s",
        task_id,
        result.get("status"),
    )
    return TaskStatusResponse.model_validate(result)


@router.get("/health", response_model=HealthResponse)
async def healthcheck() -> HealthResponse:
    """Проверить доступность API и загрузку очереди."""

    logger.info("Получен запрос на healthcheck API")
    queue_load = get_queue_load()
    logger.debug("Очередь содержит %d задач и %d IOC", queue_load["queued_tasks"], queue_load["queued_iocs"])
    return HealthResponse(status="ok", **queue_load)


def create_app() -> FastAPI:
    """Создать и настроить экземпляр FastAPI."""

    configure_logging()
    logger.debug("Логирование API настроено на уровень %s", settings.log_level)
    logger.info("Создаём экземпляр приложения FastAPI")
    application = FastAPI(
        title="API проверки IOC",
        description="HTTP-интерфейс для сервисов разбора и сканирования IOC.",
        version="0.1.0",
        docs_url="/api/docs",
        redoc_url="/api/redoc",
        openapi_url="/api/openapi.json",
    )
    application.include_router(router)
    application.add_event_handler("startup", bootstrap)
    application.add_event_handler("shutdown", shutdown)
    logger.debug("Маршрутизатор API зарегистрирован с %d маршрут(ами)", len(application.router.routes))
    return application


app = create_app()
