#!/usr/bin/env python3
"""
Migration Verification Script for Canvas Metadata Table

This script verifies that the canvas_metadata migration was successful by:
1. Checking that the canvas_metadata table exists
2. Verifying all required columns exist with correct types
3. Checking that all indexes were created
4. Validating data migration from general_canvases
5. Validating data migration from asset canvases
6. Validating data migration from storyboard canvases
7. Checking data integrity and consistency
"""

import sys
import os
from sqlalchemy import create_engine, inspect, text
from sqlalchemy.engine import Engine
import json

# Add backend directory to sys.path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))

from backend.src.config.settings import DB_PATH


class MigrationVerifier:
    def __init__(self, db_path: str):
        self.db_path = db_path
        self.engine = create_engine(f"sqlite:///{db_path}")
        self.inspector = inspect(self.engine)
        self.errors = []
        self.warnings = []
        self.success_count = 0
        self.total_checks = 0
    
    def check(self, condition: bool, success_msg: str, error_msg: str):
        """Helper method to track check results"""
        self.total_checks += 1
        if condition:
            self.success_count += 1
            print(f"✅ {success_msg}")
        else:
            self.errors.append(error_msg)
            print(f"❌ {error_msg}")
    
    def warn(self, message: str):
        """Helper method to track warnings"""
        self.warnings.append(message)
        print(f"⚠️  {message}")
    
    def verify_table_exists(self) -> bool:
        """Verify that canvas_metadata table exists"""
        print("\n=== Checking Table Existence ===")
        tables = self.inspector.get_table_names()
        self.check(
            'canvas_metadata' in tables,
            "canvas_metadata table exists",
            "canvas_metadata table does not exist"
        )
        return 'canvas_metadata' in tables
    
    def verify_columns(self) -> bool:
        """Verify all required columns exist with correct types"""
        print("\n=== Checking Columns ===")
        
        required_columns = {
            'id': 'VARCHAR',
            'project_id': 'VARCHAR',
            'canvas_type': 'VARCHAR',
            'related_entity_type': 'VARCHAR',
            'related_entity_id': 'VARCHAR',
            'name': 'VARCHAR',
            'description': 'VARCHAR',
            'order_index': 'INTEGER',
            'is_pinned': 'BOOLEAN',
            'tags': 'JSON',
            'node_count': 'INTEGER',
            'last_accessed_at': 'FLOAT',
            'access_count': 'INTEGER',
            'created_at': 'FLOAT',
            'updated_at': 'FLOAT',
            'deleted_at': 'FLOAT',
            'legacy_id': 'VARCHAR'
        }
        
        columns = self.inspector.get_columns('canvas_metadata')
        column_dict = {col['name']: col for col in columns}
        
        all_columns_exist = True
        for col_name, expected_type in required_columns.items():
            if col_name in column_dict:
                col_type = str(column_dict[col_name]['type']).upper()
                # SQLite stores JSON as TEXT, so we need to check for that
                if expected_type == 'JSON' and 'TEXT' in col_type:
                    print(f"✅ Column '{col_name}' exists with type {col_type} (JSON stored as TEXT)")
                elif expected_type in col_type or col_type in expected_type:
                    print(f"✅ Column '{col_name}' exists with type {col_type}")
                else:
                    self.warn(f"Column '{col_name}' exists but type is {col_type}, expected {expected_type}")
            else:
                all_columns_exist = False
                self.errors.append(f"Column '{col_name}' is missing")
                print(f"❌ Column '{col_name}' is missing")
        
        return all_columns_exist
    
    def verify_indexes(self) -> bool:
        """Verify all required indexes exist"""
        print("\n=== Checking Indexes ===")
        
        required_indexes = [
            'ix_canvas_metadata_project_id',
            'ix_canvas_metadata_canvas_type',
            'ix_canvas_metadata_related_entity_id',
            'ix_canvas_metadata_legacy_id',
            'ix_canvas_metadata_project_type',
            'ix_canvas_metadata_type_entity'
        ]
        
        indexes = self.inspector.get_indexes('canvas_metadata')
        index_names = [idx['name'] for idx in indexes]
        
        all_indexes_exist = True
        for idx_name in required_indexes:
            if idx_name in index_names:
                print(f"✅ Index '{idx_name}' exists")
            else:
                all_indexes_exist = False
                self.errors.append(f"Index '{idx_name}' is missing")
                print(f"❌ Index '{idx_name}' is missing")
        
        return all_indexes_exist
    
    def verify_foreign_keys(self) -> bool:
        """Verify foreign key constraints"""
        print("\n=== Checking Foreign Keys ===")
        
        fks = self.inspector.get_foreign_keys('canvas_metadata')
        
        has_project_fk = any(
            fk['referred_table'] == 'projects' and 'project_id' in fk['constrained_columns']
            for fk in fks
        )
        
        self.check(
            has_project_fk,
            "Foreign key to projects table exists",
            "Foreign key to projects table is missing"
        )
        
        return has_project_fk
    
    def verify_data_migration(self) -> bool:
        """Verify data was migrated correctly"""
        print("\n=== Checking Data Migration ===")
        
        with self.engine.connect() as conn:
            # Check if any canvas_metadata records exist
            result = conn.execute(text("SELECT COUNT(*) FROM canvas_metadata"))
            count = result.scalar()
            
            if count > 0:
                print(f"✅ Found {count} canvas metadata records")
                
                # Check general canvases
                result = conn.execute(text(
                    "SELECT COUNT(*) FROM canvas_metadata WHERE canvas_type = 'general'"
                ))
                general_count = result.scalar()
                print(f"   - General canvases: {general_count}")
                
                # Check asset canvases
                result = conn.execute(text(
                    "SELECT COUNT(*) FROM canvas_metadata WHERE canvas_type = 'asset'"
                ))
                asset_count = result.scalar()
                print(f"   - Asset canvases: {asset_count}")
                
                # Check storyboard canvases
                result = conn.execute(text(
                    "SELECT COUNT(*) FROM canvas_metadata WHERE canvas_type = 'storyboard'"
                ))
                storyboard_count = result.scalar()
                print(f"   - Storyboard canvases: {storyboard_count}")
                
                # Verify legacy_id mapping for migrated canvases
                result = conn.execute(text(
                    "SELECT COUNT(*) FROM canvas_metadata WHERE legacy_id IS NOT NULL"
                ))
                legacy_count = result.scalar()
                if legacy_count > 0:
                    print(f"✅ Found {legacy_count} canvases with legacy_id mapping")
                
                return True
            else:
                self.warn("No canvas metadata records found (this is OK if database is empty)")
                return True
    
    def verify_data_integrity(self) -> bool:
        """Verify data integrity constraints"""
        print("\n=== Checking Data Integrity ===")
        
        with self.engine.connect() as conn:
            # Check if canvases table exists
            tables = self.inspector.get_table_names()
            if 'canvases' not in tables:
                self.warn("canvases table does not exist yet - skipping canvas content check")
                orphaned_metadata = 0
            else:
                # Check that all canvas_metadata records have corresponding canvas content
                result = conn.execute(text("""
                    SELECT COUNT(*) 
                    FROM canvas_metadata cm
                    LEFT JOIN canvases c ON cm.id = c.id
                    WHERE c.id IS NULL
                """))
                orphaned_metadata = result.scalar()
            
            self.check(
                orphaned_metadata == 0,
                f"All canvas metadata records have corresponding canvas content",
                f"Found {orphaned_metadata} canvas metadata records without canvas content"
            )
            
            # Check that related_entity_id is set for asset and storyboard canvases
            result = conn.execute(text("""
                SELECT COUNT(*) 
                FROM canvas_metadata
                WHERE canvas_type IN ('asset', 'storyboard') 
                AND related_entity_id IS NULL
            """))
            missing_entity_id = result.scalar()
            
            self.check(
                missing_entity_id == 0,
                "All asset/storyboard canvases have related_entity_id",
                f"Found {missing_entity_id} asset/storyboard canvases without related_entity_id"
            )
            
            # Check that general canvases don't have related_entity_id
            result = conn.execute(text("""
                SELECT COUNT(*) 
                FROM canvas_metadata
                WHERE canvas_type = 'general' 
                AND related_entity_id IS NOT NULL
            """))
            invalid_general = result.scalar()
            
            self.check(
                invalid_general == 0,
                "General canvases don't have related_entity_id",
                f"Found {invalid_general} general canvases with related_entity_id"
            )
            
            return orphaned_metadata == 0 and missing_entity_id == 0 and invalid_general == 0
    
    def verify_project_relationship(self) -> bool:
        """Verify that ProjectDB relationship is working"""
        print("\n=== Checking Project Relationship ===")
        
        with self.engine.connect() as conn:
            # Check that all canvas_metadata records reference valid projects
            result = conn.execute(text("""
                SELECT COUNT(*) 
                FROM canvas_metadata cm
                LEFT JOIN projects p ON cm.project_id = p.id
                WHERE p.id IS NULL
            """))
            orphaned_canvases = result.scalar()
            
            self.check(
                orphaned_canvases == 0,
                "All canvas metadata records reference valid projects",
                f"Found {orphaned_canvases} canvas metadata records with invalid project_id"
            )
            
            return orphaned_canvases == 0
    
    def run_all_checks(self) -> bool:
        """Run all verification checks"""
        print("=" * 60)
        print("Canvas Metadata Migration Verification")
        print("=" * 60)
        print(f"Database: {self.db_path}")
        
        if not os.path.exists(self.db_path):
            print(f"\n❌ Database file does not exist: {self.db_path}")
            return False
        
        # Run all checks
        table_exists = self.verify_table_exists()
        if not table_exists:
            print("\n❌ Cannot continue verification - table does not exist")
            return False
        
        self.verify_columns()
        self.verify_indexes()
        self.verify_foreign_keys()
        self.verify_data_migration()
        self.verify_data_integrity()
        self.verify_project_relationship()
        
        # Print summary
        print("\n" + "=" * 60)
        print("Verification Summary")
        print("=" * 60)
        print(f"Total checks: {self.total_checks}")
        print(f"Passed: {self.success_count}")
        print(f"Failed: {len(self.errors)}")
        print(f"Warnings: {len(self.warnings)}")
        
        if self.errors:
            print("\n❌ Errors:")
            for error in self.errors:
                print(f"   - {error}")
        
        if self.warnings:
            print("\n⚠️  Warnings:")
            for warning in self.warnings:
                print(f"   - {warning}")
        
        if len(self.errors) == 0:
            print("\n✅ All checks passed! Migration is successful.")
            return True
        else:
            print("\n❌ Migration verification failed. Please review the errors above.")
            return False


def main():
    """Main entry point"""
    verifier = MigrationVerifier(DB_PATH)
    success = verifier.run_all_checks()
    sys.exit(0 if success else 1)


if __name__ == "__main__":
    main()
