# #region Test.DatasetReviewSessionModels [C:3] [TYPE Module] [SEMANTICS test,sqlalchemy,dataset,review,session,model]
# @BRIEF Verify DatasetReviewSession and SessionCollaborator SQLAlchemy models — construction, defaults, FK constraints, relationships.
# @RELATION BINDS_TO -> [DatasetReviewSessionModels]
# @TEST_EDGE: missing_session_id -> session_id auto-generated as UUID
# @TEST_EDGE: invalid_enum -> SQLEnum rejects bad values
# @TEST_EDGE: cascade_delete -> Session delete cascades to collaborators
# @TEST_EDGE: optimistic_lock -> version column starts at 0 and increments
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._enums import (
    ReadinessState,
    RecommendedAction,
    SessionCollaboratorRole,
    SessionPhase,
    SessionStatus,
)
from src.models.dataset_review_pkg._session_models import (
    Base,
    DatasetReviewSession,
    SessionCollaborator,
)
from src.models.mapping import Environment


@pytest.fixture(scope="function")
def db_session():
    """Fresh in-memory SQLite with FK enforcement using single connection (avoids per-connection isolation)."""
    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://superset.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()


class TestDatasetReviewSession:
    """Verify DatasetReviewSession model construction and defaults."""

    def test_create_minimal(self, db_session):
        """Minimal required fields produce a valid session with defaults."""
        review = DatasetReviewSession(
            user_id="user-1",
            environment_id="env-1",
            source_kind="superset",
            source_input="SELECT * FROM orders",
            dataset_ref="dataset_42",
        )
        db_session.add(review)
        db_session.flush()

        assert review.session_id is not None
        assert isinstance(review.session_id, str)
        # Check UUID format
        uuid.UUID(review.session_id)
        assert review.user_id == "user-1"
        assert review.environment_id == "env-1"
        assert review.source_kind == "superset"
        assert review.dataset_ref == "dataset_42"

        # Default values
        assert review.readiness_state == ReadinessState.EMPTY
        assert review.recommended_action == RecommendedAction.IMPORT_FROM_SUPERSET
        assert review.version == 0
        assert review.status == SessionStatus.ACTIVE
        assert review.current_phase == SessionPhase.INTAKE
        assert review.dataset_id is None
        assert review.dashboard_id is None
        assert review.active_task_id is None
        assert review.last_preview_id is None
        assert review.last_run_context_id is None
        assert review.closed_at is None
        assert review.created_at is not None
        assert review.updated_at is not None
        assert review.last_activity_at is not None

    def test_all_fields(self, db_session):
        """All fields populated explicitly."""
        created = datetime.now(UTC)
        review = DatasetReviewSession(
            user_id="user-1",
            environment_id="env-1",
            source_kind="superset",
            source_input="SELECT 1",
            dataset_ref="ds_1",
            dataset_id=100,
            dashboard_id=42,
            readiness_state=ReadinessState.RUN_READY,
            recommended_action=RecommendedAction.LAUNCH_DATASET,
            version=5,
            status=SessionStatus.ACTIVE,
            current_phase=SessionPhase.LAUNCH,
            active_task_id="task-abc",
            last_preview_id="prev-xyz",
            last_run_context_id="ctx-123",
            created_at=created,
        )
        db_session.add(review)
        db_session.flush()

        assert review.dataset_id == 100
        assert review.dashboard_id == 42
        assert review.readiness_state == ReadinessState.RUN_READY
        assert review.recommended_action == RecommendedAction.LAUNCH_DATASET
        assert review.version == 5
        assert review.current_phase == SessionPhase.LAUNCH
        assert review.active_task_id == "task-abc"
        assert review.last_preview_id == "prev-xyz"
        assert review.last_run_context_id == "ctx-123"

    def test_optimistic_lock_default(self, db_session):
        """Version column starts at 0 (optimistic locking)."""
        review = DatasetReviewSession(
            user_id="user-1", environment_id="env-1",
            source_kind="a", source_input="b", dataset_ref="c",
        )
        db_session.add(review)
        db_session.flush()
        assert review.version == 0

    def test_nullable_fields(self, db_session):
        """Fields marked nullable accept None."""
        review = DatasetReviewSession(
            user_id="user-1", environment_id="env-1",
            source_kind="a", source_input="b", dataset_ref="c",
        )
        db_session.add(review)
        db_session.flush()
        assert review.dataset_id is None
        assert review.dashboard_id is None
        assert review.closed_at is None
        assert review.active_task_id is None

    def test_foreign_key_violation(self, db_session):
        """Invalid environment_id FK raises IntegrityError."""
        from sqlalchemy.exc import IntegrityError
        review = DatasetReviewSession(
            user_id="user-1", environment_id="nonexistent",
            source_kind="a", source_input="b", dataset_ref="c",
        )
        db_session.add(review)
        with pytest.raises(IntegrityError):
            db_session.flush()

    def test_repr(self, db_session):
        """Session id string representation is printable."""
        review = DatasetReviewSession(
            user_id="user-1", environment_id="env-1",
            source_kind="a", source_input="b", dataset_ref="c",
        )
        db_session.add(review)
        db_session.flush()
        assert repr(review) is not None
        assert len(str(review)) > 0


class TestSessionCollaborator:
    """Verify SessionCollaborator model."""

    def test_create_collaborator(self, db_session):
        """Create collaborator linked to a session."""
        review = self._create_session(db_session)
        collab = SessionCollaborator(
            session_id=review.session_id,
            user_id="user-1",
            role=SessionCollaboratorRole.REVIEWER,
        )
        db_session.add(collab)
        db_session.flush()

        assert collab.id is not None
        assert collab.session_id == review.session_id
        assert collab.user_id == "user-1"
        assert collab.role == SessionCollaboratorRole.REVIEWER
        assert collab.added_at is not None

    def test_default_role_values(self, db_session):
        """All collaborator roles are valid."""
        review = self._create_session(db_session)
        for role in SessionCollaboratorRole:
            collab = SessionCollaborator(
                session_id=review.session_id,
                user_id="user-1",
                role=role,
            )
            db_session.add(collab)
        db_session.flush()
        assert db_session.query(SessionCollaborator).count() == len(SessionCollaboratorRole)

    def test_cascade_delete(self, db_session):
        """Deleting a session cascades to its collaborators."""
        review = self._create_session(db_session)
        collab = SessionCollaborator(
            session_id=review.session_id,
            user_id="user-1",
            role=SessionCollaboratorRole.VIEWER,
        )
        db_session.add(collab)
        db_session.flush()
        db_session.delete(review)
        db_session.flush()
        assert db_session.query(SessionCollaborator).count() == 0

    def test_relationship_navigation(self, db_session):
        """Navigate session -> collaborators and collaborator -> session."""
        review = self._create_session(db_session)
        collab = SessionCollaborator(
            session_id=review.session_id, user_id="user-1",
            role=SessionCollaboratorRole.APPROVER,
        )
        db_session.add(collab)
        db_session.flush()

        assert len(review.collaborators) == 1
        assert review.collaborators[0].role == SessionCollaboratorRole.APPROVER
        assert collab.session is review
        assert collab.session.session_id == review.session_id

    def _create_session(self, db_session) -> DatasetReviewSession:
        review = DatasetReviewSession(
            user_id="user-1", environment_id="env-1",
            source_kind="a", source_input="b", dataset_ref="c",
        )
        db_session.add(review)
        db_session.flush()
        return review
# #endregion Test.DatasetReviewSessionModels
