import pytest
from qdrant_client.http import models

from app.models.embedding_record import EmbeddingRecord
from app.models.enums import ChunkType, SourceType
from app.qdrant import bootstrap, point_id, payload


def test_qdrant_point_id_is_stable():
    first = point_id.qdrant_point_id("emb_chk_sym_config_go_Load")
    second = point_id.qdrant_point_id("emb_chk_sym_config_go_Load")
    assert first == second
    assert len(first) == 36


def test_qdrant_point_id_differs_by_record():
    a = point_id.qdrant_point_id("emb_record_a")
    b = point_id.qdrant_point_id("emb_record_b")
    assert a != b


def test_qdrant_point_id_rejects_empty():
    with pytest.raises(ValueError):
        point_id.qdrant_point_id("   ")


def test_embedding_record_to_qdrant_payload():
    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() {}",
        file_path="internal/config/config.go",
        symbol_name="Load",
        start_line=1,
        end_line=2,
        graph_node_id="sym_config_go_Load",
        language="go",
        symbol_type="function",
    )

    result = payload.embedding_record_to_qdrant_payload(record)

    assert result["record_id"] == "emb_chk_sym_config_go_Load"
    assert result["repo_id"] == "AD/example-repo"
    assert result["snapshot_id"] == "snap_abc123"
    assert result["source_type"] == SourceType.CODE.value
    assert result["chunk_type"] == ChunkType.SYMBOL.value
    assert result["file_path"] == "internal/config/config.go"
    assert result["graph_node_id"] == "sym_config_go_Load"
    assert result["start_line"] == 1
    assert result["end_line"] == 2


class _FakeCollectionInfo:
    def __init__(self, size: int, distance=models.Distance.COSINE):
        self.config = type(
            "Cfg",
            (),
            {"params": type("Params", (), {"vectors": models.VectorParams(size=size, distance=distance)})()},
        )()


class _FakeQdrantClient:
    def __init__(self):
        self.collections: list[str] = []
        self.payload_indexes: list[tuple[str, str]] = []
        self.created = False

    def get_collections(self):
        return type(
            "Resp",
            (),
            {"collections": [type("C", (), {"name": n})() for n in self.collections]},
        )()

    def get_collection(self, name):
        return _FakeCollectionInfo(size=1536)

    def create_collection(self, collection_name, vectors_config):
        self.collections.append(collection_name)
        self.created = True

    def create_payload_index(self, collection_name, field_name, field_schema):
        self.payload_indexes.append((collection_name, field_name))


def test_bootstrap_creates_collection_and_indexes():
    fake = _FakeQdrantClient()
    name = bootstrap.bootstrap_qdrant(fake)

    assert name == bootstrap.settings.QDRANT_COLLECTION_NAME
    assert fake.created is True
    assert fake.collections == [bootstrap.settings.QDRANT_COLLECTION_NAME]
    indexed_fields = {field for _, field in fake.payload_indexes}
    assert "repo_id" in indexed_fields
    assert "snapshot_id" in indexed_fields


def test_bootstrap_validates_existing_collection_size(monkeypatch):
    fake = _FakeQdrantClient()
    fake.collections = [bootstrap.settings.QDRANT_COLLECTION_NAME]

    def _bad_info(_name):
        return _FakeCollectionInfo(size=999)

    fake.get_collection = _bad_info

    with pytest.raises(bootstrap.QdrantBootstrapError, match="vector size"):
        bootstrap.bootstrap_qdrant(fake)
