"""chat guest authors

Разрешить сообщения чата (`chat_messages`) от гостей и хранить снапшот имени
автора:
- `user_id` становится nullable — автором может быть гость;
- `guest_access_id` — необязательная ссылка на `guest_access`, `ON DELETE
  CASCADE` (удаление гостевой записи удаляет и его сообщения чата);
- `author_name` — снапшот отображаемого имени из LiveKit-токена на момент
  отправки; добавляется nullable, backfill из `users.name_user` для уже
  существующих строк (все они с `user_id`, т.к. гостевого автора раньше не
  было), затем ужесточается до `NOT NULL`;
- `ck_chat_messages_author` — ровно один из `user_id`/`guest_access_id`
  обязателен (как у `ConferenceParticipant`, ADR-001, п.6).

Revision ID: 504791847d4f
Revises: 9d37822e4513
Create Date: 2026-07-18 18:45:20.921653

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = '504791847d4f'
down_revision: Union[str, Sequence[str], None] = '9d37822e4513'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    """Upgrade schema."""
    op.add_column('chat_messages', sa.Column('guest_access_id', sa.UUID(), nullable=True))
    op.add_column('chat_messages', sa.Column('author_name', sa.String(length=255), nullable=True))
    op.alter_column('chat_messages', 'user_id', existing_type=sa.UUID(), nullable=True)

    op.create_foreign_key(
        'fk_chat_messages_guest_access_id_guest_access',
        'chat_messages', 'guest_access', ['guest_access_id'], ['id'], ondelete='CASCADE',
    )

    # Backfill: до этой миграции автор всегда был зарегистрированным
    # пользователем — берём снапшот его текущего имени.
    op.execute(
        """
        UPDATE chat_messages cm
        SET author_name = u.name_user
        FROM users u
        WHERE cm.user_id = u.id
        """
    )
    op.alter_column('chat_messages', 'author_name', existing_type=sa.String(length=255), nullable=False)

    op.create_check_constraint(
        'ck_chat_messages_author',
        'chat_messages',
        'user_id IS NOT NULL OR guest_access_id IS NOT NULL',
    )


def downgrade() -> None:
    """Downgrade schema."""
    op.drop_constraint('ck_chat_messages_author', 'chat_messages', type_='check')
    op.drop_constraint('fk_chat_messages_guest_access_id_guest_access', 'chat_messages', type_='foreignkey')
    op.alter_column('chat_messages', 'user_id', existing_type=sa.UUID(), nullable=False)
    op.drop_column('chat_messages', 'author_name')
    op.drop_column('chat_messages', 'guest_access_id')
