from __future__ import annotations

from fastapi import HTTPException
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool

from app.core.auth_context import ChatAccessScope
from app.core.dependencies import get_current_user_context
from app.models import Base
from app.models.sso import SsoClient
from app.models.user import User
from app.services.chat_service import ChatService


def _db() -> Session:
    engine = create_engine(
        "sqlite:///:memory:",
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
    )
    Base.metadata.create_all(engine)
    return Session(engine)


def test_chat_sessions_are_isolated_by_login_source_and_application():
    with _db() as db:
        user = User(
            phone="13800138000",
            name="测试学员",
            status=1,
            daily_chat_limit=100,
            daily_chat_used=0,
            is_deleted=0,
        )
        db.add(user)
        db.commit()
        db.refresh(user)

        direct = ChatService.create_session(db, user)
        app_a_scope = ChatAccessScope(source_type="sso", source_client_id=101)
        app_b_scope = ChatAccessScope(source_type="sso", source_client_id=202)
        app_a = ChatService.create_session(db, user, app_a_scope)
        app_b = ChatService.create_session(db, user, app_b_scope)

        assert [item.id for item in ChatService.list_sessions(db, user)] == [direct.id]
        assert [item.id for item in ChatService.list_sessions(db, user, app_a_scope)] == [app_a.id]
        assert [item.id for item in ChatService.list_sessions(db, user, app_b_scope)] == [app_b.id]

        with pytest.raises(HTTPException) as cross_source:
            ChatService.get_history(db, user, app_a.id)
        assert cross_source.value.status_code == 404

        with pytest.raises(HTTPException) as cross_application:
            ChatService.get_history(db, user, app_b.id, app_a_scope)
        assert cross_application.value.status_code == 404


def test_auth_context_defaults_old_tokens_to_direct_and_rejects_disabled_sso_client():
    with _db() as db:
        user = User(
            phone="13700137000",
            name="登录来源验收",
            status=1,
            daily_chat_limit=100,
            daily_chat_used=0,
            is_deleted=0,
        )
        client = SsoClient(
            app_id="context-test-app",
            name="鉴权验收应用",
            client_secret="encrypted-placeholder",
            redirect_uris="[]",
            status=1,
        )
        db.add_all([user, client])
        db.commit()

        direct = get_current_user_context({"sub": str(user.id), "type": "user"}, db)
        assert direct.chat_scope == ChatAccessScope.direct()

        sso = get_current_user_context(
            {
                "sub": str(user.id),
                "type": "user",
                "auth_source": "sso",
                "sso_client_id": client.id,
            },
            db,
        )
        assert sso.chat_scope == ChatAccessScope(source_type="sso", source_client_id=client.id)

        client.status = 0
        db.commit()
        with pytest.raises(HTTPException) as disabled:
            get_current_user_context(
                {
                    "sub": str(user.id),
                    "type": "user",
                    "auth_source": "sso",
                    "sso_client_id": client.id,
                },
                db,
            )
        assert disabled.value.status_code == 401
