import json

import pytest
from pydantic import ValidationError

from app.models.embedding_record import (
    EmbeddingRecord,
    embedding_record_id_for_analysis,
    embedding_record_id_for_chunk,
)
from app.models.enums import ChunkType, SourceType
from app.models.mongo_ref import parse_mongo_uri
from app.models.validation import (
    parse_commit_analysis_ready,
    parse_graph_artifact_ready,
    parse_stream_payload,
    validate_embedding_record,
)


def test_code_embedding_record_from_pipeline_example():
    record = EmbeddingRecord.from_code_chunk(
        record_id="emb_chk_sym_config_go_Load",
        repo_id="AD/example-repo",
        snapshot_id="snap_abc123",
        commit_sha="a1b2c3d4e5f6",
        text="func Load(path string) (*Config, error) { ... }",
        file_path="internal/config/config.go",
        symbol_name="Load",
        start_line=24,
        end_line=58,
        graph_node_id="sym_config_go_Load",
        artifact_uri="mongo://snapshot_graphs/art_snap_abc123_merged",
        language="go",
        symbol_type="function",
    )

    assert record.source_type == SourceType.CODE
    assert record.chunk_type == ChunkType.SYMBOL
    assert record.file_path == "internal/config/config.go"
    assert record.doc_path is None


def test_docs_embedding_record_from_pipeline_example():
    record = EmbeddingRecord.from_doc_chunk(
        record_id="emb_chk_ad_example_repo_docs_arch_abc123",
        repo_id="AD/example-repo",
        snapshot_id="snap_abc123",
        commit_sha="a1b2c3d4e5f6",
        text="The service exposes a REST API on port 6001.",
        doc_path="docs/architecture.md",
        section_title="Overview",
        graph_node_id="doc_chunk_chk_ad_example_repo_docs_arch_abc123",
        section_level=2,
    )

    assert record.source_type == SourceType.DOCS
    assert record.chunk_type == ChunkType.TEXT
    assert record.file_path is None


def test_commit_embedding_record_from_pipeline_example():
    record = EmbeddingRecord.from_commit_analysis(
        record_id="emb_analysis_b2c3d4",
        repo_id="AD/example-repo",
        snapshot_id="snap_abc123",
        commit_sha="b2c3d4e5f6a7",
        text="Introduced Reload and refactored configuration loading.",
        impacted_symbols=["Load", "Reload"],
        changed_files=["internal/config/config.go"],
    )

    assert record.source_type == SourceType.COMMIT
    assert record.chunk_type == ChunkType.SUMMARY
    assert record.metadata.impacted_symbols == ["Load", "Reload"]


def test_rejects_empty_text():
    with pytest.raises(ValidationError):
        EmbeddingRecord.from_doc_chunk(
            record_id="emb_x",
            repo_id="AD/example-repo",
            snapshot_id="snap_abc123",
            commit_sha="a1b2c3d4e5f6",
            text="   ",
            doc_path="docs/architecture.md",
            section_title="Overview",
            graph_node_id="doc_chunk_x",
        )


def test_rejects_code_record_without_symbol_name():
    with pytest.raises(ValidationError):
        EmbeddingRecord.model_validate(
            {
                "record_id": "emb_x",
                "repo_id": "AD/example-repo",
                "snapshot_id": "snap_abc123",
                "source_type": "code",
                "chunk_type": "symbol",
                "text": "func main() {}",
                "file_path": "main.go",
            }
        )


def test_parse_graph_artifact_ready_event():
    payload = json.dumps(
        {
            "event_id": "evt_snap_abc123_graph_ready",
            "event_version": "v1",
            "repo_id": "AD/example-repo",
            "snapshot_id": "snap_abc123",
            "commit_sha": "a1b2c3d4e5f6",
            "artifact_id": "art_snap_abc123_merged",
            "artifact_uri": "mongo://snapshot_graphs/art_snap_abc123_merged",
            "node_count": 1240,
            "edge_count": 3180,
        }
    )

    event = parse_graph_artifact_ready(payload)
    assert event.snapshot_id == "snap_abc123"
    ref = event.artifact_ref()
    assert ref.collection == "snapshot_graphs"
    assert ref.document_id == "art_snap_abc123_merged"


def test_parse_commit_analysis_ready_event():
    payload = {
        "payload": json.dumps(
            {
                "event_id": "evt_analysis_01",
                "event_version": "v1",
                "repo_id": "AD/example-repo",
                "commit_sha": "b2c3d4e5f6a7",
                "analysis_id": "analysis_b2c3d4",
                "summary": "Introduced Reload",
                "impacted_symbols": ["Load", "Reload"],
                "changed_files": ["internal/config/config.go"],
            }
        )
    }

    event = parse_commit_analysis_ready(payload)
    assert event.analysis_id == "analysis_b2c3d4"
    assert event.impacted_symbols == ["Load", "Reload"]


def test_parse_stream_payload_rejects_invalid_json():
    with pytest.raises(ValueError, match="not valid JSON"):
        parse_stream_payload("{not-json")


def test_parse_mongo_uri():
    ref = parse_mongo_uri("mongo://graph_deltas/delta_b2c3d4")
    assert ref.uri == "mongo://graph_deltas/delta_b2c3d4"


def test_embedding_record_id_helpers():
    assert embedding_record_id_for_chunk("chk_sym_Load") == "emb_chk_sym_Load"
    assert embedding_record_id_for_chunk("emb_chk_sym_Load") == "emb_chk_sym_Load"
    assert embedding_record_id_for_analysis("analysis_b2c3d4") == "emb_analysis_b2c3d4"


def test_validate_embedding_record_dict():
    record = validate_embedding_record(
        {
            "record_id": "emb_analysis_b2c3d4",
            "repo_id": "AD/example-repo",
            "snapshot_id": "snap_abc123",
            "commit_sha": "b2c3d4e5f6a7",
            "source_type": "commit",
            "chunk_type": "summary",
            "text": "Summary text",
        }
    )
    assert record.source_type == SourceType.COMMIT
