"""Buffered graph for DOC_UPDATE/FROM_FEATURE workflow."""

from __future__ import annotations

from typing import TypeVar

from app.core.agent.utils.workflow.context import WorkflowContext
from app.core.agent.utils.workflow.graph import WorkflowGraph

TContext = TypeVar("TContext", bound=WorkflowContext)


class DocUpdateFromFeatureWorkflowGraph(WorkflowGraph[TContext]):
    async def run(self, context: TContext) -> TContext:
        trace = context.runtime.trace.module(self._source)
        trace.log("workflow_started", {"workflow_id": self._workflow_id})
        steps_buffer: list[dict[str, object]] = []
        for step in self._steps:
            before = self._snapshot(context)
            raw_inp = step.trace_input(context)
            inp = self._merge_trace_payload(raw_inp, before)
            request_id = context.runtime.request.request_id
            await context.runtime.publisher.publish_status(
                request_id,
                self._source,
                f"Шаг workflow: {step.title}.",
                {"workflow_id": self._workflow_id, "step_id": step.step_id},
            )
            context = await step.run(context)
            after = self._snapshot(context)
            raw_out = step.trace_output(context)
            out = self._merge_trace_payload(raw_out, after)
            trace.log(
                "workflow_step_traced",
                {
                    "workflow_id": self._workflow_id,
                    "step": {"id": step.step_id, "title": step.title},
                    "input": inp,
                    "output": out,
                },
            )
            steps_buffer.append({"step_id": step.step_id, "title": step.title, "input": inp, "output": out})
        trace.log("workflow_trace_flushed", {"workflow_id": self._workflow_id, "steps": steps_buffer})
        trace.log("workflow_completed", {"workflow_id": self._workflow_id})
        return context

    def _merge_trace_payload(self, payload: dict[str, object] | None, snapshot: dict[str, object]) -> dict[str, object]:
        if not payload:
            return snapshot
        merged = dict(payload)
        merged["_context"] = snapshot
        return merged

    def _snapshot(self, context: TContext) -> dict[str, object]:
        analytics = getattr(context, "analytics_meta", None)
        units = list(getattr(context, "units", []) or [])
        planned = list(getattr(context, "planned_changes", []) or [])
        changeset = list(getattr(context, "changeset", []) or [])
        bundle = getattr(context, "doc_rules_bundle", None)
        issue_items = list(getattr(context, "issues", []) or [])
        return {
            "source_kind": str(getattr(context, "source_kind", "") or ""),
            "source_ref": str(getattr(context, "source_ref", "") or ""),
            "project_root": str(getattr(context, "project_root", "") or ""),
            "feature_content_len": len(str(getattr(context, "feature_content", "") or "")),
            "analysis_id": str(getattr(analytics, "analysis_id", "") or ""),
            "application": str(getattr(analytics, "application", "") or ""),
            "platform": str(getattr(analytics, "platform", "") or ""),
            "domains": list(getattr(analytics, "domains", []) or []),
            "subdomains": list(getattr(analytics, "subdomains", []) or []),
            "units_count": len(units),
            "unit_headings": [str(getattr(unit, "heading", "")) for unit in units[:5]],
            "docs_rows_count": len(list(getattr(context, "docs_catalog_rows", []) or [])),
            "doc_rules_enabled": bool(getattr(context, "doc_rules_enabled", False)),
            "doc_rules_loaded": bundle is not None,
            "doc_rules_supported_types": sorted(list(getattr(bundle, "supported_doc_types", set()) or set())),
            "planned_changes_count": len(planned),
            "planned_changes_preview": [
                {
                    "op": str(getattr(item, "op", "") or ""),
                    "path": str(getattr(item, "path", "") or ""),
                    "doc_type": str(getattr(item, "doc_type", "") or ""),
                }
                for item in planned[:5]
            ],
            "changeset_count": len(changeset),
            "changeset_preview": [
                {
                    "op": str(getattr(item, "op", "") or ""),
                    "path": str(getattr(item, "path", "") or ""),
                }
                for item in changeset[:5]
            ],
            "apply_changeset": bool(getattr(context, "apply_changeset", False)),
            "answer_len": len(str(getattr(context, "answer", "") or "")),
            "issues_count": len(issue_items),
            "issues_preview": [str(value) for value in issue_items[:5]],
        }
