# app/modules/orders/routes/api/admin_exceptions.py
"""
Admin API endpoints for order item exception management.

Provides admin-level management of:
- Listing exceptions across all stores
- Resolving exceptions by assigning products
- Bulk resolution by GTIN
- Exception statistics
"""

import logging

from fastapi import APIRouter, Depends, Path, Query
from sqlalchemy.orm import Session

from app.api.deps import get_current_admin_api, require_module_access
from app.core.database import get_db
from app.modules.enums import FrontendType
from app.modules.orders.schemas import (
    BulkResolveRequest,
    BulkResolveResponse,
    IgnoreExceptionRequest,
    OrderItemExceptionListResponse,
    OrderItemExceptionResponse,
    OrderItemExceptionStats,
    ResolveExceptionRequest,
)
from app.modules.orders.services.order_item_exception_service import (
    order_item_exception_service,
)
from app.modules.tenancy.schemas.auth import UserContext

logger = logging.getLogger(__name__)

admin_exceptions_router = APIRouter(
    prefix="/order-exceptions",
    tags=["Order Item Exceptions"],
    dependencies=[Depends(require_module_access("orders", FrontendType.ADMIN))],
)


# ============================================================================
# Exception Listing and Stats
# ============================================================================


@admin_exceptions_router.get("", response_model=OrderItemExceptionListResponse)
def list_exceptions(
    store_id: int | None = Query(None, description="Filter by store"),
    status: str | None = Query(
        None,
        pattern="^(pending|resolved|ignored)$",
        description="Filter by status"
    ),
    search: str | None = Query(
        None,
        description="Search in GTIN, product name, SKU, or order number"
    ),
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    db: Session = Depends(get_db),
    current_admin: UserContext = Depends(get_current_admin_api),
):
    """
    List order item exceptions with filtering and pagination.

    Returns exceptions for unmatched products during marketplace order imports.
    """
    exceptions, total = order_item_exception_service.get_pending_exceptions(
        db=db,
        store_id=store_id,
        status=status,
        search=search,
        skip=skip,
        limit=limit,
    )

    # Enrich with order and store info
    response_items = []
    for exc in exceptions:
        item = OrderItemExceptionResponse.model_validate(exc)
        if exc.order_item and exc.order_item.order:
            order = exc.order_item.order
            item.order_number = order.order_number
            item.order_id = order.id
            item.order_date = order.order_date
            item.order_status = order.status
            # Add store name for cross-store view
            if order.store:
                item.store_name = order.store.name
        response_items.append(item)

    return OrderItemExceptionListResponse(
        exceptions=response_items,
        total=total,
        skip=skip,
        limit=limit,
    )


@admin_exceptions_router.get("/stats", response_model=OrderItemExceptionStats)
def get_exception_stats(
    store_id: int | None = Query(None, description="Filter by store"),
    db: Session = Depends(get_db),
    current_admin: UserContext = Depends(get_current_admin_api),
):
    """
    Get exception statistics.

    Returns counts of pending, resolved, and ignored exceptions.
    """
    stats = order_item_exception_service.get_exception_stats(db, store_id)
    return OrderItemExceptionStats(**stats)


# ============================================================================
# Exception Details
# ============================================================================


@admin_exceptions_router.get("/{exception_id}", response_model=OrderItemExceptionResponse)
def get_exception(
    exception_id: int = Path(..., description="Exception ID"),
    db: Session = Depends(get_db),
    current_admin: UserContext = Depends(get_current_admin_api),
):
    """
    Get details of a single exception.
    """
    exception = order_item_exception_service.get_exception_by_id(db, exception_id)

    response = OrderItemExceptionResponse.model_validate(exception)
    if exception.order_item and exception.order_item.order:
        order = exception.order_item.order
        response.order_number = order.order_number
        response.order_id = order.id
        response.order_date = order.order_date
        response.order_status = order.status

    return response


# ============================================================================
# Exception Resolution
# ============================================================================


@admin_exceptions_router.post("/{exception_id}/resolve", response_model=OrderItemExceptionResponse)
def resolve_exception(
    exception_id: int = Path(..., description="Exception ID"),
    request: ResolveExceptionRequest = ...,
    db: Session = Depends(get_db),
    current_admin: UserContext = Depends(get_current_admin_api),
):
    """
    Resolve an exception by assigning a product.

    This updates the order item's product_id and marks the exception as resolved.
    """
    exception = order_item_exception_service.resolve_exception(
        db=db,
        exception_id=exception_id,
        product_id=request.product_id,
        resolved_by=current_admin.id,
        notes=request.notes,
    )
    db.commit()

    response = OrderItemExceptionResponse.model_validate(exception)
    if exception.order_item and exception.order_item.order:
        order = exception.order_item.order
        response.order_number = order.order_number
        response.order_id = order.id
        response.order_date = order.order_date
        response.order_status = order.status

    logger.info(
        f"Admin {current_admin.id} resolved exception {exception_id} "
        f"with product {request.product_id}"
    )

    return response


@admin_exceptions_router.post("/{exception_id}/ignore", response_model=OrderItemExceptionResponse)
def ignore_exception(
    exception_id: int = Path(..., description="Exception ID"),
    request: IgnoreExceptionRequest = ...,
    db: Session = Depends(get_db),
    current_admin: UserContext = Depends(get_current_admin_api),
):
    """
    Mark an exception as ignored.

    Note: Ignored exceptions still block order confirmation.
    Use this when a product will never be matched (e.g., discontinued).
    """
    exception = order_item_exception_service.ignore_exception(
        db=db,
        exception_id=exception_id,
        resolved_by=current_admin.id,
        notes=request.notes,
    )
    db.commit()

    response = OrderItemExceptionResponse.model_validate(exception)
    if exception.order_item and exception.order_item.order:
        order = exception.order_item.order
        response.order_number = order.order_number
        response.order_id = order.id
        response.order_date = order.order_date
        response.order_status = order.status

    logger.info(
        f"Admin {current_admin.id} ignored exception {exception_id}: {request.notes}"
    )

    return response


# ============================================================================
# Bulk Operations
# ============================================================================


@admin_exceptions_router.post("/bulk-resolve", response_model=BulkResolveResponse)
def bulk_resolve_by_gtin(
    request: BulkResolveRequest,
    store_id: int = Query(..., description="Store ID"),
    db: Session = Depends(get_db),
    current_admin: UserContext = Depends(get_current_admin_api),
):
    """
    Bulk resolve all pending exceptions for a GTIN.

    Useful when a new product is imported and multiple orders have
    items with the same unmatched GTIN.
    """
    resolved_count = order_item_exception_service.bulk_resolve_by_gtin(
        db=db,
        store_id=store_id,
        gtin=request.gtin,
        product_id=request.product_id,
        resolved_by=current_admin.id,
        notes=request.notes,
    )
    db.commit()

    logger.info(
        f"Admin {current_admin.id} bulk resolved {resolved_count} exceptions "
        f"for GTIN {request.gtin} with product {request.product_id}"
    )

    return BulkResolveResponse(
        resolved_count=resolved_count,
        gtin=request.gtin,
        product_id=request.product_id,
    )
