from __future__ import annotations

from app.modules.agent.engine.orchestrator.execution_context import ExecutionContext
from app.modules.agent.engine.orchestrator.models import OrchestratorResult, StepResult
from app.modules.agent.engine.orchestrator.quality_metrics import QualityMetricsCalculator
from app.schemas.changeset import ChangeItem


class ResultAssembler:
    def __init__(self, quality: QualityMetricsCalculator | None = None) -> None:
        self._quality = quality or QualityMetricsCalculator()

    def assemble(self, ctx: ExecutionContext, step_results: list[StepResult]) -> OrchestratorResult:
        answer = str(ctx.artifacts.get_content("final_answer", "") or "").strip() or None
        raw_changeset = ctx.artifacts.get_content("final_changeset", []) or []
        changeset = self._normalize_changeset(raw_changeset)
        quality = self._quality.build(ctx, step_results)

        meta = {
            "scenario": ctx.task.scenario.value,
            "plan": {
                "plan_id": ctx.plan.plan_id,
                "template_id": ctx.plan.template_id,
                "template_version": ctx.plan.template_version,
                "status": ctx.plan.status.value,
            },
            "route": {
                "domain_id": ctx.task.routing.domain_id,
                "process_id": ctx.task.routing.process_id,
                "confidence": ctx.task.routing.confidence,
                "reason": ctx.task.routing.reason,
                "fallback_used": ctx.task.routing.fallback_used,
            },
            "orchestrator": {
                "steps_total": len(ctx.plan.steps),
                "steps_success": len([step for step in step_results if step.status.value == "success"]),
            },
            "quality": quality,
        }
        return OrchestratorResult(answer=answer, changeset=changeset, meta=meta, steps=step_results)

    def _normalize_changeset(self, value) -> list[ChangeItem]:
        if not isinstance(value, list):
            return []
        items: list[ChangeItem] = []
        for raw in value:
            if isinstance(raw, ChangeItem):
                items.append(raw)
                continue
            if isinstance(raw, dict):
                try:
                    items.append(ChangeItem.model_validate(raw))
                except Exception:
                    continue
        return items
