"""Чтение журналов: задания (jobs_history), развёртывание (provision_log), Helm-аддоны (helm_addon_log).

Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""

from __future__ import annotations

import asyncio
import logging

from fastapi import APIRouter, HTTPException, Query

from core.cluster_lifecycle import validate_cluster_name
from core.job_journal import collect_recent_journal_entries_page_sync, read_cluster_journal_sync
from core.provision_log import (
    HELM_ADDON_LOG_FILENAME,
    PROVISION_LOG_FILENAME,
    collect_cluster_dir_logs_page_sync,
)
from models.schemas import (
    ClusterDirLogEntryModel,
    ClusterJournalResponse,
    JournalEntryModel,
    JournalPagedDirLogsResponse,
    JournalRecentResponse,
)

logger = logging.getLogger("kind_k8s.api.journal")

router = APIRouter(tags=["journal"])


def _journal_total_pages(total: int, limit: int) -> int:
    if total <= 0 or limit <= 0:
        return 0
    return (total + limit - 1) // limit


def _build_paged_dir_response(
    rows: list[dict],
    *,
    limit: int,
    offset: int,
    total: int,
) -> JournalPagedDirLogsResponse:
    total_pages = _journal_total_pages(total, limit)
    if total <= 0:
        page = 1
    else:
        page = min((offset // limit) + 1, total_pages)
        page = max(1, page)
    entries = [ClusterDirLogEntryModel.model_validate(r) for r in rows]
    return JournalPagedDirLogsResponse(
        limit=limit,
        offset=offset,
        total=total,
        page=page,
        total_pages=total_pages,
        entries=entries,
    )


@router.get(
    "/journal/recent",
    response_model=JournalRecentResponse,
    summary="Страница журнала заданий (jobs_history), опционально один кластер",
)
async def get_journal_recent(
    limit: int = Query(default=30, ge=1, le=100, description="Записей на страницу"),
    offset: int = Query(default=0, ge=0, description="Смещение (0 = первая страница)"),
    cluster: str | None = Query(
        default=None,
        description="Имя кластера: только записи из clusters/<имя>/journal/jobs_history.json",
    ),
) -> JournalRecentResponse:
    """Сборка из ``journal/jobs_history.json``; при ``cluster`` — только выбранный каталог."""
    c = cluster.strip() if cluster else None
    if c and not validate_cluster_name(c):
        raise HTTPException(status_code=400, detail="Некорректное имя кластера")
    rows, total = await asyncio.to_thread(
        collect_recent_journal_entries_page_sync,
        limit=limit,
        offset=offset,
        cluster_name=c,
    )
    entries = [JournalEntryModel.model_validate(r) for r in rows]
    total_pages = _journal_total_pages(total, limit)
    if total <= 0:
        page = 1
    else:
        page = min((offset // limit) + 1, total_pages)
        page = max(1, page)
    return JournalRecentResponse(
        limit=limit,
        offset=offset,
        total=total,
        page=page,
        total_pages=total_pages,
        entries=entries,
    )


@router.get(
    "/journal/provision",
    response_model=JournalPagedDirLogsResponse,
    summary="Журналы развёртывания по кластерам (provision_log.json)",
)
async def get_journal_provision_logs(
    limit: int = Query(default=30, ge=1, le=100),
    offset: int = Query(default=0, ge=0),
) -> JournalPagedDirLogsResponse:
    """По одному последнему ``provision_log.json`` на кластер, новые первыми."""
    rows, total = await asyncio.to_thread(
        collect_cluster_dir_logs_page_sync,
        filename=PROVISION_LOG_FILENAME,
        limit=limit,
        offset=offset,
    )
    return _build_paged_dir_response(rows, limit=limit, offset=offset, total=total)


@router.get(
    "/journal/helm-addons",
    response_model=JournalPagedDirLogsResponse,
    summary="Журналы установки Helm-аддонов (helm_addon_log.json)",
)
async def get_journal_helm_addon_logs(
    limit: int = Query(default=30, ge=1, le=100),
    offset: int = Query(default=0, ge=0),
) -> JournalPagedDirLogsResponse:
    """Все записи из ``helm_addon_log.json`` по кластерам (история операций), новые первыми."""
    rows, total = await asyncio.to_thread(
        collect_cluster_dir_logs_page_sync,
        filename=HELM_ADDON_LOG_FILENAME,
        limit=limit,
        offset=offset,
    )
    return _build_paged_dir_response(rows, limit=limit, offset=offset, total=total)


@router.get(
    "/clusters/{name}/journal",
    response_model=ClusterJournalResponse,
    summary="Журнал заданий кластера (JSON с диска)",
)
async def get_cluster_journal(name: str) -> ClusterJournalResponse:
    n = name.strip()
    if not validate_cluster_name(n):
        raise HTTPException(status_code=400, detail="Некорректное имя кластера")
    raw = await asyncio.to_thread(read_cluster_journal_sync, n)
    if raw is None:
        return ClusterJournalResponse(cluster_name=n, file_version=None, entries=[])
    fv = raw.get("file_version") if isinstance(raw.get("file_version"), int) else None
    ent = raw.get("entries")
    if not isinstance(ent, list):
        return ClusterJournalResponse(cluster_name=n, file_version=fv, entries=[])
    entries: list[JournalEntryModel] = []
    for item in ent:
        if isinstance(item, dict):
            try:
                entries.append(JournalEntryModel.model_validate(item))
            except Exception:
                logger.debug("Пропуск некорректной записи журнала кластера «%s»", n)
    return ClusterJournalResponse(cluster_name=n, file_version=fv, entries=entries)
