from __future__ import annotations

from typing import Protocol

from app.schemas.changeset import ChangeItem, ChangeOp


class SessionArtifactWriter(Protocol):
    def add_session_artifact(self, **kwargs) -> None: ...


class StorySessionRecorder:
    def __init__(self, repository: SessionArtifactWriter) -> None:
        self._repo = repository

    def record_run(
        self,
        *,
        dialog_session_id: str,
        rag_session_id: str,
        scenario: str,
        attachments: list[dict],
        answer: str | None,
        changeset: list[ChangeItem],
        actor: str | None = None,
    ) -> None:
        self._record_input_sources(
            session_id=dialog_session_id,
            project_id=rag_session_id,
            attachments=attachments,
            actor=actor,
        )
        self._record_outputs(
            session_id=dialog_session_id,
            project_id=rag_session_id,
            scenario=scenario,
            answer=answer,
            changeset=changeset,
            actor=actor,
        )

    def _record_input_sources(self, *, session_id: str, project_id: str, attachments: list[dict], actor: str | None) -> None:
        for item in attachments:
            value = str(item.get("value") or "").strip()
            if not value:
                continue
            if item.get("type") not in {"confluence_url", "http_url"}:
                continue
            self._repo.add_session_artifact(
                session_id=session_id,
                project_id=project_id,
                artifact_role="analysis",
                source_ref=value,
                summary="Input analytics document",
                change_type="linked",
                created_by=actor,
            )

    def _record_outputs(
        self,
        *,
        session_id: str,
        project_id: str,
        scenario: str,
        answer: str | None,
        changeset: list[ChangeItem],
        actor: str | None,
    ) -> None:
        role = self._role_for_scenario(scenario)
        if answer and answer.strip():
            self._repo.add_session_artifact(
                session_id=session_id,
                project_id=project_id,
                artifact_role=role,
                summary=answer.strip()[:4000],
                created_by=actor,
            )

        for item in changeset:
            self._repo.add_session_artifact(
                session_id=session_id,
                project_id=project_id,
                artifact_role=role,
                path=item.path,
                summary=item.reason,
                change_type=self._change_type(item.op),
                created_by=actor,
            )

    def _role_for_scenario(self, scenario: str) -> str:
        mapping = {
            "docs_from_analytics": "doc_change",
            "targeted_edit": "doc_change",
            "gherkin_model": "test_model",
            "analytics_review": "analysis",
            "explain_part": "note",
            "general_qa": "note",
        }
        return mapping.get(scenario, "note")

    def _change_type(self, op: ChangeOp) -> str:
        if op == ChangeOp.CREATE:
            return "added"
        if op == ChangeOp.DELETE:
            return "removed"
        return "updated"
