# File: migrations/env.py

import os
import sys
import warnings
import json
import importlib
from logging.config import fileConfig
from sqlalchemy import create_engine, pool
from alembic import context

# ─── Suppress harmless warnings about FK cycles ───────────────────────────────
warnings.filterwarnings(
    "ignore",
    r"Cannot correctly sort tables; there are unresolvable cycles between tables.*"
)

# ─── Ensure project root is on sys.path ──────────────────────────────────────
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, project_root)

# ─── Load environment vars so DB URL is available ────────────────────────────
from dotenv import load_dotenv, find_dotenv
dotenv = find_dotenv()
if dotenv:
    load_dotenv(dotenv, override=True)

# ─── Dynamically import every plugin’s models *before* capturing metadata ────
plugins_dir = os.path.join(project_root, "plugins")
for plugin in sorted(os.listdir(plugins_dir)):
    manifest = os.path.join(plugins_dir, plugin, "plugin.json")
    if not os.path.isfile(manifest):
        continue
    try:
        meta = json.load(open(manifest))
    except Exception:
        continue
    for model_mod in meta.get("models", []):
        try:
            importlib.import_module(model_mod)
        except ImportError:
            pass
    for sp in meta.get("subplugins", []):
        for model_mod in sp.get("models", []):
            try:
                importlib.import_module(model_mod)
            except ImportError:
                pass

# ─── Alembic config & logging ────────────────────────────────────────────────
config = context.config
fileConfig(config.config_file_name)

# ─── Now import the application’s metadata ───────────────────────────────────
from app import db
target_metadata = db.metadata

# ─── Hook to skip unwanted objects (never drop tables) ───────────────────────
def include_object(obj, name, type_, reflected, compare_to):
    # skip tables present in DB but not in models
    if type_ == "table" and reflected and compare_to is None:
        return False
    # skip constraints & indexes
    if type_ in ("foreign_key_constraint", "unique_constraint", "index"):
        return False
    return True

# ─── Helper to build the DB URL ───────────────────────────────────────────────
def get_url():
    url = config.get_main_option("sqlalchemy.url")
    if url:
        return url.strip()
    url = os.environ.get("DATABASE_URL")
    if url:
        return url
    u = os.environ.get("MYSQL_USER")
    p = os.environ.get("MYSQL_PASSWORD")
    h = os.environ.get("MYSQL_HOST", "db")
    pt= os.environ.get("MYSQL_PORT", "3306")
    dbn= os.environ.get("MYSQL_DATABASE")
    if u and p and dbn:
        return f"mysql+pymysql://{u}:{p}@{h}:{pt}/{dbn}"
    raise RuntimeError("No DB URL configured")

# ─── Offline migrations ──────────────────────────────────────────────────────
def run_migrations_offline():
    context.configure(
        url=get_url(),
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
        compare_type=True,
        compare_server_default=True,
        include_object=include_object,
    )
    with context.begin_transaction():
        context.run_migrations()

# ─── Online migrations ───────────────────────────────────────────────────────
def run_migrations_online():
    engine = create_engine(get_url(), poolclass=pool.NullPool)
    with engine.connect() as conn:
        context.configure(
            connection=conn,
            target_metadata=target_metadata,
            compare_type=True,
            compare_server_default=True,
            include_object=include_object,
        )
        with context.begin_transaction():
            context.run_migrations()

# ─── Entrypoint ─────────────────────────────────────────────────────────────
if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()
