"""Справочник версий Helm-чартов и сборка YAML values для редактора на странице аддонов.

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

from __future__ import annotations

import asyncio
import logging

from fastapi import APIRouter, HTTPException

from core.helm_addons import (
    HelmAddonError,
    compose_ingress_effective_values,
    compose_istio_mesh_preview_values,
    compose_kube_prometheus_effective_values,
    compose_metrics_server_effective_values,
    dump_helm_values_yaml,
    helm_addon_chart_versions_all,
    helm_repo_ensure,
    require_helm_binary,
)
from models.schemas import (
    HelmAddonChartVersionsResponse,
    HelmAddonComposeBatchRequest,
    HelmAddonComposeBatchResponse,
    HelmAddonComposeValuesRequest,
    HelmAddonComposeValuesResponse,
)

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

router = APIRouter(tags=["helm-charts"])


def _compose_values_sync(req: HelmAddonComposeValuesRequest) -> HelmAddonComposeValuesResponse:
    """Синхронная сборка YAML (вызов из ``asyncio.to_thread``): ``helm show values`` + оверлеи."""
    helm_repo_ensure()
    addon = req.addon
    if addon == "ingress-nginx":
        data = compose_ingress_effective_values(req.chart_version)
        return HelmAddonComposeValuesResponse(values_yaml=dump_helm_values_yaml(data))
    if addon == "kube-prometheus-stack":
        u = (req.grafana_admin_user or "admin").strip() or "admin"
        pw = (req.grafana_admin_password or "").strip() or "ChangeMe12345"
        data = compose_kube_prometheus_effective_values(req.chart_version, u, pw)
        return HelmAddonComposeValuesResponse(values_yaml=dump_helm_values_yaml(data))
    if addon == "metrics-server":
        data = compose_metrics_server_effective_values(req.chart_version)
        return HelmAddonComposeValuesResponse(values_yaml=dump_helm_values_yaml(data))
    if addon == "istio-kiali":
        k, ib, ir = compose_istio_mesh_preview_values(req.istio_chart_version, req.kiali_chart_version)
        return HelmAddonComposeValuesResponse(
            values_yaml=dump_helm_values_yaml(k),
            istio_base_values_yaml=dump_helm_values_yaml(ib),
            istio_istiod_values_yaml=dump_helm_values_yaml(ir),
        )
    raise RuntimeError(f"неизвестный addon: {addon}")


def _compose_batch_sync(body: HelmAddonComposeBatchRequest) -> HelmAddonComposeBatchResponse:
    """Один ``helm repo update`` и шесть выводов ``helm show values`` (с оверлеями где нужно)."""
    helm_repo_ensure()
    u = (body.grafana_admin_user or "admin").strip() or "admin"
    pw = (body.grafana_admin_password or "").strip() or "ChangeMe12345"
    ing = dump_helm_values_yaml(compose_ingress_effective_values(body.ingress_chart_version))
    prom = dump_helm_values_yaml(
        compose_kube_prometheus_effective_values(body.kube_prometheus_chart_version, u, pw),
    )
    ms = dump_helm_values_yaml(compose_metrics_server_effective_values(body.metrics_server_chart_version))
    k, ib, ir = compose_istio_mesh_preview_values(body.istio_chart_version, body.kiali_chart_version)
    return HelmAddonComposeBatchResponse(
        ingress_nginx_values_yaml=ing,
        kube_prometheus_values_yaml=prom,
        metrics_server_values_yaml=ms,
        kiali_values_yaml=dump_helm_values_yaml(k),
        istio_base_values_yaml=dump_helm_values_yaml(ib),
        istio_istiod_values_yaml=dump_helm_values_yaml(ir),
    )


@router.get(
    "/helm/chart-versions",
    response_model=HelmAddonChartVersionsResponse,
    summary="Версии чартов аддонов (для выпадающих списков)",
)
async def get_helm_addon_chart_versions() -> HelmAddonChartVersionsResponse:
    """
    Выполняет ``helm repo update`` и для каждого аддона — ``helm search repo <chart> --versions``.

    Результат кэшируется на ``KIND_K8S_HELM_VERSIONS_CACHE_SEC`` (по чарту).
    Пустой список — если helm недоступен или репозиторий не ответил.
    """
    try:
        require_helm_binary()
    except HelmAddonError as e:
        logger.warning("helm недоступен для списка версий: %s", e)
        raise HTTPException(status_code=503, detail=str(e)) from e
    try:
        data = await asyncio.to_thread(helm_addon_chart_versions_all)
    except HelmAddonError as e:
        logger.exception("Ошибка получения версий чартов")
        raise HTTPException(status_code=500, detail=str(e)) from e
    return HelmAddonChartVersionsResponse(**data)


@router.post(
    "/helm/addons/compose-values",
    response_model=HelmAddonComposeValuesResponse,
    summary="Собрать YAML values для редактора аддонов (helm show values + форма)",
)
async def post_helm_addon_compose_values(
    body: HelmAddonComposeValuesRequest,
) -> HelmAddonComposeValuesResponse:
    """
    Выполняет ``helm repo update`` (внутри compose-функций) и ``helm show values`` для выбранного аддона.

    Для **kube-prometheus-stack** в YAML подставляются логин и пароль Grafana из тела запроса;
    если пароль пуст, в preview используется временная строка ``ChangeMe12345`` (замените перед установкой).

    Для **istio-kiali** возвращаются три блока YAML: **kiali-server**, **istio/base**, **istio/istiod**.
    """
    try:
        require_helm_binary()
    except HelmAddonError as e:
        raise HTTPException(status_code=503, detail=str(e)) from e
    try:
        return await asyncio.to_thread(_compose_values_sync, body)
    except HelmAddonError as e:
        logger.exception("compose-values: ошибка helm")
        raise HTTPException(status_code=500, detail=str(e)) from e


@router.post(
    "/helm/addons/compose-values-batch",
    response_model=HelmAddonComposeBatchResponse,
    summary="Собрать все YAML values для страницы аддонов одним запросом",
)
async def post_helm_addon_compose_values_batch(
    body: HelmAddonComposeBatchRequest,
) -> HelmAddonComposeBatchResponse:
    """
    Один проход **``helm repo update``** и подстановка версий из селектов / полей формы на странице аддонов.

    Удобнее, чем четыре отдельных **compose-values**, когда UI обновляет все карточки сразу.
    """
    try:
        require_helm_binary()
    except HelmAddonError as e:
        raise HTTPException(status_code=503, detail=str(e)) from e
    try:
        return await asyncio.to_thread(_compose_batch_sync, body)
    except HelmAddonError as e:
        logger.exception("compose-values-batch: ошибка helm")
        raise HTTPException(status_code=500, detail=str(e)) from e
