"""Resolve App Block pack policy for a codegen run from Core state."""

from uuid import UUID

from sqlalchemy import func, select

from src.domain.app_blocks.adoption import (
    COMPLETED_CODEGEN,
    adoption_for,
    apply_adoption,
    install_and_protect_packs,
)
from src.domain.app_blocks.compiler import compile_install_plan
from src.domain.app_blocks.execution import assert_install_plan_installable
from src.domain.app_blocks.planner import source_prompt_from_discovery
from src.domain.app_blocks.schemas import AppBlockPlan
from src.domain.codegen.models import CodegenRun
from src.domain.feature_packs.models import ProjectFeaturePack
from src.domain.projects.discovery_repository import DiscoveryRepository

_CALLABLE_PACK_STATUSES = frozenset(
    {
        "installed",
        "configuration_required",
        "configured",
        "deployed",
        "verified",
        "enabled",
        "supported",
    }
)


def assert_discovery_installable(discovery_json: dict | None, *, composition_recipe=None) -> None:
    """Preflight Core Discovery state at an execution orchestrator, not in planning."""
    spec = ((discovery_json or {}).get("result") or {}).get("spec")
    if spec:
        assert_install_plan_installable(
            compile_install_plan(
                spec,
                source_prompt=source_prompt_from_discovery(discovery_json),
                composition_recipe=composition_recipe,
            )
        )


async def resolve_pack_policy(
    db, project_id: UUID, *, run_id: UUID | None = None
) -> tuple[str, list[str], list[str]]:
    """Return (adoption, install_slugs, protect_slugs).

    An in-flight run that already reconciled composition is the install source.
    The last completed plan is the fallback when this run has no plan yet.
    """
    project = await DiscoveryRepository(db).get(project_id)
    if not project:
        return "advisory", [], []
    completed = await db.scalar(
        select(func.count())
        .select_from(CodegenRun)
        .where(
            CodegenRun.project_id == project_id,
            CodegenRun.status.in_(tuple(COMPLETED_CODEGEN)),
        )
    )
    adoption = adoption_for(
        source_kind=project.source_kind or "generated",
        completed_codegen=bool(completed),
    )
    # This run's reconciled plan is the composition about to be generated.
    # Otherwise the latest completed GenerationPlan is the installed baseline.
    # Discovery alone can be an older paraphrase and must not drop required packs.
    generation_plan = await _run_generation_plan(db, run_id)
    if generation_plan is None:
        generation_plan = await _latest_generation_plan(db, project_id)
    if generation_plan:
        from src.domain.codegen.composition_manifest import render_core_composition_files

        try:
            projected = render_core_composition_files(generation_plan)
            plan = AppBlockPlan.model_validate_json(projected["p2hs/app-blocks-plan.json"])
            plan = apply_adoption(plan, adoption)
        except (KeyError, TypeError, ValueError):
            plan = None
    else:
        plan = None

    if plan is None:
        spec = ((project.discovery_json or {}).get("result") or {}).get("spec")
        if not spec:
            return adoption, [], []
        from src.domain.composition_recipes.compile import compile_pinned_install_plan

        plan = apply_adoption(
            await compile_pinned_install_plan(
                db,
                project.discovery_json,
                spec,
                source_prompt=source_prompt_from_discovery(project.discovery_json),
                project_type=getattr(project, "type", None),
            ),
            adoption,
        )

    install_slugs, protect_slugs = install_and_protect_packs(plan)
    if adoption == "advisory" and protect_slugs:
        installed = await db.execute(
            select(ProjectFeaturePack.pack_slug, ProjectFeaturePack.status).where(
                ProjectFeaturePack.project_id == project_id,
                ProjectFeaturePack.pack_slug.in_(protect_slugs),
            )
        )
        callable_slugs = {
            slug for slug, status in installed.all() if status in _CALLABLE_PACK_STATUSES
        }
        # Advisory adoption preserves healthy installs, but repairs a required
        # pack missed by an earlier generation attempt.
        install_slugs = [slug for slug in protect_slugs if slug not in callable_slugs]
    return plan.adoption, install_slugs, protect_slugs


async def _run_generation_plan(db, run_id: UUID | None) -> dict | None:
    if run_id is None:
        return None
    from src.domain.codegen.repository import CodegenRunRepository

    run = await CodegenRunRepository(db).get_by_id(run_id)
    if run is None or not isinstance(run.plan, dict):
        return None
    generation_plan = run.plan.get("generation_plan")
    if isinstance(generation_plan, dict):
        return generation_plan
    return None


async def _latest_generation_plan(db, project_id: UUID) -> dict | None:
    rows = (
        await db.execute(
            select(CodegenRun.plan)
            .where(
                CodegenRun.project_id == project_id,
                CodegenRun.status.in_(tuple(COMPLETED_CODEGEN)),
            )
            .order_by(CodegenRun.created_at.desc())
            .limit(20)
        )
    ).all()
    chosen: dict | None = None
    chosen_at = ""
    for (plan,) in rows:
        if not isinstance(plan, dict):
            continue
        generation_plan = plan.get("generation_plan")
        if not isinstance(generation_plan, dict):
            request = plan.get("codegen_request")
            if isinstance(request, dict) and isinstance(request.get("generation_plan"), dict):
                generation_plan = request["generation_plan"]
            else:
                continue
        compiled_at = str((generation_plan.get("provenance") or {}).get("compiled_at") or "")
        if chosen is None or compiled_at > chosen_at:
            chosen = generation_plan
            chosen_at = compiled_at
    return chosen
