"""
Migration script to add multi-user support.

This script:
1. Creates the User table
2. Creates a default admin user from environment variables
3. Migrates existing ListeningSession and Recommendation data to the default user
"""

import os
import sys
import asyncio
from datetime import datetime
from sqlalchemy import text, inspect
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker

# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from models import Base, User
from config import get_settings


async def run_migration():
    """Run the multi-user migration."""
    settings = get_settings()

    # Convert sqlite:/// to sqlite+aiosqlite:///
    db_url = settings.database_url.replace("sqlite:///", "sqlite+aiosqlite:///")

    engine = create_async_engine(db_url, echo=True)
    async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

    async with engine.begin() as conn:
        # Check if migration has already been run
        result = await conn.execute(text(
            "SELECT name FROM sqlite_master WHERE type='table' AND name='users'"
        ))
        if result.fetchone():
            print("Migration already run - users table exists")
            return

        print("Starting multi-user migration...")

        # Step 1: Backup existing data
        print("Backing up existing listening_sessions...")
        sessions_backup = await conn.execute(text(
            "SELECT * FROM listening_sessions"
        ))
        sessions_data = sessions_backup.fetchall()
        sessions_columns = sessions_backup.keys()

        print("Backing up existing recommendations...")
        recs_backup = await conn.execute(text(
            "SELECT * FROM recommendations"
        ))
        recs_data = recs_backup.fetchall()
        recs_columns = recs_backup.keys()

        # Step 2: Create User table
        print("Creating users table...")
        await conn.execute(text("""
            CREATE TABLE users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                username VARCHAR NOT NULL UNIQUE,
                email VARCHAR NOT NULL UNIQUE,
                hashed_password VARCHAR NOT NULL,
                abs_url VARCHAR NOT NULL,
                abs_api_token VARCHAR NOT NULL,
                display_name VARCHAR,
                created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                last_login DATETIME,
                is_active BOOLEAN DEFAULT 1
            )
        """))

        await conn.execute(text(
            "CREATE INDEX ix_users_username ON users (username)"
        ))
        await conn.execute(text(
            "CREATE INDEX ix_users_email ON users (email)"
        ))

        # Step 3: Create default admin user
        print("Creating default admin user...")

        # Get credentials from environment
        abs_url = settings.abs_url if hasattr(settings, 'abs_url') else os.getenv('ABS_URL', '')
        abs_token = settings.abs_api_token if hasattr(settings, 'abs_api_token') else os.getenv('ABS_API_TOKEN', '')

        if not abs_url or not abs_token:
            print("WARNING: No ABS_URL or ABS_API_TOKEN found in environment")
            print("Creating placeholder admin user - update credentials in settings")
            abs_url = "http://localhost:13378"
            abs_token = "PLACEHOLDER_TOKEN"

        # Hash the default password using bcrypt
        # Password is "admin123" - user should change this immediately
        import bcrypt as bcrypt_lib
        password_bytes = "admin123".encode('utf-8')
        salt = bcrypt_lib.gensalt()
        hashed = bcrypt_lib.hashpw(password_bytes, salt)
        default_password = hashed.decode('utf-8')

        await conn.execute(text("""
            INSERT INTO users
            (username, email, hashed_password, abs_url, abs_api_token, display_name, created_at, is_active)
            VALUES
            (:username, :email, :password, :abs_url, :abs_token, :display_name, :created_at, :is_active)
        """), {
            "username": "admin",
            "email": "admin@localhost",
            "password": default_password,
            "abs_url": abs_url,
            "abs_token": abs_token,
            "display_name": "Admin User",
            "created_at": datetime.now(),
            "is_active": True
        })

        admin_id = (await conn.execute(text("SELECT last_insert_rowid()"))).scalar()
        print(f"Created admin user with ID: {admin_id}")

        # Step 4: Drop and recreate listening_sessions table
        print("Recreating listening_sessions table with user_id...")
        await conn.execute(text("DROP TABLE listening_sessions"))

        await conn.execute(text("""
            CREATE TABLE listening_sessions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER NOT NULL,
                book_id VARCHAR NOT NULL,
                progress FLOAT DEFAULT 0.0,
                current_time FLOAT DEFAULT 0.0,
                is_finished BOOLEAN DEFAULT 0,
                started_at DATETIME,
                finished_at DATETIME,
                last_update DATETIME DEFAULT CURRENT_TIMESTAMP,
                rating INTEGER,
                FOREIGN KEY (user_id) REFERENCES users (id)
            )
        """))

        await conn.execute(text(
            "CREATE INDEX ix_listening_sessions_user_id ON listening_sessions (user_id)"
        ))

        # Step 5: Migrate listening_sessions data
        if sessions_data:
            print(f"Migrating {len(sessions_data)} listening sessions to admin user...")
            for row in sessions_data:
                row_dict = dict(zip(sessions_columns, row))
                await conn.execute(text("""
                    INSERT INTO listening_sessions
                    (user_id, book_id, progress, current_time, is_finished,
                     started_at, finished_at, last_update, rating)
                    VALUES
                    (:user_id, :book_id, :progress, :current_time, :is_finished,
                     :started_at, :finished_at, :last_update, :rating)
                """), {
                    "user_id": admin_id,
                    "book_id": row_dict.get("book_id"),
                    "progress": row_dict.get("progress", 0.0),
                    "current_time": row_dict.get("current_time", 0.0),
                    "is_finished": row_dict.get("is_finished", False),
                    "started_at": row_dict.get("started_at"),
                    "finished_at": row_dict.get("finished_at"),
                    "last_update": row_dict.get("last_update"),
                    "rating": row_dict.get("rating")
                })

        # Step 6: Drop and recreate recommendations table
        print("Recreating recommendations table with user_id...")
        await conn.execute(text("DROP TABLE recommendations"))

        await conn.execute(text("""
            CREATE TABLE recommendations (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER NOT NULL,
                title VARCHAR NOT NULL,
                author VARCHAR,
                description TEXT,
                reason TEXT,
                genres VARCHAR,
                created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                dismissed BOOLEAN DEFAULT 0,
                FOREIGN KEY (user_id) REFERENCES users (id)
            )
        """))

        await conn.execute(text(
            "CREATE INDEX ix_recommendations_user_id ON recommendations (user_id)"
        ))

        # Step 7: Migrate recommendations data
        if recs_data:
            print(f"Migrating {len(recs_data)} recommendations to admin user...")
            for row in recs_data:
                row_dict = dict(zip(recs_columns, row))
                await conn.execute(text("""
                    INSERT INTO recommendations
                    (user_id, title, author, description, reason, genres, created_at, dismissed)
                    VALUES
                    (:user_id, :title, :author, :description, :reason, :genres, :created_at, :dismissed)
                """), {
                    "user_id": admin_id,
                    "title": row_dict.get("title"),
                    "author": row_dict.get("author"),
                    "description": row_dict.get("description"),
                    "reason": row_dict.get("reason"),
                    "genres": row_dict.get("genres"),
                    "created_at": row_dict.get("created_at"),
                    "dismissed": row_dict.get("dismissed", False)
                })

        print("Migration completed successfully!")
        print("\nDEFAULT ADMIN CREDENTIALS:")
        print("  Username: admin")
        print("  Password: admin123")
        print("  Email: admin@localhost")
        print("\nIMPORTANT: Change the admin password after first login!")

    await engine.dispose()


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