"""Юнит-тесты модели `ConferenceInvitee`: CHECK «ровно одна identity» и частичные
UNIQUE-индексы (ADR-003, `docs/architecture/adr/003-conference-invitees.md`).
"""

import uuid

import pytest
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession

from core.security import hash_password
from models.conference import Conference
from models.invitee import ConferenceInvitee
from models.user import User
from services.conference_ids import generate_number, generate_slug


async def _make_user(session: AsyncSession) -> User:
    user = User(
        email=f"{uuid.uuid4()}@example.com",
        name_user="Invitee Tester",
        password_hash=await hash_password("password123"),
        email_verified=True,
    )
    session.add(user)
    await session.flush()
    return user


async def _make_conference(
    session: AsyncSession, *, owner_id: uuid.UUID | None = None
) -> Conference:
    conference = Conference(
        number=generate_number(), slug=generate_slug(), owner_id=owner_id, status="scheduled"
    )
    session.add(conference)
    await session.flush()
    return conference


async def test_neither_user_id_nor_email_violates_check(db_session: AsyncSession) -> None:
    conference = await _make_conference(db_session)
    db_session.add(ConferenceInvitee(conference_id=conference.id))
    with pytest.raises(IntegrityError):
        await db_session.commit()


async def test_both_user_id_and_email_violates_check(db_session: AsyncSession) -> None:
    conference = await _make_conference(db_session)
    invitee_user = await _make_user(db_session)
    await db_session.commit()

    db_session.add(
        ConferenceInvitee(
            conference_id=conference.id, user_id=invitee_user.id, email="x@example.com"
        )
    )
    with pytest.raises(IntegrityError):
        await db_session.commit()


async def test_duplicate_user_id_on_same_conference_violates_unique(
    db_session: AsyncSession,
) -> None:
    conference = await _make_conference(db_session)
    invitee_user = await _make_user(db_session)
    db_session.add(ConferenceInvitee(conference_id=conference.id, user_id=invitee_user.id))
    await db_session.commit()

    db_session.add(ConferenceInvitee(conference_id=conference.id, user_id=invitee_user.id))
    with pytest.raises(IntegrityError):
        await db_session.commit()


async def test_duplicate_email_case_insensitive_violates_unique(db_session: AsyncSession) -> None:
    conference = await _make_conference(db_session)
    unique_email = f"guest-{uuid.uuid4()}@example.com"
    db_session.add(ConferenceInvitee(conference_id=conference.id, email=unique_email))
    await db_session.commit()

    db_session.add(ConferenceInvitee(conference_id=conference.id, email=unique_email.upper()))
    with pytest.raises(IntegrityError):
        await db_session.commit()


async def test_same_email_on_different_conferences_is_allowed(db_session: AsyncSession) -> None:
    conference_a = await _make_conference(db_session)
    conference_b = await _make_conference(db_session)
    shared_email = f"shared-{uuid.uuid4()}@example.com"
    db_session.add(ConferenceInvitee(conference_id=conference_a.id, email=shared_email))
    db_session.add(ConferenceInvitee(conference_id=conference_b.id, email=shared_email))
    await db_session.commit()  # не должно бросить — разные конференции
