"""session_audio_tracks + атрибуция phrases к участнику (ADR-002)

Схема БД для записи аудиодорожек сеанса и атрибуции фраз:
- новая таблица `session_audio_tracks` — одна аудиодорожка сеанса, записанная
  LiveKit Track Egress (per-track, трек = спикер, диаризация не нужна);
- `phrases`: `user_id` -> `participant_id` (FK `conference_participants.id`,
  ON DELETE CASCADE) — атрибуция фразы к окну присутствия участника сеанса
  (пользователя ИЛИ гостя), а не напрямую к `users`
  (`docs/architecture/adr/002-phrase-attribution-session-participant.md`).

Продакшен-данных нет (см. ADR-002, контекст) — простая замена колонки без
backfill; единственная строка `phrases`, оставшаяся в дев-БД от ручного
тестирования, удаляется явно (см. `_clear_dev_phrases`), т.к. её
`user_id` не сопоставим ни с одним `conference_participants.id`. Downgrade
симметричен и данные `phrases` не восстанавливает (как и в f418dd65e7b1).

Revision ID: 88aa676ac140
Revises: f418dd65e7b1
Create Date: 2026-07-17 10:30:10.456704

"""
from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
from sqlalchemy.engine import Connection

# revision identifiers, used by Alembic.
revision: str = '88aa676ac140'
down_revision: Union[str, Sequence[str], None] = 'f418dd65e7b1'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def _clear_dev_phrases(connection: Connection) -> None:
    """Удалить строки `phrases`, оставшиеся от ручного тестирования до ADR-002.

    Продакшен-данных нет (см. докстринг ревизии) — на пустой таблице это no-op.
    """
    connection.execute(sa.text("DELETE FROM phrases"))


def upgrade() -> None:
    """Upgrade schema."""
    bind = op.get_bind()

    op.create_table(
        'session_audio_tracks',
        sa.Column('id', sa.UUID(), server_default=sa.text('gen_random_uuid()'), nullable=False),
        sa.Column('session_id', sa.UUID(), nullable=False),
        sa.Column('participant_id', sa.UUID(), nullable=False),
        sa.Column('track_sid', sa.String(length=64), nullable=False),
        sa.Column('egress_id', sa.String(length=64), nullable=True),
        sa.Column('file_path', sa.Text(), nullable=True),
        sa.Column(
            'status',
            sa.Enum('recording', 'recorded', 'transcribed', 'failed', name='audio_track_status'),
            server_default='recording',
            nullable=False,
        ),
        sa.Column('started_at', sa.DateTime(timezone=True), nullable=False),
        sa.Column('ended_at', sa.DateTime(timezone=True), nullable=True),
        sa.Column('segments', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
        sa.ForeignKeyConstraint(
            ['participant_id'], ['conference_participants.id'], ondelete='CASCADE'
        ),
        sa.ForeignKeyConstraint(['session_id'], ['conference_sessions.id'], ondelete='CASCADE'),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('session_id', 'track_sid', name='uq_session_track'),
    )
    op.create_index(
        'ix_session_audio_tracks_session_id', 'session_audio_tracks', ['session_id']
    )
    op.create_index(
        'ix_session_audio_tracks_session_id_status',
        'session_audio_tracks',
        ['session_id', 'status'],
    )

    _clear_dev_phrases(bind)
    op.drop_constraint('phrases_user_id_fkey', 'phrases', type_='foreignkey')
    op.drop_column('phrases', 'user_id')
    op.add_column('phrases', sa.Column('participant_id', sa.UUID(), nullable=False))
    op.create_foreign_key(
        'phrases_participant_id_fkey',
        'phrases', 'conference_participants',
        ['participant_id'], ['id'], ondelete='CASCADE',
    )


def downgrade() -> None:
    """Downgrade schema.

    Разрушительная миграция для `phrases` (см. докстринг ревизии выше) —
    downgrade восстанавливает структуру колонки, но не исходные данные.
    """
    bind = op.get_bind()

    _clear_dev_phrases(bind)
    op.drop_constraint('phrases_participant_id_fkey', 'phrases', type_='foreignkey')
    op.drop_column('phrases', 'participant_id')
    op.add_column('phrases', sa.Column('user_id', sa.UUID(), nullable=False))
    op.create_foreign_key('phrases_user_id_fkey', 'phrases', 'users', ['user_id'], ['id'])

    op.drop_index('ix_session_audio_tracks_session_id_status', table_name='session_audio_tracks')
    op.drop_index('ix_session_audio_tracks_session_id', table_name='session_audio_tracks')
    op.drop_table('session_audio_tracks')
    postgresql.ENUM(name='audio_track_status').drop(bind, checkfirst=True)
