#!/usr/bin/env python3
import os
import sys
from pathlib import Path

# Add the project root directory to Python path to make imports work
root_dir = Path(__file__).resolve().parent.parent
sys.path.append(str(root_dir))

import asyncio
import json
from datetime import datetime
from sqlalchemy import select, func, text
from sqlalchemy.orm import selectinload
from database.base import async_session, init_db, engine
from database.models import Payment, Order, User
import logging

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler("payments_migration.log"),
    ],
)
logger = logging.getLogger("payments_migration")

async def count_tables():
    """Count records in both tables for verification"""
    async with async_session() as session:
        payment_count = await session.execute(select(func.count()).select_from(Payment))
        order_count = await session.execute(select(func.count()).select_from(Order))
        
        payment_count = payment_count.scalar_one()
        order_count = order_count.scalar_one()
        
        logger.info(f"Current payment count: {payment_count}")
        logger.info(f"Current order count: {order_count}")
        
        return payment_count, order_count

async def migrate_payments_to_orders():
    """
    Transfer data from the Payment table to the Orders table.
    Maps fields appropriately and maintains data integrity.
    """
    logger.info("Starting migration of payments to orders")
    
    # Count before migration
    payment_count, order_count_before = await count_tables()
    
    migrated_count = 0
    skipped_count = 0
    error_count = 0
    
    async with async_session() as session:
        # Get all payments
        result = await session.execute(
            select(Payment).options(selectinload(Payment.user)).order_by(Payment.id)
        )
        payments = result.scalars().all()
        
        logger.info(f"Found {len(payments)} payments to migrate")
        
        for payment in payments:
            # Check if an order with the same payment ID already exists
            # to avoid duplicate migrations
            check_result = await session.execute(
                select(Order).where(
                    Order.created_at == payment.created_at,
                    Order.user_id == payment.user_id,
                    Order.amount == payment.amount
                )
            )
            existing_order = check_result.scalars().first()
            
            if existing_order:
                logger.info(f"Order already exists for payment {payment.id}, skipping")
                skipped_count += 1
                continue
                
            # Create product_info JSON with all relevant payment data
            product_info = {
                "original_payment_id": payment.id,
                "payment_id": payment.payment_id,
                "provider": payment.provider,
                "status": payment.status,
                "paid_at": payment.paid_at.isoformat() if payment.paid_at else None,
            }
            
            # Map payment status to appropriate type_of_order value
            type_of_order = "buy"
            
            # Create new order
            new_order = Order(
                user_id=payment.user_id,
                amount=payment.amount,
                created_at=payment.created_at,
                type_of_order=type_of_order,
                product="vpn_subscription",
                product_info=json.dumps(product_info)
            )
            
            try:
                session.add(new_order)
                await session.commit()
                logger.info(f"Migrated payment {payment.id} to order successfully")
                migrated_count += 1
            except Exception as e:
                await session.rollback()
                logger.error(f"Error migrating payment {payment.id}: {str(e)}")
                error_count += 1
    
    # Count after migration
    _, order_count_after = await count_tables()
    
    logger.info(f"Migration completed. Stats:")
    logger.info(f"- Total payments processed: {len(payments)}")
    logger.info(f"- Successfully migrated: {migrated_count}")
    logger.info(f"- Skipped (already existed): {skipped_count}")
    logger.info(f"- Errors: {error_count}")
    logger.info(f"- Orders before migration: {order_count_before}")
    logger.info(f"- Orders after migration: {order_count_after}")
    logger.info(f"- Net new orders: {order_count_after - order_count_before}")

async def verify_migration():
    """Verify the migration was successful by comparing record counts"""
    payment_count, order_count = await count_tables()
    
    # This isn't a perfect verification since there could be pre-existing orders
    # But it gives us a sanity check
    logger.info("Migration verification:")
    if order_count >= payment_count:
        logger.info("✅ Verification passed: All payments appear to have been migrated")
    else:
        logger.warning("⚠️ Verification warning: Order count is less than payment count")
        logger.warning(f"  Payment count: {payment_count}, Order count: {order_count}")
        logger.warning("  This could be normal if some payments were skipped or had errors")

async def add_balance_column():
    """
    Add 'balance' column to users table if it doesn't exist.
    Sets default value of 0 for existing users.
    """
    logger.info("Checking if balance column exists in users table")
    
    async with engine.connect() as conn:
        # Check if balance column exists in users table
        check_query = text("""
            SELECT COUNT(*) AS column_exists
            FROM information_schema.columns
            WHERE table_schema = DATABASE()
            AND table_name = 'users' 
            AND column_name = 'balance'
        """)
        
        result = await conn.execute(check_query)
        column_exists = result.scalar()
        
        if column_exists:
            logger.info("Balance column already exists in users table")
            return
            
        # Add balance column to users table
        logger.info("Adding balance column to users table")
        add_column_query = text("""
            ALTER TABLE users 
            ADD COLUMN balance BIGINT DEFAULT 0 NOT NULL
        """)
        
        try:
            await conn.execute(add_column_query)
            await conn.commit()
            logger.info("Balance column added successfully")
        except Exception as e:
            logger.error(f"Error adding balance column: {str(e)}")
            raise
            
        # Update existing users to have a balance of 0
        logger.info("Setting default balance for existing users")
        update_query = text("""
            UPDATE users 
            SET balance = 0
            WHERE balance IS NULL
        """)
        
        try:
            await conn.execute(update_query)
            await conn.commit()
            logger.info("Default balance set for all users")
        except Exception as e:
            logger.error(f"Error setting default balance: {str(e)}")
            raise

async def main():
    logger.info("Starting database migration process")
    try:
        await init_db()  # Ensure tables exist
        await add_balance_column()  # Add balance column if needed
        await migrate_payments_to_orders()
        await verify_migration()
        logger.info("Migration process completed successfully")
    except Exception as e:
        logger.error(f"Migration failed: {str(e)}")
    logger.info("Migration process completed")

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