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 DocUpdateFromFeatureV2WorkflowGraph(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)
        requirements = list(getattr(context, "requirements", []) or [])
        tasks = list(getattr(context, "requirement_tasks", []) or [])
        rules = list(getattr(context, "rules", []) or [])
        changeset = list(getattr(context, "changeset", []) or [])
        issues = list(getattr(context, "issues", []) or [])
        accumulated = list(getattr(context, "accumulated_pages", []) 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 ""),
            "source_content_len": len(str(getattr(context, "source_content", "") or "")),
            "analysis_id": str(getattr(analytics, "analysis_id", "") or ""),
            "application": str(getattr(analytics, "application", "") or ""),
            "platform": str(getattr(analytics, "platform", "") or ""),
            "domain": str(getattr(analytics, "domain", "") or ""),
            "sub_domain": str(getattr(analytics, "subdomain", "") or ""),
            "requirements_count": len(requirements),
            "requirements_preview": [
                {
                    "section_key": str(getattr(item, "section_key", "") or ""),
                    "heading": str(getattr(item, "heading", "") or ""),
                }
                for item in requirements[:6]
            ],
            "docs_rows_count": len(list(getattr(context, "docs_catalog_rows", []) or [])),
            "tasks_count": len(tasks),
            "tasks_preview": [
                {
                    "section_key": str(getattr(item, "section_key", "") or ""),
                    "action": str(getattr(getattr(item, "action", None), "value", "") or ""),
                    "path": str(getattr(item, "path", "") or ""),
                    "doc_type": str(getattr(item, "doc_type", "") or ""),
                    "platform": str(getattr(item, "platform", "") or ""),
                }
                for item in tasks[:8]
            ],
            "rules_count": len(rules),
            "rule_names_preview": [str(getattr(item, "name", "") or "") for item in rules[:8]],
            "changeset_count": len(changeset),
            "changeset_preview": [
                {
                    "op": str(getattr(item, "op", "") or ""),
                    "path": str(getattr(item, "path", "") or ""),
                }
                for item in changeset[:8]
            ],
            "accumulated_pages_count": len(accumulated),
            "accumulated_pages_preview": [
                {
                    "path": str(getattr(item, "path", "") or ""),
                    "action": str(getattr(getattr(item, "action", None), "value", "") or ""),
                }
                for item in accumulated[:8]
            ],
            "apply_changeset": bool(getattr(context, "apply_changeset", False)),
            "answer_len": len(str(getattr(context, "answer", "") or "")),
            "issues_count": len(issues),
            "issues_preview": [str(item) for item in issues[:8]],
        }
