#!/usr/bin/env python3
import asyncio
import importlib
import os
import sys
import uuid
import enum
from pathlib import Path
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy import inspect, text, UniqueConstraint, Index, Enum as SQLEnum
from sqlalchemy.schema import CreateTable
from sqlalchemy.sql import func

# Backend hozzáadása a path-hoz
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from app.database import Base
from app.core.config import settings

def dynamic_import_models():
    models_dir = Path(__file__).parent.parent / "models"
    for py_file in models_dir.glob("*.py"):
        if py_file.name == "__init__.py": continue
        module_name = f"app.models.{py_file.stem}"
        try:
            importlib.import_module(module_name)
            print(f"✅ Imported {module_name}")
        except Exception as e:
            print(f"⚠️ Could not import {module_name}: {e}")
    import app.models
    print(f"📦 Total tables in Base.metadata: {len(Base.metadata.tables)}")

async def compare_and_repair(apply: bool = False):
    print(f"🔗 Connecting to database... (Apply mode: {apply})")
    engine = create_async_engine(str(settings.SQLALCHEMY_DATABASE_URI))
    
    def get_diff_and_repair(connection):
        inspector = inspect(connection)
        
        # 1. KITERJESZTÉSEK ÉS SÉMÁK
        schemas = sorted({t.schema for t in Base.metadata.sorted_tables if t.schema})
        db_schemas = inspector.get_schema_names()
        
        if apply:
            print("🔧 Ensuring extensions and schemas...")
            connection.execute(text('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'))
            try: connection.execute(text('CREATE EXTENSION IF NOT EXISTS "postgis"'))
            except Exception: pass
            
            for schema in schemas:
                if schema not in db_schemas:
                    connection.execute(text(f'CREATE SCHEMA IF NOT EXISTS "{schema}"'))

            # Search path beállítása a típusok felismeréséhez
            search_path = ", ".join([f'"{s}"' for s in schemas]) + ", public"
            connection.execute(text(f"SET search_path TO {search_path}"))

        # 2. OKOS ENUM LÉTREHOZÁS (Case-Insensitive támogatással)
        print("🔧 Checking custom Enum types...")
        for table in Base.metadata.sorted_tables:
            for col in table.columns:
                if isinstance(col.type, SQLEnum):
                    enum_name = col.type.name
                    schema = table.schema or 'public'
                    check_enum = connection.execute(text(
                        "SELECT 1 FROM pg_type t JOIN pg_namespace n ON n.oid = t.typnamespace "
                        "WHERE t.typname = :name AND n.nspname = :schema"
                    ), {"name": enum_name, "schema": schema}).fetchone()
                    
                    if not check_enum and apply:
                        # TRÜKK: Hozzáadjuk a kis- és nagybetűs változatokat is, hogy ne bukjon el a DEFAULT-on
                        all_variants = set()
                        for val in col.type.enums:
                            all_variants.add(val)
                            all_variants.add(val.lower())
                            all_variants.add(val.upper())
                        
                        labels = ", ".join([f"'{l}'" for l in sorted(list(all_variants))])
                        print(f"➕ Creating Enum {schema}.{enum_name} with variants...")
                        connection.execute(text(f'CREATE TYPE "{schema}"."{enum_name}" AS ENUM ({labels})'))

        # 3. TÁBLÁK ÉS OSZLOPOK SZINKRONIZÁLÁSA
        db_tables_cache = {s: inspector.get_table_names(schema=s) for s in schemas}
        db_tables_cache[None] = inspector.get_table_names()

        for table in Base.metadata.sorted_tables:
            if table.name not in db_tables_cache.get(table.schema, []):
                print(f"❌ Missing table: {table.schema}.{table.name}")
                if apply:
                    try:
                        connection.execute(CreateTable(table))
                        print(f"✅ Table {table.schema}.{table.name} created.")
                    except Exception as e:
                        print(f"🔥 Error creating {table.name}: {e}")
                continue

            # Oszlop szinkronizálás
            db_cols = {c['name']: c for c in inspector.get_columns(table.name, schema=table.schema)}
            for col in table.columns:
                if col.name not in db_cols:
                    col_type = col.type.compile(dialect=connection.dialect)
                    sql = f'ALTER TABLE "{table.schema}"."{table.name}" ADD COLUMN "{col.name}" {col_type}'
                    if not col.nullable: sql += " NOT NULL"
                    
                    if col.default is not None:
                        arg = col.default.arg
                        if callable(arg):
                            if "uuid" in col.name.lower(): sql += " DEFAULT gen_random_uuid()"
                            elif "now" in str(arg).lower(): sql += " DEFAULT NOW()"
                        elif isinstance(arg, enum.Enum):
                            sql += f" DEFAULT '{arg.value}'"
                        else:
                            val = f"'{arg}'" if isinstance(arg, str) else arg
                            sql += f" DEFAULT {val}"
                    
                    print(f"⚠️ Adding column: {table.schema}.{table.name}.{col.name}")
                    if apply: connection.execute(text(sql))

        print("\n--- ✅ Synchronization cycle complete. ---")

    async with engine.begin() as conn:
        await conn.run_sync(get_diff_and_repair)
    await engine.dispose()

async def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('--apply', action='store_true')
    args = parser.parse_args()
    dynamic_import_models()
    await compare_and_repair(apply=args.apply)
    print("\n✨ Minden tábla és típus szinkronizálva!")

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