"""Integration regression test: archive-status guard on message insert.

Previously, ``ChatService.insert_message_in_db`` ran an
``UPDATE chat_sessions SET message_count = message_count + 1
   WHERE id = :session_id``
without checking the session's status. The route-layer
``status='active'`` guard was informational only — between that check
and the UPDATE, a concurrent PATCH could flip the session to
``archived``, and the send would still land. Result: archived sessions
could silently receive new messages.

The fix narrows the UPDATE's WHERE clause to
``id = :session_id AND status = 'active'``. If the session is archived
(or deleted), the UPDATE matches zero rows, ``scalar_one_or_none``
returns None, and the service raises ValueError("not found or not
active") — caught by routes.py and converted to a 4xx.

This test asserts on the atomic UPDATE directly so the regression
surface is covered even if a future refactor moves the route-layer
guard.
"""

import uuid

import pytest

from src.local_deep_research.chat.service import ChatService
from src.local_deep_research.database.models import (
    ChatMessage,
    ChatSession,
    ChatSessionStatus,
)


def _seed_session(db, status: str):
    """Insert a chat_sessions row in *status* and return its id."""
    sid = str(uuid.uuid4())
    db.add(
        ChatSession(
            id=sid,
            title="archive-guard test",
            status=status,
            message_count=0,
        )
    )
    db.commit()
    return sid


@pytest.mark.parametrize(
    "status",
    [
        ChatSessionStatus.ARCHIVED.value,
        ChatSessionStatus.DELETED.value,
    ],
)
def test_insert_message_rejects_non_active_session(
    setup_database_for_all_tests, status
):
    """A direct call to insert_message_in_db against a non-active
    session must raise rather than silently increment message_count."""
    SessionLocal = setup_database_for_all_tests
    service = ChatService(username=f"alice_{uuid.uuid4().hex[:8]}")

    with SessionLocal() as db:
        sid = _seed_session(db, status=status)

    with SessionLocal() as db:
        with pytest.raises(ValueError, match="not found or not active"):
            service.insert_message_in_db(
                db=db,
                session_id=sid,
                role="user",
                content="should not land",
                message_type="query",
            )

        # And the counter MUST not have moved.
        row = db.query(ChatSession).filter_by(id=sid).first()
        assert row is not None
        assert row.message_count == 0, (
            f"message_count incremented despite {status} session — "
            f"the atomic guard did not hold"
        )
        # And no message row was persisted.
        msgs = db.query(ChatMessage).filter_by(session_id=sid).all()
        assert msgs == [], f"Unexpected message rows: {msgs}"


def test_insert_message_succeeds_on_active_session(
    setup_database_for_all_tests,
):
    """Sanity counter-test: an active session accepts the message and
    message_count bumps by 1."""
    SessionLocal = setup_database_for_all_tests
    service = ChatService(username=f"alice_{uuid.uuid4().hex[:8]}")

    with SessionLocal() as db:
        sid = _seed_session(db, status=ChatSessionStatus.ACTIVE.value)

    with SessionLocal() as db:
        mid = service.insert_message_in_db(
            db=db,
            session_id=sid,
            role="user",
            content="hello",
            message_type="query",
        )
        db.commit()

        row = db.query(ChatSession).filter_by(id=sid).first()
        assert row.message_count == 1
        msg = db.query(ChatMessage).filter_by(id=mid).first()
        assert msg is not None
        assert msg.content == "hello"
        assert msg.session_id == sid


def test_insert_message_rejects_unknown_session(
    setup_database_for_all_tests,
):
    """An unknown id is rejected the same way an archived one is —
    the WHERE clause matches zero rows either way."""
    SessionLocal = setup_database_for_all_tests
    service = ChatService(username=f"alice_{uuid.uuid4().hex[:8]}")

    with SessionLocal() as db:
        with pytest.raises(ValueError, match="not found or not active"):
            service.insert_message_in_db(
                db=db,
                session_id=str(uuid.uuid4()),
                role="user",
                content="should not land",
                message_type="query",
            )
