"""add multi-platform support

Revision ID: z4e5f6a7b8c9
Revises: 1b398cf45e85
Create Date: 2026-01-18 12:00:00.000000

This migration adds multi-platform support:
1. Creates platforms table for business offerings (OMS, Loyalty, etc.)
2. Creates vendor_platforms junction table for many-to-many relationship
3. Adds platform_id and CMS limits to subscription_tiers
4. Adds platform_id and is_platform_page to content_pages
5. Inserts default "oms" platform
6. Backfills existing data to OMS platform
7. Creates vendor_platforms entries for existing vendors
"""

import json
from collections.abc import Sequence

import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "z4e5f6a7b8c9"
down_revision: str | None = "1b398cf45e85"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None

# Platform marketing page slugs (is_platform_page=True)
PLATFORM_PAGE_SLUGS = [
    "platform_homepage",
    "home",
    "pricing",
    "about",
    "contact",
    "faq",
    "terms",
    "privacy",
    "features",
    "integrations",
]

# CMS limits per tier
CMS_TIER_LIMITS = {
    "essential": {"cms_pages_limit": 3, "cms_custom_pages_limit": 0},
    "professional": {"cms_pages_limit": 10, "cms_custom_pages_limit": 5},
    "business": {"cms_pages_limit": 30, "cms_custom_pages_limit": 20},
    "enterprise": {"cms_pages_limit": None, "cms_custom_pages_limit": None},  # Unlimited
}

# CMS features per tier
CMS_TIER_FEATURES = {
    "essential": ["cms_basic"],
    "professional": ["cms_basic", "cms_custom_pages", "cms_seo"],
    "business": ["cms_basic", "cms_custom_pages", "cms_seo", "cms_templates"],
    "enterprise": ["cms_basic", "cms_custom_pages", "cms_unlimited_pages", "cms_templates", "cms_seo", "cms_scheduling"],
}


def upgrade() -> None:
    conn = op.get_bind()

    # =========================================================================
    # 1. Create platforms table
    # =========================================================================
    op.create_table(
        "platforms",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("code", sa.String(50), nullable=False),
        sa.Column("name", sa.String(100), nullable=False),
        sa.Column("description", sa.Text(), nullable=True),
        sa.Column("domain", sa.String(255), nullable=True),
        sa.Column("path_prefix", sa.String(50), nullable=True),
        sa.Column("logo", sa.String(500), nullable=True),
        sa.Column("logo_dark", sa.String(500), nullable=True),
        sa.Column("favicon", sa.String(500), nullable=True),
        sa.Column("theme_config", sa.JSON(), nullable=True),
        sa.Column("default_language", sa.String(5), nullable=False, server_default="fr"),
        sa.Column("supported_languages", sa.JSON(), nullable=False),
        sa.Column("is_active", sa.Boolean(), nullable=False, server_default="true"),
        sa.Column("is_public", sa.Boolean(), nullable=False, server_default="true"),
        sa.Column("settings", sa.JSON(), nullable=True),
        sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
        sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index("ix_platforms_code", "platforms", ["code"], unique=True)
    op.create_index("ix_platforms_domain", "platforms", ["domain"], unique=True)
    op.create_index("ix_platforms_path_prefix", "platforms", ["path_prefix"], unique=True)
    op.create_index("idx_platform_active", "platforms", ["is_active"])
    op.create_index("idx_platform_public", "platforms", ["is_public", "is_active"])

    # =========================================================================
    # 2. Create vendor_platforms junction table
    # =========================================================================
    op.create_table(
        "vendor_platforms",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("vendor_id", sa.Integer(), nullable=False),
        sa.Column("platform_id", sa.Integer(), nullable=False),
        sa.Column("tier_id", sa.Integer(), nullable=True),
        sa.Column("is_active", sa.Boolean(), nullable=False, server_default="true"),
        sa.Column("is_primary", sa.Boolean(), nullable=False, server_default="false"),
        sa.Column("custom_subdomain", sa.String(100), nullable=True),
        sa.Column("settings", sa.JSON(), nullable=True),
        sa.Column("joined_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
        sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
        sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
        sa.ForeignKeyConstraint(["vendor_id"], ["vendors.id"], ondelete="CASCADE"),
        sa.ForeignKeyConstraint(["platform_id"], ["platforms.id"], ondelete="CASCADE"),
        sa.ForeignKeyConstraint(["tier_id"], ["subscription_tiers.id"], ondelete="SET NULL"),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index("ix_vendor_platforms_vendor_id", "vendor_platforms", ["vendor_id"])
    op.create_index("ix_vendor_platforms_platform_id", "vendor_platforms", ["platform_id"])
    op.create_index("ix_vendor_platforms_tier_id", "vendor_platforms", ["tier_id"])
    op.create_index("idx_vendor_platform_active", "vendor_platforms", ["vendor_id", "platform_id", "is_active"])
    op.create_index("idx_vendor_platform_primary", "vendor_platforms", ["vendor_id", "is_primary"])
    op.create_unique_constraint("uq_vendor_platform", "vendor_platforms", ["vendor_id", "platform_id"])

    # =========================================================================
    # 3. Add platform_id and CMS columns to subscription_tiers
    # =========================================================================
    # Add platform_id column (nullable for global tiers)
    op.add_column(
        "subscription_tiers",
        sa.Column("platform_id", sa.Integer(), nullable=True),
    )
    op.create_index("ix_subscription_tiers_platform_id", "subscription_tiers", ["platform_id"])
    op.create_foreign_key(
        "fk_subscription_tiers_platform_id",
        "subscription_tiers",
        "platforms",
        ["platform_id"],
        ["id"],
        ondelete="CASCADE",
    )

    # Add CMS limit columns
    op.add_column(
        "subscription_tiers",
        sa.Column("cms_pages_limit", sa.Integer(), nullable=True),
    )
    op.add_column(
        "subscription_tiers",
        sa.Column("cms_custom_pages_limit", sa.Integer(), nullable=True),
    )
    op.create_index("idx_tier_platform_active", "subscription_tiers", ["platform_id", "is_active"])

    # =========================================================================
    # 4. Add platform_id and is_platform_page to content_pages
    # =========================================================================
    # Add platform_id column (will be set to NOT NULL after backfill)
    op.add_column(
        "content_pages",
        sa.Column("platform_id", sa.Integer(), nullable=True),
    )
    op.create_index("ix_content_pages_platform_id", "content_pages", ["platform_id"])

    # Add is_platform_page column
    op.add_column(
        "content_pages",
        sa.Column("is_platform_page", sa.Boolean(), nullable=False, server_default="false"),
    )
    op.create_index("idx_platform_page_type", "content_pages", ["platform_id", "is_platform_page"])

    # =========================================================================
    # 5. Insert default OMS platform
    # =========================================================================
    conn.execute(
        sa.text("""
            INSERT INTO platforms (code, name, description, domain, path_prefix, default_language,
                                   supported_languages, is_active, is_public, theme_config, settings,
                                   created_at, updated_at)
            VALUES ('oms', 'Wizamart OMS', 'Order Management System for Luxembourg merchants',
                    'omsflow.lu', 'oms', 'fr', '["fr", "de", "en"]', true, true, '{}', '{}',
                    CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
        """)
    )

    # Get OMS platform ID for backfilling
    result = conn.execute(sa.text("SELECT id FROM platforms WHERE code = 'oms'"))
    oms_platform_id = result.fetchone()[0]

    # =========================================================================
    # 6. Backfill content_pages with platform_id
    # =========================================================================
    conn.execute(
        sa.text(f"UPDATE content_pages SET platform_id = {oms_platform_id} WHERE platform_id IS NULL")
    )

    # Set is_platform_page=True for platform marketing page slugs
    # Only for pages that have vendor_id=NULL (platform-level pages)
    slugs_list = ", ".join([f"'{slug}'" for slug in PLATFORM_PAGE_SLUGS])
    conn.execute(
        sa.text(f"""
            UPDATE content_pages
            SET is_platform_page = true
            WHERE vendor_id IS NULL AND slug IN ({slugs_list})
        """)
    )

    # Make platform_id NOT NULL after backfill
    op.alter_column("content_pages", "platform_id", nullable=False)

    # Add foreign key constraint
    op.create_foreign_key(
        "fk_content_pages_platform_id",
        "content_pages",
        "platforms",
        ["platform_id"],
        ["id"],
        ondelete="CASCADE",
    )

    # =========================================================================
    # 7. Update content_pages constraints
    # =========================================================================
    # Drop old unique constraint
    op.drop_constraint("uq_vendor_slug", "content_pages", type_="unique")

    # Create new unique constraint including platform_id
    op.create_unique_constraint(
        "uq_platform_vendor_slug",
        "content_pages",
        ["platform_id", "vendor_id", "slug"],
    )

    # Update indexes
    op.drop_index("idx_vendor_published", table_name="content_pages")
    op.drop_index("idx_slug_published", table_name="content_pages")
    op.create_index("idx_platform_vendor_published", "content_pages", ["platform_id", "vendor_id", "is_published"])
    op.create_index("idx_platform_slug_published", "content_pages", ["platform_id", "slug", "is_published"])

    # =========================================================================
    # 8. Update subscription_tiers with CMS limits
    # =========================================================================
    for tier_code, limits in CMS_TIER_LIMITS.items():
        cms_pages = limits["cms_pages_limit"] if limits["cms_pages_limit"] is not None else "NULL"
        cms_custom = limits["cms_custom_pages_limit"] if limits["cms_custom_pages_limit"] is not None else "NULL"
        conn.execute(
            sa.text(f"""
                UPDATE subscription_tiers
                SET cms_pages_limit = {cms_pages},
                    cms_custom_pages_limit = {cms_custom}
                WHERE code = '{tier_code}'
            """)
        )

    # Add CMS features to each tier
    for tier_code, cms_features in CMS_TIER_FEATURES.items():
        # Get current features
        result = conn.execute(
            sa.text(f"SELECT features FROM subscription_tiers WHERE code = '{tier_code}'")
        )
        row = result.fetchone()
        if row and row[0]:
            current_features = json.loads(row[0]) if isinstance(row[0], str) else row[0]
        else:
            current_features = []

        # Add CMS features that aren't already present
        for feature in cms_features:
            if feature not in current_features:
                current_features.append(feature)

        # Update features
        features_json = json.dumps(current_features)
        conn.execute(
            sa.text(f"UPDATE subscription_tiers SET features = '{features_json}' WHERE code = '{tier_code}'")
        )

    # =========================================================================
    # 9. Create vendor_platforms entries for existing vendors
    # =========================================================================
    # Get all vendors with their subscription tier_id
    conn.execute(
        sa.text(f"""
            INSERT INTO vendor_platforms (vendor_id, platform_id, tier_id, is_active, is_primary,
                                          joined_at, created_at, updated_at)
            SELECT v.id, {oms_platform_id}, vs.tier_id, v.is_active, true,
                   v.created_at, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
            FROM vendors v
            LEFT JOIN vendor_subscriptions vs ON vs.vendor_id = v.id
        """)
    )

    # =========================================================================
    # 10. Add CMS feature records to features table
    # =========================================================================
    # Get minimum tier IDs for CMS features
    tier_ids = {}
    result = conn.execute(sa.text("SELECT id, code FROM subscription_tiers"))
    for row in result:
        tier_ids[row[1]] = row[0]

    cms_features = [
        ("cms", "cms_basic", "Basic CMS", "Override default pages with custom content", "settings", "document-text", None, tier_ids.get("essential"), 1),
        ("cms", "cms_custom_pages", "Custom Pages", "Create custom pages beyond defaults", "settings", "document-add", None, tier_ids.get("professional"), 2),
        ("cms", "cms_unlimited_pages", "Unlimited Pages", "No page limit", "settings", "documents", None, tier_ids.get("enterprise"), 3),
        ("cms", "cms_templates", "Page Templates", "Access to page templates", "settings", "template", None, tier_ids.get("business"), 4),
        ("cms", "cms_seo", "Advanced SEO", "SEO metadata and optimization", "settings", "search", None, tier_ids.get("professional"), 5),
        ("cms", "cms_scheduling", "Page Scheduling", "Schedule page publish/unpublish", "settings", "clock", None, tier_ids.get("enterprise"), 6),
    ]

    for category, code, name, description, ui_location, ui_icon, _ui_route, minimum_tier_id, display_order in cms_features:
        min_tier_val = minimum_tier_id if minimum_tier_id else "NULL"
        conn.execute(
            sa.text(f"""
                INSERT INTO features (code, name, description, category, ui_location, ui_icon, ui_route,
                                      minimum_tier_id, is_active, is_visible, display_order, created_at, updated_at)
                VALUES ('{code}', '{name}', '{description}', '{category}', '{ui_location}', '{ui_icon}', NULL,
                        {min_tier_val}, true, true, {display_order}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
                ON CONFLICT (code) DO NOTHING
            """)
        )


def downgrade() -> None:
    conn = op.get_bind()

    # Remove CMS features from features table
    conn.execute(
        sa.text("""
            DELETE FROM features
            WHERE code IN ('cms_basic', 'cms_custom_pages', 'cms_unlimited_pages',
                           'cms_templates', 'cms_seo', 'cms_scheduling')
        """)
    )

    # Remove CMS features from subscription_tiers
    result = conn.execute(sa.text("SELECT id, code, features FROM subscription_tiers"))
    for row in result:
        tier_id, tier_code, features_data = row
        if features_data:
            current_features = json.loads(features_data) if isinstance(features_data, str) else features_data
            # Remove CMS features
            updated_features = [f for f in current_features if not f.startswith("cms_")]
            features_json = json.dumps(updated_features)
            conn.execute(
                sa.text(f"UPDATE subscription_tiers SET features = '{features_json}' WHERE id = {tier_id}")
            )

    # Drop vendor_platforms table
    op.drop_table("vendor_platforms")

    # Restore old content_pages constraints
    op.drop_constraint("uq_platform_vendor_slug", "content_pages", type_="unique")
    op.drop_index("idx_platform_vendor_published", table_name="content_pages")
    op.drop_index("idx_platform_slug_published", table_name="content_pages")
    op.drop_index("idx_platform_page_type", table_name="content_pages")
    op.drop_constraint("fk_content_pages_platform_id", "content_pages", type_="foreignkey")
    op.drop_index("ix_content_pages_platform_id", table_name="content_pages")
    op.drop_column("content_pages", "is_platform_page")
    op.drop_column("content_pages", "platform_id")
    op.create_unique_constraint("uq_vendor_slug", "content_pages", ["vendor_id", "slug"])
    op.create_index("idx_vendor_published", "content_pages", ["vendor_id", "is_published"])
    op.create_index("idx_slug_published", "content_pages", ["slug", "is_published"])

    # Remove subscription_tiers platform columns
    op.drop_index("idx_tier_platform_active", table_name="subscription_tiers")
    op.drop_constraint("fk_subscription_tiers_platform_id", "subscription_tiers", type_="foreignkey")
    op.drop_index("ix_subscription_tiers_platform_id", table_name="subscription_tiers")
    op.drop_column("subscription_tiers", "cms_custom_pages_limit")
    op.drop_column("subscription_tiers", "cms_pages_limit")
    op.drop_column("subscription_tiers", "platform_id")

    # Drop platforms table
    op.drop_index("idx_platform_public", table_name="platforms")
    op.drop_index("idx_platform_active", table_name="platforms")
    op.drop_index("ix_platforms_path_prefix", table_name="platforms")
    op.drop_index("ix_platforms_domain", table_name="platforms")
    op.drop_index("ix_platforms_code", table_name="platforms")
    op.drop_table("platforms")
