"""
Migration: Fix telegram_id to allow NULL for web users

Changes:
- Drop existing primary key constraint on telegram_id
- Make telegram_id nullable
- Ensure id column exists and is unique
- Add constraint that either telegram_id OR username must be NOT NULL

Run this migration to allow web-only users without telegram_id.
"""

import asyncio
import os
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy import text

DB_USER = os.getenv("POSTGRES_USER")
DB_PASS = os.getenv("POSTGRES_PASSWORD")
DB_NAME = os.getenv("POSTGRES_DB")
DB_HOST = os.getenv("POSTGRES_HOST", "localhost")
DB_PORT = os.getenv("POSTGRES_PORT", "5432")

DATABASE_URL = f"postgresql+psycopg://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}"


async def migrate():
    engine = create_async_engine(DATABASE_URL)
    
    async with engine.begin() as conn:
        print("Starting migration: Fix telegram_id to allow NULL...")
        
        try:
            # First, check current state
            result = await conn.execute(text("""
                SELECT 
                    c.column_name,
                    c.is_nullable,
                    c.column_default
                FROM information_schema.columns c
                WHERE c.table_name = 'players' 
                    AND c.column_name IN ('telegram_id', 'id', 'username')
                ORDER BY c.ordinal_position
            """))
            print("\nCurrent columns:")
            for row in result:
                print(f"  - {row[0]}: nullable={row[1]}, default={row[2]}")
            
            # Store foreign keys that reference players.telegram_id
            print("\nFinding foreign keys that reference players(telegram_id)...")
            result = await conn.execute(text("""
                SELECT 
                    tc.constraint_name,
                    tc.table_name,
                    kcu.column_name
                FROM information_schema.table_constraints tc
                JOIN information_schema.key_column_usage kcu
                    ON tc.constraint_name = kcu.constraint_name
                JOIN information_schema.constraint_column_usage ccu
                    ON tc.constraint_name = ccu.constraint_name
                WHERE tc.constraint_type = 'FOREIGN KEY'
                    AND ccu.table_name = 'players'
                    AND ccu.column_name = 'telegram_id'
            """))
            fk_constraints = list(result)
            
            # Drop foreign key constraints temporarily
            for fk_name, table_name, column_name in fk_constraints:
                print(f"  Dropping FK: {table_name}.{fk_name}")
                await conn.execute(text(f"ALTER TABLE {table_name} DROP CONSTRAINT {fk_name}"))
            
            # Check for primary key constraint
            result = await conn.execute(text("""
                SELECT constraint_name, constraint_type
                FROM information_schema.table_constraints
                WHERE table_name = 'players' AND constraint_type = 'PRIMARY KEY'
            """))
            pk_constraints = list(result)
            
            if pk_constraints:
                pk_name = pk_constraints[0][0]
                print(f"\nDropping PRIMARY KEY constraint: {pk_name}")
                await conn.execute(text(f"ALTER TABLE players DROP CONSTRAINT {pk_name}"))
            else:
                print("\n✓ No PRIMARY KEY constraint found")
            
            # Make telegram_id nullable
            print("Making telegram_id nullable...")
            await conn.execute(text("""
                ALTER TABLE players 
                ALTER COLUMN telegram_id DROP NOT NULL
            """))
            
            # Make telegram_id unique if not already
            print("Ensuring telegram_id is unique...")
            try:
                await conn.execute(text("""
                    ALTER TABLE players 
                    ADD CONSTRAINT players_telegram_id_unique UNIQUE (telegram_id)
                """))
            except Exception as e:
                if "already exists" in str(e):
                    print("✓ telegram_id unique constraint already exists")
                else:
                    raise
            
            # Ensure id column exists and is unique
            result = await conn.execute(text("""
                SELECT column_name 
                FROM information_schema.columns 
                WHERE table_name='players' AND column_name='id'
            """))
            if not list(result):
                print("Adding id column...")
                await conn.execute(text("""
                    ALTER TABLE players 
                    ADD COLUMN id SERIAL UNIQUE
                """))
            else:
                print("✓ id column exists")
                
                # Make sure it's unique
                try:
                    await conn.execute(text("""
                        ALTER TABLE players 
                        ADD CONSTRAINT players_id_unique UNIQUE (id)
                    """))
                except Exception as e:
                    if "already exists" in str(e):
                        print("✓ id unique constraint already exists")
                    else:
                        raise
            
            # Add check constraint that either telegram_id OR username must be NOT NULL
            print("Adding constraint: either telegram_id OR username must be NOT NULL...")
            try:
                await conn.execute(text("""
                    ALTER TABLE players 
                    ADD CONSTRAINT players_id_check 
                    CHECK (telegram_id IS NOT NULL OR username IS NOT NULL)
                """))
            except Exception as e:
                if "already exists" in str(e):
                    print("✓ Check constraint already exists")
                else:
                    raise
            
            # Recreate foreign key constraints
            print("\nRecreating foreign key constraints...")
            for fk_name, table_name, column_name in fk_constraints:
                print(f"  Adding FK: {table_name}.{fk_name}")
                await conn.execute(text(f"""
                    ALTER TABLE {table_name} 
                    ADD CONSTRAINT {fk_name} 
                    FOREIGN KEY ({column_name}) 
                    REFERENCES players(telegram_id) 
                    ON DELETE CASCADE
                """))
            
            print("\n✅ Migration completed successfully!")
            print("\nNow players can be created with:")
            print("  - telegram_id (Telegram users)")
            print("  - username + password_hash (web users)")
            print("  - Both telegram_id is unique and id is unique")
            
        except Exception as e:
            print(f"\n❌ Migration failed: {e}")
            raise
    
    await engine.dispose()


if __name__ == "__main__":
    asyncio.run(migrate())
