"""Endpoints des intégrations BYOK (spec Imports T8).

CRUD `integrations`, CRUD `import_schedules`, déclenchement manuel par cible. **Aucune
réponse ne porte la clé** : voir `schemas.IntegrationOut`, qui n'a pas de champ pour elle.

Tout est sous `CurrentOrgDep` et filtré par `user.org_id` : une intégration d'une autre
organisation n'existe pas (404, jamais 403).
"""

import uuid

from fastapi import APIRouter

from app.core.auth import CurrentOrgDep
from app.db.engine import SessionDep
from app.integrations import service
from app.integrations.schemas import (
    ImportSummary,
    ImportTrigger,
    ImportTriggerItem,
    ImportTriggerOut,
    IntegrationCreate,
    IntegrationListOut,
    IntegrationOut,
    IntegrationUpdate,
    KeywordListOut,
    KeywordListsOut,
    ListPreviewIn,
    ListPreviewOut,
    QuotaOut,
    ScheduleListOut,
    ScheduleOut,
    ScheduleUpsert,
    TargetImportListOut,
    TargetImportOut,
)
from app.keywords.sources import mangools_api

router = APIRouter(prefix="/integrations", tags=["integrations"])


@router.get("")
async def list_integrations(user: CurrentOrgDep, session: SessionDep) -> IntegrationListOut:
    items = await service.list_integrations(session, user.org_id)
    return IntegrationListOut(items=[IntegrationOut.model_validate(item) for item in items])


@router.post("", status_code=201)
async def create_integration(
    user: CurrentOrgDep, session: SessionDep, payload: IntegrationCreate
) -> IntegrationOut:
    record = await service.create_integration(session, user.org_id, payload)
    return IntegrationOut.model_validate(record)


@router.get("/{integration_id}")
async def get_integration(
    user: CurrentOrgDep, session: SessionDep, integration_id: uuid.UUID
) -> IntegrationOut:
    record = await service.get_integration(session, user.org_id, integration_id)
    return IntegrationOut.model_validate(record)


@router.patch("/{integration_id}")
async def update_integration(
    user: CurrentOrgDep,
    session: SessionDep,
    integration_id: uuid.UUID,
    payload: IntegrationUpdate,
) -> IntegrationOut:
    record = await service.update_integration(session, user.org_id, integration_id, payload)
    return IntegrationOut.model_validate(record)


@router.delete("/{integration_id}", status_code=204)
async def delete_integration(
    user: CurrentOrgDep, session: SessionDep, integration_id: uuid.UUID
) -> None:
    await service.delete_integration(session, user.org_id, integration_id)


@router.post("/{integration_id}/check")
async def check_integration(
    user: CurrentOrgDep, session: SessionDep, integration_id: uuid.UUID
) -> IntegrationOut:
    """Confronte la clé au fournisseur. Un refus est un **statut**, pas une erreur HTTP."""
    record = await service.check_integration(session, user.org_id, integration_id)
    return IntegrationOut.model_validate(record)


# --- listes enregistrées du compte --------------------------------------------------------------


@router.get("/{integration_id}/lists")
async def list_keyword_lists(
    user: CurrentOrgDep, session: SessionDep, integration_id: uuid.UUID
) -> KeywordListsOut:
    """Les listes de mots-clés déjà enregistrées dans le compte du fournisseur.

    **Aucune unité de quota consommée** (mesuré 2026-09-02) : cet appel peut être fait à chaque
    ouverture du wizard. Il reste un aller-retour vers un tiers, donc pas sur un chemin
    déclenché à chaque frappe.
    """
    items = await service.list_keyword_lists(session, user.org_id, integration_id)
    return KeywordListsOut(items=[KeywordListOut.model_validate(item) for item in items])


@router.post("/{integration_id}/lists/preview")
async def preview_lists(
    user: CurrentOrgDep,
    session: SessionDep,
    integration_id: uuid.UUID,
    payload: ListPreviewIn,
) -> ListPreviewOut:
    """Les marchés réellement présents dans les listes sélectionnées. **Rien n'est persisté.**

    `POST` parce que la sélection est un corps, comme `POST /imports/preview` du chemin CSV — et
    pour la même raison : c'est une lecture qui ne change rien, mais dont l'entrée est une liste.
    """
    items, census = await service.preview_lists(
        session, user.org_id, integration_id, payload.list_ids, payload.site_target_id
    )
    return ListPreviewOut(items=items, countries=census)


# --- dernier rapport par cible ----------------------------------------------------------------


@router.get("/{integration_id}/imports")
async def list_last_imports(
    user: CurrentOrgDep, session: SessionDep, integration_id: uuid.UUID
) -> TargetImportListOut:
    """Le dernier import API de chaque cible de l'organisation, pour ce fournisseur.

    Ne rend que les cibles qui **ont** un import : l'écran connaît déjà sa liste de cibles, et
    fabriquer ici des entrées vides ne lui apprendrait rien.
    """
    integration = await service.get_integration(session, user.org_id, integration_id)
    reports = await service.last_imports(session, user.org_id, None, integration.provider)
    return TargetImportListOut(
        items=[
            TargetImportOut(
                site_target_id=target_id, last_import=ImportSummary.model_validate(record)
            )
            for target_id, record in sorted(reports.items(), key=lambda pair: str(pair[0]))
        ]
    )


# --- plannings par cible --------------------------------------------------------------------


@router.get("/{integration_id}/schedules")
async def list_schedules(
    user: CurrentOrgDep, session: SessionDep, integration_id: uuid.UUID
) -> ScheduleListOut:
    """Le mode, la prochaine échéance et le dernier rapport, par cible (§1.11)."""
    items = await service.list_schedules(session, user.org_id, integration_id)
    integration = await service.get_integration(session, user.org_id, integration_id)
    reports = await service.last_imports(
        session, user.org_id, [item.site_target_id for item in items], integration.provider
    )
    return ScheduleListOut(
        items=[
            ScheduleOut(
                id=item.id,
                integration_id=item.integration_id,
                site_target_id=item.site_target_id,
                sync_mode=item.sync_mode,
                next_run_at=item.next_run_at,
                enabled=item.enabled,
                config=item.config,
                last_import=(
                    ImportSummary.model_validate(found)
                    if (found := reports.get(item.site_target_id)) is not None
                    else None
                ),
            )
            for item in items
        ]
    )


@router.put("/{integration_id}/schedules")
async def upsert_schedule(
    user: CurrentOrgDep,
    session: SessionDep,
    integration_id: uuid.UUID,
    payload: ScheduleUpsert,
) -> ScheduleOut:
    """Pose ou change le mode de synchro d'une cible. Idempotent : `PUT`, pas `POST`."""
    record = await service.upsert_schedule(session, user.org_id, integration_id, payload)
    return ScheduleOut.model_validate(record)


@router.delete("/{integration_id}/schedules/{schedule_id}", status_code=204)
async def delete_schedule(
    user: CurrentOrgDep,
    session: SessionDep,
    integration_id: uuid.UUID,
    schedule_id: uuid.UUID,
) -> None:
    await service.delete_schedule(session, user.org_id, integration_id, schedule_id)


# --- déclenchement manuel ---------------------------------------------------------------------


@router.post("/{integration_id}/import", status_code=202)
async def trigger_import(
    user: CurrentOrgDep,
    session: SessionDep,
    integration_id: uuid.UUID,
    payload: ImportTrigger,
) -> ImportTriggerOut:
    """« Importer maintenant » pour une cible. Deux clics ne lancent qu'un import par liste.

    Le corps porte le **mode** : `list_ids` (listes enregistrées du compte) ou `domain`
    (découverte), jamais les deux. Aucun des deux = découverte du domaine de la cible.

    **Seul `list_ids` est encore produit par un écran** (le parcours d'import de listes) : le
    bouton « Importer maintenant » des Réglages, qui envoyait `{site_target_id}` seul, a été
    supprimé le 2026-09-02. `keywords` (enrichissement) reste accepté par le schéma mais est
    refusé à l'enfilage par un 422 : il n'a aucune liste de destination où atterrir, et un
    import sans appartenance n'apparaît jamais dans le réservoir.

    En mode liste, un import est enfilé **par liste** : autant de rapports que de listes
    cochées, chacun avec son propre décompte de lignes hors cible.
    """
    launched = await service.trigger_import(
        session,
        user.org_id,
        integration_id,
        payload.site_target_id,
        domain=payload.domain,
        keywords=payload.keywords,
        list_ids=payload.list_ids,
    )
    return ImportTriggerOut(
        items=[
            ImportTriggerItem(
                import_id=record.id,
                job_id=job.id,
                created=created,
                list_id=list_id,
                list_name=list_name,
            )
            for record, job, created, list_id, list_name in launched
        ]
    )


@router.get("/{integration_id}/quota")
async def read_quota(
    user: CurrentOrgDep, session: SessionDep, integration_id: uuid.UUID
) -> QuotaOut:
    """Le reste de quota du fournisseur — ce que le récapitulatif d'un import API annonce.

    L'appel sous-jacent (`GET /kwfinder/limits`) est **gratuit** : il ne consomme aucune unité.
    Il reste un aller-retour vers un tiers, donc à appeler une fois à l'ouverture du
    récapitulatif, jamais sur un chemin déclenché à chaque frappe.
    """
    integration = await service.get_integration(session, user.org_id, integration_id)
    limit, remaining, error = await service.read_quota(session, user.org_id, integration_id)
    return QuotaOut(
        provider=integration.provider,
        resource=mangools_api.QUOTA_RESOURCE,
        limit=limit,
        remaining=remaining,
        error=error,
    )
