"""Tests for strict type safety in TabularValidator."""

import polars as pl
import pytest

from axm.catalog.entries import Identity, Location, Owner
from axm_tabular.entries.tabular import TabularEntry, TabularSchema, TabularSpec
from axm_tabular.validation.tabular import TabularValidator


@pytest.fixture
def base_tabular_entry():
    """Create a base entry to be customized in tests."""

    def _create(col_name: str, col_type: str, nullable: bool = True):
        return TabularEntry(
            name="type_test",
            version="1.0",
            identity=Identity(
                display_name="Test",
                description="Test",
                domain="test",
                owner=Owner(team="test", contact="test@test.com"),
            ),
            data_schema=TabularSchema(
                spec=TabularSpec(
                    columns=[
                        {"name": col_name, "type": col_type, "nullable": nullable},
                    ]
                )
            ),
            location=Location(storage="fs", path_template="/"),
        )

    return _create


def test_strict_int_types(base_tabular_entry):
    """It should distinguish between various integer widths."""
    entry = base_tabular_entry("val", "int64")
    validator = TabularValidator(entry)

    df_ok = pl.DataFrame({"val": [1, 2, 3]}, schema={"val": pl.Int64})
    assert validator.validate(df_ok).is_valid

    assert validator.validate(df_ok).is_valid

    df_bad = pl.DataFrame({"val": [1, 2, 3]}, schema={"val": pl.Int32})
    result = validator.validate(df_bad)

    assert not result.is_valid
    assert "Type mismatch" in result.errors[0].message
    assert "expected int64" in result.errors[0].message.lower()


def test_float_precision(base_tabular_entry):
    """It should distinguish between float precisions."""
    entry = base_tabular_entry("val", "float64")
    validator = TabularValidator(entry)

    df_ok = pl.DataFrame({"val": [1.0, 2.0]}, schema={"val": pl.Float64})
    assert validator.validate(df_ok).is_valid

    df_bad = pl.DataFrame({"val": [1.0, 2.0]}, schema={"val": pl.Float32})
    result = validator.validate(df_bad)
    assert not result.is_valid
    assert "Type mismatch" in result.errors[0].message


def test_temporal_types(base_tabular_entry):
    """It should validate datetime precision/types."""
    entry = base_tabular_entry("event_time", "datetime")
    validator = TabularValidator(entry)

    from datetime import datetime

    df_ok = pl.DataFrame({"event_time": [datetime.now()]})
    df_ok = pl.DataFrame({"event_time": [datetime.now()]})
    assert validator.validate(df_ok).is_valid

    from datetime import date

    df_bad = pl.DataFrame({"event_time": [date.today()]})
    result = validator.validate(df_bad)
    assert not result.is_valid
    assert "Type mismatch" in result.errors[0].message


def test_string_vs_categorical(base_tabular_entry):
    """It should handle string vs categorical distinction."""
    entry = base_tabular_entry("cat", "string")
    validator = TabularValidator(entry)

    df_str = pl.DataFrame({"cat": ["a", "b"]}, schema={"cat": pl.String})
    df_str = pl.DataFrame({"cat": ["a", "b"]}, schema={"cat": pl.String})
    assert validator.validate(df_str).is_valid

    df_cat = pl.DataFrame({"cat": ["a", "b"]}, schema={"cat": pl.Categorical})
    result = validator.validate(df_cat)
    assert not result.is_valid
    assert "Type mismatch" in result.errors[0].message
