# alembic/env.py
"""
Alembic migration environment configuration.

This file is responsible for:
1. Importing ALL database models so Alembic can detect schema changes
2. Configuring the database connection
3. Running migrations in online/offline mode

CRITICAL: Every model in models/database/__init__.py must be imported here!
"""

import os
import sys
from logging.config import fileConfig

from sqlalchemy import engine_from_config, pool

from alembic import context

# Add your project directory to the Python path
sys.path.append(os.path.dirname(os.path.dirname(__file__)))

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

# ============================================================================
# IMPORT ALL DATABASE MODELS
# ============================================================================
# CRITICAL: Every model must be imported here so Alembic can detect tables!
# If a model is not imported, Alembic will not create/update its table.
# ============================================================================

print("[ALEMBIC] Importing database models...")
print("=" * 70)

_import_errors = []

# ----------------------------------------------------------------------------
# CORE MODULE (1 model)
# ----------------------------------------------------------------------------
try:
    from app.modules.core.models import AdminMenuConfig  # noqa: F401

    print("  ✓ Core models (1)")
except ImportError as e:
    _import_errors.append(f"core: {e}")
    print(f"  ✗ Core models failed: {e}")

# ----------------------------------------------------------------------------
# TENANCY MODULE (15 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.tenancy.models import (  # noqa: F401
        AdminAuditLog,
        AdminPlatform,
        AdminSession,
        AdminSetting,
        ApplicationLog,
        Merchant,
        Platform,
        PlatformAlert,
        PlatformModule,
        Role,
        Store,
        StoreDomain,
        StorePlatform,
        StoreUser,
        User,
    )

    print("  ✓ Tenancy models (15)")
except ImportError as e:
    _import_errors.append(f"tenancy: {e}")
    print(f"  ✗ Tenancy models failed: {e}")

# ----------------------------------------------------------------------------
# BILLING MODULE (9 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.billing.models import (  # noqa: F401
        AddOnProduct,
        BillingHistory,
        MerchantFeatureOverride,
        MerchantSubscription,
        StoreAddOn,
        StripeWebhookEvent,
        SubscriptionTier,
        TierFeatureLimit,
    )

    print("  ✓ Billing models (8)")
except ImportError as e:
    _import_errors.append(f"billing: {e}")
    print(f"  ✗ Billing models failed: {e}")

# ----------------------------------------------------------------------------
# CATALOG MODULE (3 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.catalog.models import (  # noqa: F401
        Product,
        ProductMedia,
        ProductTranslation,
    )

    print("  ✓ Catalog models (3)")
except ImportError as e:
    _import_errors.append(f"catalog: {e}")
    print(f"  ✗ Catalog models failed: {e}")

# ----------------------------------------------------------------------------
# MARKETPLACE MODULE (10 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.marketplace.models import (  # noqa: F401
        LetzshopFulfillmentQueue,
        LetzshopHistoricalImportJob,
        LetzshopStoreCache,
        LetzshopSyncLog,
        MarketplaceImportError,
        MarketplaceImportJob,
        MarketplaceProduct,
        MarketplaceProductTranslation,
        StoreLetzshopCredentials,
        StoreOnboarding,
    )

    print("  ✓ Marketplace models (10)")
except ImportError as e:
    _import_errors.append(f"marketplace: {e}")
    print(f"  ✗ Marketplace models failed: {e}")

# ----------------------------------------------------------------------------
# CMS MODULE (3 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.cms.models import (  # noqa: F401
        ContentPage,
        MediaFile,
        StoreTheme,
    )

    print("  ✓ CMS models (3)")
except ImportError as e:
    _import_errors.append(f"cms: {e}")
    print(f"  ✗ CMS models failed: {e}")

# ----------------------------------------------------------------------------
# CUSTOMERS MODULE (3 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.customers.models import (  # noqa: F401
        Customer,
        CustomerAddress,
        PasswordResetToken,
    )

    print("  ✓ Customers models (3)")
except ImportError as e:
    _import_errors.append(f"customers: {e}")
    print(f"  ✗ Customers models failed: {e}")

# ----------------------------------------------------------------------------
# ORDERS MODULE (5 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.orders.models import (  # noqa: F401
        Invoice,
        Order,
        OrderItem,
        OrderItemException,
        StoreInvoiceSettings,
    )

    print("  ✓ Orders models (5)")
except ImportError as e:
    _import_errors.append(f"orders: {e}")
    print(f"  ✗ Orders models failed: {e}")

# ----------------------------------------------------------------------------
# INVENTORY MODULE (2 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.inventory.models import (  # noqa: F401
        Inventory,
        InventoryTransaction,
    )

    print("  ✓ Inventory models (2)")
except ImportError as e:
    _import_errors.append(f"inventory: {e}")
    print(f"  ✗ Inventory models failed: {e}")

# ----------------------------------------------------------------------------
# CART MODULE (1 model)
# ----------------------------------------------------------------------------
try:
    from app.modules.cart.models import CartItem  # noqa: F401

    print("  ✓ Cart models (1)")
except ImportError as e:
    _import_errors.append(f"cart: {e}")
    print(f"  ✗ Cart models failed: {e}")

# ----------------------------------------------------------------------------
# MESSAGING MODULE (9 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.messaging.models import (  # noqa: F401
        AdminNotification,
        Conversation,
        ConversationParticipant,
        EmailLog,
        EmailTemplate,
        Message,
        MessageAttachment,
        StoreEmailSettings,
        StoreEmailTemplate,
    )

    print("  ✓ Messaging models (9)")
except ImportError as e:
    _import_errors.append(f"messaging: {e}")
    print(f"  ✗ Messaging models failed: {e}")

# ----------------------------------------------------------------------------
# LOYALTY MODULE (6 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.loyalty.models import (  # noqa: F401
        AppleDeviceRegistration,
        LoyaltyCard,
        LoyaltyProgram,
        LoyaltyTransaction,
        MerchantLoyaltySettings,
        StaffPin,
    )

    print("  ✓ Loyalty models (6)")
except ImportError as e:
    _import_errors.append(f"loyalty: {e}")
    print(f"  ✗ Loyalty models failed: {e}")

# ----------------------------------------------------------------------------
# DEV_TOOLS MODULE (8 models)
# ----------------------------------------------------------------------------
try:
    from app.modules.dev_tools.models import (  # noqa: F401
        ArchitectureRule,
        ArchitectureScan,
        ArchitectureViolation,
        TestCollection,
        TestResult,
        TestRun,
        ViolationAssignment,
        ViolationComment,
    )

    print("  ✓ Dev Tools models (8)")
except ImportError as e:
    _import_errors.append(f"dev_tools: {e}")
    print(f"  ✗ Dev Tools models failed: {e}")

# ----------------------------------------------------------------------------
# MONITORING MODULE (1 model)
# ----------------------------------------------------------------------------
try:
    from app.modules.monitoring.models import (  # noqa: F401
        CapacitySnapshot,
    )

    print("  ✓ Monitoring models (1)")
except ImportError as e:
    _import_errors.append(f"monitoring: {e}")
    print(f"  ✗ Monitoring models failed: {e}")

# ============================================================================
# SUMMARY
# ============================================================================
print("=" * 70)
if _import_errors:
    print(f"[ALEMBIC] WARNING: {len(_import_errors)} import error(s):")
    for err in _import_errors:
        print(f"  - {err}")
    print("=" * 70)

print(f"[ALEMBIC] Total tables in metadata: {len(Base.metadata.tables)}")
print("=" * 70)
print()

# ============================================================================
# ALEMBIC CONFIGURATION
# ============================================================================

# Alembic Config object
config = context.config

# Override sqlalchemy.url with our settings
config.set_main_option("sqlalchemy.url", settings.database_url)

if config.config_file_name is not None:
    fileConfig(config.config_file_name)

# Set target metadata from Base
target_metadata = Base.metadata


# ============================================================================
# MODULE MIGRATIONS DISCOVERY
# ============================================================================
# Discover migration paths from self-contained modules.
# Each module can have its own migrations/ directory.
# ============================================================================

def get_version_locations() -> list[str]:
    """
    Get all version locations including module migrations.

    Returns:
        List of paths to migration version directories
    """
    try:
        from app.modules.migrations import get_all_migration_paths

        paths = get_all_migration_paths()
        locations = [str(p) for p in paths if p.exists()]

        if len(locations) > 1:
            print(f"[ALEMBIC] Found {len(locations)} migration locations:")
            for loc in locations:
                print(f"  - {loc}")

        return locations
    except ImportError:
        # Fallback if module migrations not available
        return ["alembic/versions"]


# Get version locations for multi-directory support
version_locations = get_version_locations()


def run_migrations_offline() -> None:
    """
    Run migrations in 'offline' mode.

    This configures the context with just a URL and not an Engine,
    though an Engine is acceptable here as well. By skipping the Engine
    creation we don't even need a DBAPI to be available.

    Calls to context.execute() here emit the given string to the script output.
    """
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
        url=url,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
        version_locations=version_locations,
    )

    with context.begin_transaction():
        context.run_migrations()


def run_migrations_online() -> None:
    """
    Run migrations in 'online' mode.

    In this scenario we need to create an Engine and associate a connection
    with the context.
    """
    connectable = engine_from_config(
        config.get_section(config.config_ini_section, {}),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )

    with connectable.connect() as connection:
        context.configure(
            connection=connection,
            target_metadata=target_metadata,
            version_locations=version_locations,
        )

        with context.begin_transaction():
            context.run_migrations()


# ============================================================================
# MAIN EXECUTION
# ============================================================================

if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()
