# app/modules/routes.py
"""
Module route discovery for FastAPI.

Provides utilities to:
- Discover route modules from all registered modules
- Auto-register API and page routes from self-contained modules

This module bridges the gap between the module system and FastAPI,
allowing routes to be defined within modules and automatically
discovered and registered.

Route Discovery:
    Routes are discovered from these file locations in each module:
    - routes/api/admin.py      -> /api/v1/admin/*
    - routes/api/store.py     -> /api/v1/store/*
    - routes/api/storefront.py -> /api/v1/storefront/*
    - routes/pages/admin.py    -> /admin/*
    - routes/pages/store.py   -> /store/*

Usage:
    # In app/api/v1/{admin,store,storefront}/__init__.py
    from app.modules.routes import get_admin_api_routes  # or store/storefront

    for route_info in get_admin_api_routes():
        router.include_router(
            route_info.router,
            prefix=route_info.custom_prefix or "",
            tags=route_info.tags,
        )

Route Configuration:
    Modules can export a ROUTE_CONFIG dict to customize route registration:

    ROUTE_CONFIG = {
        "prefix": "/content-pages",  # Custom prefix (replaces default)
        "tags": ["admin-content-pages"],  # Custom tags
        "priority": 100,  # Higher = registered later (for catch-all routes)
    }
"""

import importlib
import logging
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from fastapi import APIRouter

logger = logging.getLogger(__name__)


@dataclass
class RouteInfo:
    """Information about a discovered route."""

    router: "APIRouter"
    prefix: str
    tags: list[str]
    include_in_schema: bool = True
    module_code: str = ""
    route_type: str = ""  # "api" or "pages"
    frontend: str = ""  # "admin", "store", "storefront"
    priority: int = 0  # Higher = registered later (for catch-all routes)
    custom_prefix: str = ""  # Custom prefix from ROUTE_CONFIG


def discover_module_routes() -> list[RouteInfo]:
    """
    Discover routes from all registered self-contained modules.

    Scans all modules in the registry and returns RouteInfo objects for
    modules that have routes directories.

    Route discovery looks for:
    - routes/api/admin.py -> admin API routes
    - routes/api/store.py -> store API routes
    - routes/api/storefront.py -> storefront API routes
    - routes/pages/admin.py -> admin page routes
    - routes/pages/store.py -> store page routes

    Returns:
        List of RouteInfo objects with router and registration info

    Example:
        >>> routes = discover_module_routes()
        >>> for route in routes:
        ...     print(f"{route.module_code}: {route.route_type}/{route.frontend}")
        analytics: pages/store
        cms: api/admin
        cms: api/store
        cms: pages/admin
        cms: pages/store
    """
    # Import here to avoid circular imports
    from app.modules.registry import MODULES

    routes: list[RouteInfo] = []

    for module in MODULES.values():
        if not module.is_self_contained:
            continue

        module_routes = _discover_module_routes(module.code)
        routes.extend(module_routes)

    logger.info(f"Discovered {len(routes)} routes from self-contained modules")
    return routes


def _discover_module_routes(module_code: str) -> list[RouteInfo]:
    """
    Discover routes for a specific module.

    Args:
        module_code: Module code (e.g., "analytics", "cms")

    Returns:
        List of RouteInfo for this module
    """
    routes: list[RouteInfo] = []
    dir_name = module_code.replace("-", "_")
    module_path = Path(__file__).parent / dir_name

    if not module_path.exists():
        return routes

    routes_path = module_path / "routes"
    if not routes_path.exists():
        return routes

    # Discover API routes (with fallback to routes/ for legacy modules)
    api_routes = _discover_routes_in_dir(
        module_code, dir_name, routes_path / "api", "api",
        fallback_dir=routes_path  # Allow routes/admin.py as fallback
    )
    routes.extend(api_routes)

    # Discover page routes
    page_routes = _discover_routes_in_dir(
        module_code, dir_name, routes_path / "pages", "pages"
    )
    routes.extend(page_routes)

    return routes


def _discover_routes_in_dir(
    module_code: str, dir_name: str, routes_dir: Path, route_type: str,
    fallback_dir: Path | None = None
) -> list[RouteInfo]:
    """
    Discover routes in a specific directory (api/ or pages/).

    Args:
        module_code: Module code for tags
        dir_name: Directory name (module_code with _ instead of -)
        routes_dir: Path to routes/api/ or routes/pages/
        route_type: "api" or "pages"
        fallback_dir: Optional fallback directory (e.g., routes/ for modules
                     with routes/admin.py instead of routes/api/admin.py)

    Returns:
        List of RouteInfo for discovered routes
    """
    routes: list[RouteInfo] = []

    # Look for admin.py, store.py, storefront.py, public.py, webhooks.py
    frontends = {
        "admin": {
            "api_prefix": "/api/v1/admin",
            "pages_prefix": "/admin",
            "include_in_schema": True,
        },
        "store": {
            "api_prefix": "/api/v1/store",
            "pages_prefix": "/store",
            "include_in_schema": route_type == "api",
        },
        "storefront": {
            "api_prefix": "/api/v1/storefront",
            "pages_prefix": "/storefront",
            "include_in_schema": route_type == "api",
        },
        "platform": {
            "api_prefix": "/api/v1/platform",
            "pages_prefix": "/platform",
            "include_in_schema": True,
        },
        "webhooks": {
            "api_prefix": "/api/v1/webhooks",
            "pages_prefix": "/webhooks",
            "include_in_schema": True,
        },
        "merchant": {
            "api_prefix": "/api/v1/merchants",
            "pages_prefix": "/merchants",
            "include_in_schema": True,
        },
    }

    for frontend, config in frontends.items():
        # Check primary location first, then fallback
        route_file = routes_dir / f"{frontend}.py" if routes_dir.exists() else None
        use_fallback = False

        if route_file is None or not route_file.exists():
            if fallback_dir and fallback_dir.exists():
                fallback_file = fallback_dir / f"{frontend}.py"
                if fallback_file.exists():
                    route_file = fallback_file
                    use_fallback = True

        if route_file is None or not route_file.exists():
            continue

        try:
            # Import the module
            if use_fallback:
                import_path = f"app.modules.{dir_name}.routes.{frontend}"
            else:
                import_path = f"app.modules.{dir_name}.routes.{route_type}.{frontend}"
            route_module = importlib.import_module(import_path)

            # Get the router (try common names)
            router = None
            for attr_name in ["router", f"{frontend}_router", "api_router", "page_router"]:
                if hasattr(route_module, attr_name):
                    router = getattr(route_module, attr_name)
                    break

            if router is None:
                logger.warning(f"No router found in {import_path}")
                continue

            # Read ROUTE_CONFIG if present
            route_config = getattr(route_module, "ROUTE_CONFIG", {})
            custom_prefix = route_config.get("prefix", "")
            custom_tags = route_config.get("tags", [])
            priority = route_config.get("priority", 0)

            # Determine prefix based on route type
            if route_type == "api":
                prefix = config["api_prefix"]
            else:
                prefix = config["pages_prefix"]

            # Build tags - use custom tags if provided, otherwise default
            tags = custom_tags if custom_tags else [f"{frontend}-{module_code}"]

            route_info = RouteInfo(
                router=router,
                prefix=prefix,
                tags=tags,
                include_in_schema=config["include_in_schema"],
                module_code=module_code,
                route_type=route_type,
                frontend=frontend,
                priority=priority,
                custom_prefix=custom_prefix,
            )
            routes.append(route_info)

            logger.debug(f"Discovered route: {module_code} {route_type}/{frontend}")

        except ImportError as e:
            logger.warning(f"Failed to import {import_path}: {e}")
        except Exception as e:
            logger.error(f"Error discovering routes in {route_file}: {e}")

    return routes


def get_api_routes() -> list[RouteInfo]:
    """Get only API routes from modules."""
    return [r for r in discover_module_routes() if r.route_type == "api"]


def get_page_routes() -> list[RouteInfo]:
    """Get only page routes from modules."""
    return [r for r in discover_module_routes() if r.route_type == "pages"]


def get_store_page_routes() -> list[RouteInfo]:
    """
    Get store page routes from modules, sorted by priority.

    Returns routes sorted by priority (lower first, higher last).
    This ensures catch-all routes (priority 100+) are registered after
    specific routes.
    """
    routes = [r for r in discover_module_routes() if r.route_type == "pages" and r.frontend == "store"]
    return sorted(routes, key=lambda r: r.priority)


def get_admin_page_routes() -> list[RouteInfo]:
    """Get admin page routes from modules."""
    return [r for r in discover_module_routes() if r.route_type == "pages" and r.frontend == "admin"]


def get_admin_api_routes() -> list[RouteInfo]:
    """
    Get admin API routes from modules, sorted by priority.

    Returns routes sorted by priority (lower first, higher last).
    This ensures catch-all routes (priority 100+) are registered after
    specific routes.
    """
    routes = [
        r for r in discover_module_routes()
        if r.route_type == "api" and r.frontend == "admin"
    ]
    return sorted(routes, key=lambda r: r.priority)


def get_store_api_routes() -> list[RouteInfo]:
    """
    Get store API routes from modules, sorted by priority.

    Returns routes sorted by priority (lower first, higher last).
    This ensures catch-all routes (priority 100+) are registered after
    specific routes.
    """
    routes = [
        r for r in discover_module_routes()
        if r.route_type == "api" and r.frontend == "store"
    ]
    return sorted(routes, key=lambda r: r.priority)


def get_storefront_api_routes() -> list[RouteInfo]:
    """
    Get storefront API routes from modules, sorted by priority.

    Returns routes sorted by priority (lower first, higher last).
    This ensures catch-all routes (priority 100+) are registered after
    specific routes.
    """
    routes = [
        r for r in discover_module_routes()
        if r.route_type == "api" and r.frontend == "storefront"
    ]
    return sorted(routes, key=lambda r: r.priority)


def get_platform_api_routes() -> list[RouteInfo]:
    """
    Get platform API routes from modules, sorted by priority.

    Platform routes are unauthenticated endpoints for marketing pages,
    pricing info, and other public-facing features.
    """
    routes = [
        r for r in discover_module_routes()
        if r.route_type == "api" and r.frontend == "platform"
    ]
    return sorted(routes, key=lambda r: r.priority)


def get_webhooks_api_routes() -> list[RouteInfo]:
    """
    Get webhook API routes from modules, sorted by priority.

    Webhook routes handle callbacks from external services
    (Stripe, payment providers, etc.).
    """
    routes = [
        r for r in discover_module_routes()
        if r.route_type == "api" and r.frontend == "webhooks"
    ]
    return sorted(routes, key=lambda r: r.priority)


def get_platform_page_routes() -> list[RouteInfo]:
    """
    Get platform (marketing) page routes from modules, sorted by priority.

    Platform pages are unauthenticated marketing pages like:
    - Homepage (/)
    - Pricing (/pricing)
    - Signup (/signup)
    - Find shop (/find-shop)
    - CMS catch-all (/{slug})

    Note: CMS routes should have priority=100 to be registered last
    since they have catch-all patterns.
    """
    routes = [
        r for r in discover_module_routes()
        if r.route_type == "pages" and r.frontend == "platform"
    ]
    return sorted(routes, key=lambda r: r.priority)


def get_merchant_api_routes() -> list[RouteInfo]:
    """
    Get merchant API routes from modules, sorted by priority.

    Merchant routes are authenticated endpoints for the merchant billing portal,
    where business owners manage subscriptions, view invoices, and see their stores.
    """
    routes = [
        r for r in discover_module_routes()
        if r.route_type == "api" and r.frontend == "merchant"
    ]
    return sorted(routes, key=lambda r: r.priority)


def get_merchant_page_routes() -> list[RouteInfo]:
    """
    Get merchant page routes from modules, sorted by priority.

    Merchant pages include:
    - Dashboard (overview of stores, subscriptions)
    - Subscriptions per platform
    - Billing history / invoices
    - Profile management
    """
    routes = [
        r for r in discover_module_routes()
        if r.route_type == "pages" and r.frontend == "merchant"
    ]
    return sorted(routes, key=lambda r: r.priority)


def get_storefront_page_routes() -> list[RouteInfo]:
    """
    Get storefront (customer shop) page routes from modules, sorted by priority.

    Storefront pages include:
    - Catalog pages (/, /products, /products/{id}, /categories/{slug})
    - Cart and checkout (/cart, /checkout)
    - Account pages (/account/*)
    - CMS content pages (/{slug})

    Note: CMS routes should have priority=100 to be registered last
    since they have catch-all patterns.
    """
    routes = [
        r for r in discover_module_routes()
        if r.route_type == "pages" and r.frontend == "storefront"
    ]
    return sorted(routes, key=lambda r: r.priority)


__all__ = [
    "RouteInfo",
    "discover_module_routes",
    "get_api_routes",
    "get_page_routes",
    "get_store_page_routes",
    "get_admin_page_routes",
    "get_admin_api_routes",
    "get_store_api_routes",
    "get_storefront_api_routes",
    "get_platform_api_routes",
    "get_webhooks_api_routes",
    "get_platform_page_routes",
    "get_storefront_page_routes",
    "get_merchant_api_routes",
    "get_merchant_page_routes",
]
