# ================================================================
# services/orders/app/api/orders.py
# ================================================================
"""
Orders API endpoints - ATOMIC CRUD operations only
"""

from datetime import date
from typing import List, Optional
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Path, Query, status
from sqlalchemy.ext.asyncio import AsyncSession
import structlog

from shared.auth.decorators import get_current_user_dep
from shared.auth.access_control import require_user_role
from shared.routing import RouteBuilder
from shared.security import create_audit_logger, AuditSeverity, AuditAction
from app.core.database import get_db
from app.services.orders_service import OrdersService
from app.models import AuditLog
from app.schemas.order_schemas import (
    OrderCreate,
    OrderUpdate,
    OrderResponse
)

logger = structlog.get_logger()
audit_logger = create_audit_logger("orders-service", AuditLog)

# Create route builder for consistent URL structure
route_builder = RouteBuilder('orders')

router = APIRouter()


# ===== Dependency Injection =====

async def get_orders_service(db = Depends(get_db)) -> OrdersService:
    """Get orders service with dependencies"""
    from app.repositories.order_repository import (
        OrderRepository,
        CustomerRepository,
        OrderItemRepository,
        OrderStatusHistoryRepository
    )
    from shared.clients import (
        get_inventory_client,
        get_production_client,
        get_sales_client
    )

    return OrdersService(
        order_repo=OrderRepository(),
        customer_repo=CustomerRepository(),
        order_item_repo=OrderItemRepository(),
        status_history_repo=OrderStatusHistoryRepository(),
        inventory_client=get_inventory_client(),
        production_client=get_production_client(),
        sales_client=get_sales_client()
    )


# ===== Order CRUD Endpoints =====

@router.post(
    route_builder.build_base_route("").rstrip("/"),
    response_model=OrderResponse,
    status_code=status.HTTP_201_CREATED
)
@require_user_role(['admin', 'owner', 'member'])
async def create_order(
    order_data: OrderCreate,
    tenant_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Create a new customer order"""
    try:
        # Extract user ID safely
        user_id = current_user.get("user_id")
        if not user_id:
            logger.error("User ID not found in current_user context", current_user_keys=list(current_user.keys()))
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="User authentication error"
            )

        order = await orders_service.create_order(
            db,
            order_data,
            user_id=UUID(user_id)
        )

        # Commit the transaction to persist changes
        await db.commit()

        logger.info("Order created successfully",
                   order_id=str(order.id),
                   order_number=order.order_number)

        return order

    except ValueError as e:
        logger.warning("Invalid order data", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception as e:
        logger.error("Error creating order", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to create order"
        )


@router.get(
    route_builder.build_base_route("").rstrip("/"),
    response_model=List[OrderResponse]
)
async def get_orders(
    tenant_id: UUID = Path(...),
    status_filter: Optional[str] = Query(None, description="Filter by order status"),
    start_date: Optional[date] = Query(None, description="Start date for date range filter"),
    end_date: Optional[date] = Query(None, description="End date for date range filter"),
    skip: int = Query(0, ge=0, description="Number of orders to skip"),
    limit: int = Query(100, ge=1, le=1000, description="Number of orders to return"),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Get orders with filtering and pagination"""
    try:
        # Determine which repository method to use based on filters
        if status_filter:
            orders = await orders_service.order_repo.get_orders_by_status(
                db, tenant_id, status_filter, skip, limit
            )
        elif start_date and end_date:
            orders = await orders_service.order_repo.get_orders_by_date_range(
                db, tenant_id, start_date, end_date, skip, limit
            )
        else:
            orders = await orders_service.order_repo.get_multi(
                db, tenant_id, skip, limit, order_by="order_date", order_desc=True
            )

        return [OrderResponse.from_orm(order) for order in orders]

    except Exception as e:
        logger.error("Error getting orders", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve orders"
        )


@router.get(
    route_builder.build_base_route("{order_id}"),
    response_model=OrderResponse
)
async def get_order(
    tenant_id: UUID = Path(...),
    order_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Get order details with items"""
    try:
        order = await orders_service.get_order_with_items(db, order_id, tenant_id)
        if not order:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Order not found"
            )

        return order

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error getting order",
                    order_id=str(order_id),
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve order"
        )


@router.put(
    route_builder.build_base_route("{order_id}"),
    response_model=OrderResponse
)
@require_user_role(['admin', 'owner', 'member'])
async def update_order(
    order_data: OrderUpdate,
    tenant_id: UUID = Path(...),
    order_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Update order information"""
    try:
        # Get existing order
        order = await orders_service.order_repo.get(db, order_id, tenant_id)
        if not order:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Order not found"
            )

        # Update order
        updated_order = await orders_service.order_repo.update(
            db,
            db_obj=order,
            obj_in=order_data.dict(exclude_unset=True),
            updated_by=UUID(current_user["user_id"])
        )

        # Commit the transaction to persist changes
        await db.commit()

        logger.info("Order updated successfully",
                   order_id=str(order_id))

        return OrderResponse.from_orm(updated_order)

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error updating order",
                    order_id=str(order_id),
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to update order"
        )


@router.delete(
    route_builder.build_base_route("{order_id}"),
    status_code=status.HTTP_204_NO_CONTENT
)
@require_user_role(['admin', 'owner'])
async def delete_order(
    tenant_id: UUID = Path(...),
    order_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Delete an order (Admin+ only, soft delete)"""
    try:
        order = await orders_service.order_repo.get(db, order_id, tenant_id)
        if not order:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Order not found"
            )

        # Capture order data before deletion
        order_data = {
            "order_number": order.order_number,
            "customer_id": str(order.customer_id) if order.customer_id else None,
            "order_status": order.order_status,
            "total_amount": float(order.total_amount) if order.total_amount else 0.0,
            "order_date": order.order_date.isoformat() if order.order_date else None
        }

        await orders_service.order_repo.delete(db, order_id, tenant_id)

        # Commit the transaction to persist deletion
        await db.commit()

        # Log audit event for order deletion
        try:
            await audit_logger.log_deletion(
                db_session=db,
                tenant_id=str(tenant_id),
                user_id=current_user["user_id"],
                resource_type="order",
                resource_id=str(order_id),
                resource_data=order_data,
                description=f"Admin {current_user.get('email', 'unknown')} deleted order {order_data['order_number']}",
                endpoint=f"/orders/{order_id}",
                method="DELETE"
            )
        except Exception as audit_error:
            logger.warning("Failed to log audit event", error=str(audit_error))

        logger.info("Order deleted successfully",
                   order_id=str(order_id),
                   tenant_id=str(tenant_id),
                   user_id=current_user["user_id"])

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error deleting order",
                    order_id=str(order_id),
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to delete order"
        )


# ===== Tenant Data Deletion Endpoint =====

@router.delete(
    route_builder.build_base_route("tenant/{tenant_id}", include_tenant_prefix=False),
    status_code=status.HTTP_200_OK
)
async def delete_tenant_data(
    tenant_id: str = Path(..., description="Tenant ID"),
    current_user: dict = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """
    Delete all order-related data for a tenant
    Only accessible by internal services (called during tenant deletion)
    """

    logger.info("Tenant data deletion request received",
               tenant_id=tenant_id,
               requesting_service=current_user.get("service", "unknown"))

    # Only allow internal service calls
    if current_user.get("type") != "service":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="This endpoint is only accessible to internal services"
        )

    try:
        from app.services.tenant_deletion_service import OrdersTenantDeletionService

        deletion_service = OrdersTenantDeletionService(db)
        result = await deletion_service.safe_delete_tenant_data(tenant_id)

        return {
            "message": "Tenant data deletion completed in orders-service",
            "summary": result.to_dict()
        }

    except Exception as e:
        logger.error("Tenant data deletion failed",
                    tenant_id=tenant_id,
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to delete tenant data: {str(e)}"
        )


@router.get(
    route_builder.build_base_route("tenant/{tenant_id}/deletion-preview", include_tenant_prefix=False),
    status_code=status.HTTP_200_OK
)
async def preview_tenant_data_deletion(
    tenant_id: str = Path(..., description="Tenant ID"),
    current_user: dict = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """
    Preview what data would be deleted for a tenant (dry-run)
    Accessible by internal services and tenant admins
    """

    # Allow internal services and admins
    is_service = current_user.get("type") == "service"
    is_admin = current_user.get("role") in ["owner", "admin"]

    if not (is_service or is_admin):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Insufficient permissions"
        )

    try:
        from app.services.tenant_deletion_service import OrdersTenantDeletionService

        deletion_service = OrdersTenantDeletionService(db)
        preview = await deletion_service.get_tenant_data_preview(tenant_id)

        return {
            "tenant_id": tenant_id,
            "service": "orders-service",
            "data_counts": preview,
            "total_items": sum(preview.values())
        }

    except Exception as e:
        logger.error("Deletion preview failed",
                    tenant_id=tenant_id,
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to get deletion preview: {str(e)}"
        )
