import uuid

import pytest


class FakeResult:
    def __init__(self, records=None):
        self.records = records or []

    def __iter__(self):
        return iter(self.records)

    def single(self):
        return self.records[0] if self.records else None


class FakeGraphSession:
    def __init__(self, records=None):
        self.records = records or []
        self.calls = []

    def run(self, query, parameters=None, **kwargs):
        values = parameters or kwargs
        self.calls.append((query, values))
        return FakeResult(self.records)

    @property
    def last_parameters(self):
        return self.calls[-1][1]


def test_definition_repository_assigns_uid_and_excludes_secrets():
    from app.core.data_source.definitions import (
        DataSourceDefinitionRepository,
    )
    from app.core.data_source.models import DataSourceDefinition

    graph = FakeGraphSession(
        records=[
            {
                "properties": {
                    "uid": "placeholder",
                    "name_en": "warehouse",
                    "type": "postgresql",
                    "host": "source-postgres",
                    "port": 5432,
                    "database": "analytics",
                    "schema": "public",
                    "credential_ref": (
                        "01900000-0000-7000-8000-000000000011"
                    ),
                    "credential_version": 1,
                }
            }
        ]
    )
    repository = DataSourceDefinitionRepository(graph)
    definition = DataSourceDefinition(
        uid=None,
        name_en="warehouse",
        database_type="postgresql",
        host="source-postgres",
        port=5432,
        database="analytics",
        schema="public",
        credential_ref="01900000-0000-7000-8000-000000000011",
        credential_version=1,
    )

    saved = repository.save(definition)

    assert uuid.UUID(saved.uid).version == 7
    properties = graph.last_parameters["properties"]
    assert "password" not in properties
    assert "username" not in properties
    assert properties["uid"] == saved.uid
    query = graph.calls[-1][0]
    assert "SET n = $properties" in query
    assert "SET n += $properties" not in query


def test_definition_rejects_secret_properties():
    from app.core.data_source.definitions import (
        DataSourceDefinitionRepository,
    )
    from app.core.data_source.models import DataSourceDefinition

    definition = DataSourceDefinition(
        uid=None,
        name_en="warehouse",
        database_type="postgresql",
        host="db",
        port=5432,
        database="analytics",
        extra_properties={"password": "must-not-enter-graph"},
    )

    with pytest.raises(ValueError, match="secret"):
        DataSourceDefinitionRepository(FakeGraphSession()).save(definition)


def test_definition_list_uses_allowlisted_filters_and_parameters():
    from app.core.data_source.definitions import (
        DataSourceDefinitionRepository,
        DataSourceFilters,
    )

    graph = FakeGraphSession()
    repository = DataSourceDefinitionRepository(graph)

    repository.list(
        DataSourceFilters(name_en="warehouse", database_type="postgresql")
    )

    query, parameters = graph.calls[-1]
    assert "n.name_en = $name_en" in query
    assert "n.type = $database_type" in query
    assert parameters == {
        "name_en": "warehouse",
        "database_type": "postgresql",
    }
