from __future__ import annotations

from hashlib import sha256

from app.modules.rag.contracts import EvidenceLink, EvidenceType, RagDocument, RagLayer, RagSource
from app.modules.rag.indexing.docs.chunkers.markdown_chunker import SectionChunk
from app.modules.rag.indexing.docs.models import RelationEdge, WorkflowScenario


class DocsDocumentBuilder:
    def build_document_catalog(self, source: RagSource, frontmatter: dict, summary_text: str, doc_kind: str, *, fallback_title: str) -> RagDocument:
        document_id = str(frontmatter.get("id") or source.path).strip()
        metadata = {
            "document_id": document_id,
            "type": str(frontmatter.get("type") or "").strip(),
            "name": str(frontmatter.get("name") or "").strip(),
            "title": str(frontmatter.get("title") or "").strip() or fallback_title,
            "module": str(frontmatter.get("module") or frontmatter.get("domain") or "").strip(),
            "layer": str(frontmatter.get("layer") or "").strip(),
            "status": frontmatter.get("status"),
            "updated_at": frontmatter.get("updated_at"),
            "tags": frontmatter.get("tags") or [],
            "entities": frontmatter.get("entities") or [],
            "parent": frontmatter.get("parent"),
            "children": frontmatter.get("children") or [],
            "links": frontmatter.get("links") or [],
            "source_path": source.path,
            "summary_text": summary_text[:4000],
            "doc_kind": doc_kind,
        }
        return RagDocument(
            layer=RagLayer.DOCS_DOCUMENT_CATALOG,
            source=source,
            title=metadata["title"] or document_id,
            text=summary_text[:4000] or metadata["title"] or document_id,
            metadata=metadata,
        )

    def build_doc_chunk(self, source: RagSource, chunk: SectionChunk, frontmatter: dict, doc_kind: str) -> RagDocument:
        document_id = str(frontmatter.get("id") or source.path)
        metadata = {
            "document_id": document_id,
            "type": frontmatter.get("type"),
            "module": frontmatter.get("module") or frontmatter.get("domain"),
            "tags": frontmatter.get("tags") or [],
            "section_path": chunk.section_path,
            "section_title": chunk.section_title,
            "order": chunk.order,
            "doc_kind": doc_kind,
            "source_path": source.path,
            "artifact_type": "DOCS",
        }
        return RagDocument(
            layer=RagLayer.DOCS_DOC_CHUNKS,
            source=source,
            title=f"{document_id}:{chunk.section_title}",
            text=chunk.content,
            metadata=metadata,
            links=[EvidenceLink(type=EvidenceType.DOC_SECTION, target_id=document_id, path=source.path, note=chunk.section_path)],
        )

    def build_entity_record(self, source: RagSource, frontmatter: dict, entity: str) -> RagDocument:
        document_id = str(frontmatter.get("id") or source.path)
        metadata = {
            "entity_name": entity,
            "document_id": document_id,
            "document_type": frontmatter.get("type"),
            "module": frontmatter.get("module") or frontmatter.get("domain"),
            "tags": frontmatter.get("tags") or [],
            "source_path": source.path,
        }
        return RagDocument(
            layer=RagLayer.DOCS_ENTITY_CATALOG,
            source=source,
            title=entity,
            text=entity,
            metadata=metadata,
        )

    def build_fact(
        self,
        source: RagSource,
        *,
        subject_id: str,
        predicate: str,
        obj: str,
        object_ref: str | None,
        anchor: str,
        tags: list[str] | None = None,
    ) -> RagDocument:
        fact_id = sha256(f"{subject_id}|{predicate}|{obj}|{source.path}|{anchor}".encode("utf-8")).hexdigest()
        metadata = {
            "fact_id": fact_id,
            "subject_id": subject_id,
            "predicate": predicate,
            "object": obj,
            "object_ref": object_ref,
            "anchor": anchor,
            "tags": tags or [],
            "source_path": source.path,
        }
        return RagDocument(
            layer=RagLayer.DOCS_FACT_INDEX,
            source=source,
            title=f"{subject_id}:{predicate}",
            text=f"{subject_id} {predicate} {obj}".strip(),
            metadata=metadata,
            links=[EvidenceLink(type=EvidenceType.DOC_FACT, target_id=fact_id, path=source.path, note=anchor)],
        )

    def build_workflow_record(self, source: RagSource, frontmatter: dict, workflow: WorkflowScenario) -> RagDocument:
        document_id = str(frontmatter.get("id") or source.path)
        workflow_id = sha256(f"{document_id}|workflow|{workflow.name}|{workflow.anchor}".encode("utf-8")).hexdigest()
        metadata = {
            "workflow_id": workflow_id,
            "document_id": document_id,
            "workflow_name": workflow.name,
            "preconditions": workflow.preconditions,
            "trigger": workflow.trigger,
            "main_flow": workflow.main_flow,
            "alternative_flow": workflow.alternative_flow,
            "error_handling": workflow.error_handling,
            "postconditions": workflow.postconditions,
            "source_path": source.path,
        }
        text = "\n".join(
            [workflow.name, *workflow.preconditions, *workflow.trigger, *workflow.main_flow, *workflow.alternative_flow]
        ).strip()
        return RagDocument(
            layer=RagLayer.DOCS_WORKFLOW_INDEX,
            source=source,
            title=workflow.name,
            text=text[:4000],
            metadata=metadata,
        )

    def build_relation_record(self, source: RagSource, edge: RelationEdge) -> RagDocument:
        relation_id = sha256(f"{edge.source_id}|{edge.relation_type}|{edge.target_id}|{source.path}|{edge.anchor}".encode("utf-8")).hexdigest()
        metadata = {
            "relation_id": relation_id,
            "source_id": edge.source_id,
            "relation_type": edge.relation_type,
            "target_id": edge.target_id,
            "anchor": edge.anchor,
            "source_path": source.path,
        }
        return RagDocument(
            layer=RagLayer.DOCS_RELATION_GRAPH,
            source=source,
            title=f"{edge.source_id}:{edge.relation_type}",
            text=f"{edge.source_id} {edge.relation_type} {edge.target_id}",
            metadata=metadata,
        )
