"""Add game types (playthrough/challenges) and bonus assignments

Revision ID: 020_add_game_types
Revises: 019_add_marathon_cover
Create Date: 2024-12-26

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy import inspect


# revision identifiers, used by Alembic.
revision: str = '020_add_game_types'
down_revision: Union[str, None] = '019_add_marathon_cover'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def column_exists(table_name: str, column_name: str) -> bool:
    bind = op.get_bind()
    inspector = inspect(bind)
    columns = [col['name'] for col in inspector.get_columns(table_name)]
    return column_name in columns


def table_exists(table_name: str) -> bool:
    bind = op.get_bind()
    inspector = inspect(bind)
    return table_name in inspector.get_table_names()


def upgrade() -> None:
    # === Games table: добавляем поля для типа игры ===

    # game_type - тип игры (playthrough/challenges)
    if not column_exists('games', 'game_type'):
        op.add_column('games', sa.Column(
            'game_type',
            sa.String(20),
            nullable=False,
            server_default='challenges'
        ))

    # playthrough_points - очки за прохождение
    if not column_exists('games', 'playthrough_points'):
        op.add_column('games', sa.Column(
            'playthrough_points',
            sa.Integer(),
            nullable=True
        ))

    # playthrough_description - описание прохождения
    if not column_exists('games', 'playthrough_description'):
        op.add_column('games', sa.Column(
            'playthrough_description',
            sa.Text(),
            nullable=True
        ))

    # playthrough_proof_type - тип пруфа для прохождения
    if not column_exists('games', 'playthrough_proof_type'):
        op.add_column('games', sa.Column(
            'playthrough_proof_type',
            sa.String(20),
            nullable=True
        ))

    # playthrough_proof_hint - подсказка для пруфа
    if not column_exists('games', 'playthrough_proof_hint'):
        op.add_column('games', sa.Column(
            'playthrough_proof_hint',
            sa.Text(),
            nullable=True
        ))

    # === Assignments table: добавляем поля для прохождений ===

    # game_id - ссылка на игру (для playthrough)
    if not column_exists('assignments', 'game_id'):
        op.add_column('assignments', sa.Column(
            'game_id',
            sa.Integer(),
            sa.ForeignKey('games.id', ondelete='CASCADE'),
            nullable=True
        ))
        op.create_index('ix_assignments_game_id', 'assignments', ['game_id'])

    # is_playthrough - флаг прохождения
    if not column_exists('assignments', 'is_playthrough'):
        op.add_column('assignments', sa.Column(
            'is_playthrough',
            sa.Boolean(),
            nullable=False,
            server_default='false'
        ))

    # Делаем challenge_id nullable (для playthrough заданий)
    # SQLite не поддерживает ALTER COLUMN, поэтому проверяем dialect
    bind = op.get_bind()
    if bind.dialect.name != 'sqlite':
        op.alter_column('assignments', 'challenge_id', nullable=True)

    # === Создаём таблицу bonus_assignments ===

    if not table_exists('bonus_assignments'):
        op.create_table(
            'bonus_assignments',
            sa.Column('id', sa.Integer(), primary_key=True),
            sa.Column('main_assignment_id', sa.Integer(),
                      sa.ForeignKey('assignments.id', ondelete='CASCADE'),
                      nullable=False, index=True),
            sa.Column('challenge_id', sa.Integer(),
                      sa.ForeignKey('challenges.id', ondelete='CASCADE'),
                      nullable=False, index=True),
            sa.Column('status', sa.String(20), nullable=False, server_default='pending'),
            sa.Column('proof_path', sa.String(500), nullable=True),
            sa.Column('proof_url', sa.Text(), nullable=True),
            sa.Column('proof_comment', sa.Text(), nullable=True),
            sa.Column('points_earned', sa.Integer(), nullable=False, server_default='0'),
            sa.Column('completed_at', sa.DateTime(), nullable=True),
            sa.Column('created_at', sa.DateTime(), nullable=False,
                      server_default=sa.func.now()),
        )


def downgrade() -> None:
    # Удаляем таблицу bonus_assignments
    if table_exists('bonus_assignments'):
        op.drop_table('bonus_assignments')

    # Удаляем поля из assignments
    if column_exists('assignments', 'is_playthrough'):
        op.drop_column('assignments', 'is_playthrough')

    if column_exists('assignments', 'game_id'):
        op.drop_index('ix_assignments_game_id', 'assignments')
        op.drop_column('assignments', 'game_id')

    # Удаляем поля из games
    if column_exists('games', 'playthrough_proof_hint'):
        op.drop_column('games', 'playthrough_proof_hint')

    if column_exists('games', 'playthrough_proof_type'):
        op.drop_column('games', 'playthrough_proof_type')

    if column_exists('games', 'playthrough_description'):
        op.drop_column('games', 'playthrough_description')

    if column_exists('games', 'playthrough_points'):
        op.drop_column('games', 'playthrough_points')

    if column_exists('games', 'game_type'):
        op.drop_column('games', 'game_type')
