"""Load a request-scoped Forms runtime snapshot from installed composition."""
from __future__ import annotations

import json
from uuid import UUID

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from src.domain.app_blocks.canonical import FORM_RUNTIME_BY_BLOCK
from src.domain.app_blocks.forms_binding import sources_from_plan_and_packs
from src.domain.app_blocks.planner import source_prompt_from_discovery
from src.domain.app_blocks.schemas import AppBlockPlan
from src.domain.codegen.composition_manifest import render_core_composition_files
from src.domain.codegen.models import CodegenRun
from src.domain.feature_packs.models import ProjectFeaturePack
from src.domain.forms.composition import (
    CompositionFormRuntimeStore,
    InstalledPackView,
    resolve_form_bindings,
)
from src.domain.projects.discovery_repository import DiscoveryRepository


async def load_composition_form_store(
    db: AsyncSession, project_id: UUID
) -> CompositionFormRuntimeStore:
    packs = await _installed_packs(db, project_id)
    generation_plan = await _latest_generation_plan(db, project_id)
    packs = _with_plan_form_definitions(packs, generation_plan)
    plan = await _app_block_plan(db, project_id)
    sources = sources_from_plan_and_packs(plan, packs)
    resolution = resolve_form_bindings(sources)
    return CompositionFormRuntimeStore(str(project_id), resolution)


def _with_plan_form_definitions(
    packs: tuple[InstalledPackView, ...], generation_plan: dict | None
) -> tuple[InstalledPackView, ...]:
    """Make Core's completed form definitions callable on the installed pack.

    Pack config remains authoritative when it already has a key. Definitions
    that exist only on the GenerationPlan are added so a migrated app can
    submit them without a second manual pack edit.
    """
    raw = ((generation_plan or {}).get("composition") or {}).get("form_definitions")
    if not isinstance(raw, dict) or not raw:
        return packs
    updated: list[InstalledPackView] = []
    for pack in packs:
        if pack.slug != "contact-capture":
            updated.append(pack)
            continue
        config = dict(pack.config)
        existing = dict(config.get("form_definitions") or {})
        for key, value in raw.items():
            if isinstance(key, str) and isinstance(value, dict) and key not in existing:
                existing[key] = value
        config["form_definitions"] = existing
        updated.append(
            InstalledPackView(slug=pack.slug, status=pack.status, config=config)
        )
    return tuple(updated)


async def _installed_packs(
    db: AsyncSession, project_id: UUID
) -> tuple[InstalledPackView, ...]:
    rows = (
        await db.execute(
            select(ProjectFeaturePack).where(ProjectFeaturePack.project_id == project_id)
        )
    ).scalars().all()
    return tuple(
        InstalledPackView(
            slug=row.pack_slug,
            status=row.status,
            config=row.config or {},
        )
        for row in rows
    )


async def _app_block_plan(db: AsyncSession, project_id: UUID):
    # A completed GenerationPlan is the authoritative composition selected for
    # the deployed app. Discovery remains the compatibility fallback for older
    # projects that predate plan-first codegen or have no completed run yet.
    generation_plan = await _latest_generation_plan(db, project_id)
    if generation_plan is not None:
        try:
            projected = render_core_composition_files(generation_plan)
            candidate = AppBlockPlan.model_validate(
                json.loads(projected["p2hs/app-blocks-plan.json"])
            )
            # A legacy/direct-edit run may have completed without carrying the
            # form selection even though Discovery contains an explicit form
            # request. Let the Discovery projection repair that stale plan;
            # otherwise the generated quote UI is permanently unbound.
            if any(block.id in FORM_RUNTIME_BY_BLOCK for block in candidate.blocks):
                return candidate
        except (TypeError, ValueError, KeyError):
            # Do not make a malformed historical plan take down the public
            # Forms route; use the legacy Discovery projection instead.
            pass

    project = await DiscoveryRepository(db).get(project_id)
    if project is None:
        return None
    spec = ((project.discovery_json or {}).get("result") or {}).get("spec")
    if not spec:
        return None
    from src.domain.composition_recipes.compile import compile_pinned_install_plan

    return 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),
    )


async def _latest_generation_plan(
    db: AsyncSession, project_id: UUID
) -> dict | None:
    result = await db.execute(
        select(CodegenRun.plan)
        .where(
            CodegenRun.project_id == project_id,
            CodegenRun.status.in_(
                ("completed", "completed_with_limitations", "completed_with_l3")
            ),
        )
        .order_by(CodegenRun.created_at.desc())
        .limit(10)
    )
    # Some compatibility repositories expose only a scalar result for this
    # optional historical lookup. Treat that as "no completed plan" and use
    # the existing Discovery/installed-pack fallback below; real SQLAlchemy
    # results always provide ``all``.
    rows = result.all() if hasattr(result, "all") else ()
    for (plan,) in rows:
        if not isinstance(plan, dict):
            continue
        generation_plan = plan.get("generation_plan")
        if isinstance(generation_plan, dict):
            return generation_plan
        request = plan.get("codegen_request")
        if isinstance(request, dict):
            generation_plan = request.get("generation_plan")
            if isinstance(generation_plan, dict):
                return generation_plan
    return None
