# #region Test.DatasetReviewFilterModels [C:3] [TYPE Module] [SEMANTICS test,sqlalchemy,dataset,review,filter,template,model]
# @BRIEF Verify ImportedFilter and TemplateVariable SQLAlchemy models — construction, defaults, FK constraints, JSON columns.
# @RELATION BINDS_TO -> [DatasetReviewFilterModels]
# @TEST_EDGE: raw_value_json -> JSON column stores dict/list values
# @TEST_EDGE: masking -> raw_value_masked defaults to False
# @TEST_EDGE: mapping_status -> TemplateVariable defaults to UNMAPPED
# @TEST_EDGE: cascade_delete -> Session delete cascades to filters and variables
import uuid
from datetime import UTC, datetime

from sqlalchemy import create_engine, text
from sqlalchemy.orm import Session as SASession
import pytest

from src.models.dataset_review_pkg._session_models import DatasetReviewSession
from src.models.dataset_review_pkg._filter_models import (
    Base,
    ImportedFilter,
    TemplateVariable,
)
from src.models.dataset_review_pkg._enums import (
    FilterConfidenceState,
    FilterRecoveryStatus,
    FilterSource,
    MappingStatus,
    VariableKind,
)
from src.models.mapping import Environment


@pytest.fixture(scope="function")
def db_session():
    """Fresh in-memory SQLite with FK enforcement using single connection."""
    engine = create_engine("sqlite:///:memory:", connect_args={"check_same_thread": False})
    conn = engine.connect()
    conn.execute(text("PRAGMA foreign_keys=ON"))

    # Create the raw users table FIRST — multiple model tables FK-reference it
    conn.execute(text("CREATE TABLE IF NOT EXISTS users (id VARCHAR PRIMARY KEY)"))

    from src.models.mapping import Base as MappingBase
    MappingBase.metadata.create_all(conn)
    Base.metadata.create_all(conn)
    conn.commit()

    session = SASession(bind=conn)
    env = Environment(id="env-1", name="Test", url="https://example.com", credentials_id="cred-1")
    session.add(env)
    session.execute(text("INSERT OR IGNORE INTO users (id) VALUES ('user-1')"))
    session.commit()
    yield session
    session.close()
    conn.close()


def _create_session(db_session) -> DatasetReviewSession:
    rev = DatasetReviewSession(
        user_id="user-1", environment_id="env-1",
        source_kind="superset", source_input="SELECT 1", dataset_ref="ds_1",
    )
    db_session.add(rev)
    db_session.flush()
    return rev


class TestImportedFilter:
    """Verify ImportedFilter model."""

    def test_create_minimal(self, db_session):
        """Minimal required fields."""
        session = _create_session(db_session)
        filt = ImportedFilter(
            session_id=session.session_id,
            filter_name="date_range",
            raw_value={"time_range": "Last 30 days"},
            source=FilterSource.SUPERSET_NATIVE,
            confidence_state=FilterConfidenceState.CONFIRMED,
            recovery_status=FilterRecoveryStatus.RECOVERED,
        )
        db_session.add(filt)
        db_session.flush()

        assert filt.filter_id is not None
        assert isinstance(uuid.UUID(filt.filter_id), uuid.UUID)
        assert filt.filter_name == "date_range"
        assert filt.raw_value == {"time_range": "Last 30 days"}
        assert filt.source == FilterSource.SUPERSET_NATIVE
        assert filt.confidence_state == FilterConfidenceState.CONFIRMED
        assert filt.recovery_status == FilterRecoveryStatus.RECOVERED
        assert filt.raw_value_masked is False
        assert filt.requires_confirmation is False
        assert filt.display_name is None
        assert filt.normalized_value is None
        assert filt.notes is None
        assert filt.created_at is not None
        assert filt.updated_at is not None

    def test_all_fields(self, db_session):
        """All fields populated."""
        session = _create_session(db_session)
        filt = ImportedFilter(
            session_id=session.session_id,
            filter_name="status_filter",
            display_name="Order Status",
            raw_value={"values": ["pending", "shipped"]},
            raw_value_masked=True,
            normalized_value={"values": ["PENDING", "SHIPPED"]},
            source=FilterSource.MANUAL,
            confidence_state=FilterConfidenceState.IMPORTED,
            requires_confirmation=True,
            recovery_status=FilterRecoveryStatus.PARTIAL,
            notes="Needs review",
        )
        db_session.add(filt)
        db_session.flush()

        assert filt.display_name == "Order Status"
        assert filt.normalized_value == {"values": ["PENDING", "SHIPPED"]}
        assert filt.raw_value_masked is True
        assert filt.requires_confirmation is True

    def test_json_raw_value_dict(self, db_session):
        """Raw value as complex dict stored/retrieved."""
        session = _create_session(db_session)
        complex_value = {
            "filter": "status",
            "values": ["a", "b", "c"],
            "operator": "IN",
        }
        filt = ImportedFilter(
            session_id=session.session_id, filter_name="complex",
            raw_value=complex_value, source=FilterSource.INFERRED,
            confidence_state=FilterConfidenceState.INFERRED,
            recovery_status=FilterRecoveryStatus.CONFLICTED,
        )
        db_session.add(filt)
        db_session.flush()

        loaded = db_session.query(ImportedFilter).filter_by(filter_id=filt.filter_id).first()
        assert loaded.raw_value == complex_value

    def test_all_filter_sources(self, db_session):
        """All FilterSource values accepted."""
        session = _create_session(db_session)
        for fs in FilterSource:
            filt = ImportedFilter(
                session_id=session.session_id, filter_name=f"f_{fs.value}",
                raw_value={}, source=fs,
                confidence_state=FilterConfidenceState.CONFIRMED,
                recovery_status=FilterRecoveryStatus.RECOVERED,
            )
            db_session.add(filt)
        db_session.flush()
        assert db_session.query(ImportedFilter).count() == len(FilterSource)

    def test_cascade_delete(self, db_session):
        """Session delete cascades to imported filters."""
        session = _create_session(db_session)
        filt = ImportedFilter(
            session_id=session.session_id, filter_name="test",
            raw_value={"v": 1}, source=FilterSource.SUPERSET_NATIVE,
            confidence_state=FilterConfidenceState.CONFIRMED,
            recovery_status=FilterRecoveryStatus.RECOVERED,
        )
        db_session.add(filt)
        db_session.flush()
        db_session.delete(session)
        db_session.flush()
        assert db_session.query(ImportedFilter).count() == 0

    def test_relationship(self, db_session):
        """Navigate filter -> session."""
        session = _create_session(db_session)
        filt = ImportedFilter(
            session_id=session.session_id, filter_name="test",
            raw_value={}, source=FilterSource.SUPERSET_NATIVE,
            confidence_state=FilterConfidenceState.CONFIRMED,
            recovery_status=FilterRecoveryStatus.RECOVERED,
        )
        db_session.add(filt)
        db_session.flush()
        assert filt.session is session


class TestTemplateVariable:
    """Verify TemplateVariable model."""

    def test_create_minimal(self, db_session):
        """Minimal required fields."""
        session = _create_session(db_session)
        tv = TemplateVariable(
            session_id=session.session_id,
            variable_name="country",
            expression_source="SELECT * FROM orders WHERE country = '{{ country }}'",
            variable_kind=VariableKind.PARAMETER,
        )
        db_session.add(tv)
        db_session.flush()

        assert tv.variable_id is not None
        assert tv.variable_name == "country"
        assert tv.variable_kind == VariableKind.PARAMETER
        assert tv.mapping_status == MappingStatus.UNMAPPED
        assert tv.is_required is True
        assert tv.default_value is None
        assert tv.created_at is not None
        assert tv.updated_at is not None

    def test_all_fields(self, db_session):
        """All fields populated."""
        session = _create_session(db_session)
        tv = TemplateVariable(
            session_id=session.session_id,
            variable_name="date_from",
            expression_source="date > '{{ date_from }}'",
            variable_kind=VariableKind.NATIVE_FILTER,
            is_required=False,
            default_value="2024-01-01",
            mapping_status=MappingStatus.PROPOSED,
        )
        db_session.add(tv)
        db_session.flush()

        assert tv.is_required is False
        assert tv.default_value == "2024-01-01"
        assert tv.mapping_status == MappingStatus.PROPOSED

    def test_all_variable_kinds(self, db_session):
        """All VariableKind values accepted."""
        session = _create_session(db_session)
        for vk in VariableKind:
            tv = TemplateVariable(
                session_id=session.session_id,
                variable_name=f"v_{vk.value}",
                expression_source="expr",
                variable_kind=vk,
            )
            db_session.add(tv)
        db_session.flush()
        assert db_session.query(TemplateVariable).count() == len(VariableKind)

    def test_default_value_json(self, db_session):
        """Default value as JSON stored/retrieved."""
        session = _create_session(db_session)
        tv = TemplateVariable(
            session_id=session.session_id,
            variable_name="multi",
            expression_source="expr",
            variable_kind=VariableKind.DERIVED,
            default_value={"values": ["a", "b"]},
        )
        db_session.add(tv)
        db_session.flush()
        loaded = db_session.query(TemplateVariable).filter_by(variable_id=tv.variable_id).first()
        assert loaded.default_value == {"values": ["a", "b"]}

    def test_cascade_delete(self, db_session):
        """Session delete cascades to template variables."""
        session = _create_session(db_session)
        tv = TemplateVariable(
            session_id=session.session_id,
            variable_name="test", expression_source="e",
            variable_kind=VariableKind.UNKNOWN,
        )
        db_session.add(tv)
        db_session.flush()
        db_session.delete(session)
        db_session.flush()
        assert db_session.query(TemplateVariable).count() == 0
# #endregion Test.DatasetReviewFilterModels
