from typing import Optional, List, Dict, Any, Union
from uuid import UUID

from fastapi import FastAPI, Query, Path, Body, Header, Cookie
import pytest

from .types import (
    Product,
    Customer,
    OrderResponse,
    PaginatedResponse,
    ProductCategory,
    OrderRequest,
    ErrorResponse,
)


def make_complex_fastapi_app(
    example_product: Product,
    example_customer: Customer,
    example_order_response: OrderResponse,
) -> FastAPI:
    app = FastAPI(
        title="Complex E-Commerce API",
        description="A more complex API with nested models and various schemas",
        version="1.0.0",
    )

    @app.get(
        "/products",
        response_model=PaginatedResponse,
        tags=["products"],
        operation_id="list_products",
        response_model_exclude_none=True,
    )
    async def list_products(
        category: Optional[ProductCategory] = Query(None, description="Filter by product category"),
        min_price: Optional[float] = Query(None, description="Minimum price filter", gt=0),
        max_price: Optional[float] = Query(None, description="Maximum price filter", gt=0),
        tag: Optional[List[str]] = Query(None, description="Filter by tags"),
        sort_by: str = Query("created_at", description="Field to sort by"),
        sort_direction: str = Query("desc", description="Sort direction (asc or desc)"),
        in_stock_only: bool = Query(False, description="Show only in-stock products"),
        page: int = Query(1, description="Page number", ge=1),
        size: int = Query(20, description="Page size", ge=1, le=100),
        user_agent: Optional[str] = Header(None, description="User agent header"),
    ):
        """
        List products with various filtering, sorting and pagination options.
        Returns a paginated response of products.
        """
        return PaginatedResponse(items=[example_product], total=1, page=page, size=size, pages=1)

    @app.get(
        "/products/{product_id}",
        response_model=Product,
        tags=["products"],
        operation_id="get_product",
        responses={
            404: {"model": ErrorResponse, "description": "Product not found"},
        },
    )
    async def get_product(
        product_id: UUID = Path(..., description="The ID of the product to retrieve"),
        include_unavailable: bool = Query(False, description="Include product even if not available"),
    ):
        """
        Get detailed information about a specific product by its ID.
        Includes all variants, images, and metadata.
        """
        # Just returning the example product with the requested ID
        product_copy = example_product.model_copy()
        product_copy.id = product_id
        return product_copy

    @app.post(
        "/orders",
        response_model=OrderResponse,
        tags=["orders"],
        operation_id="create_order",
        status_code=201,
        responses={
            400: {"model": ErrorResponse, "description": "Invalid order data"},
            404: {"model": ErrorResponse, "description": "Customer or product not found"},
            422: {"model": ErrorResponse, "description": "Validation error"},
        },
    )
    async def create_order(
        order: OrderRequest = Body(..., description="Order details"),
        user_id: Optional[UUID] = Cookie(None, description="User ID from cookie"),
        authorization: Optional[str] = Header(None, description="Authorization header"),
    ):
        """
        Create a new order with multiple items, shipping details, and payment information.
        Returns the created order with full details including status and tracking information.
        """
        # Return a copy of the example order response with the customer ID from the request
        order_copy = example_order_response.model_copy()
        order_copy.customer_id = order.customer_id
        order_copy.items = order.items
        return order_copy

    @app.get(
        "/customers/{customer_id}",
        response_model=Union[Customer, Dict[str, Any]],
        tags=["customers"],
        operation_id="get_customer",
        responses={
            404: {"model": ErrorResponse, "description": "Customer not found"},
            403: {"model": ErrorResponse, "description": "Forbidden access"},
        },
    )
    async def get_customer(
        customer_id: UUID = Path(..., description="The ID of the customer to retrieve"),
        include_orders: bool = Query(False, description="Include customer's order history"),
        include_payment_methods: bool = Query(False, description="Include customer's saved payment methods"),
        fields: List[str] = Query(None, description="Specific fields to include in response"),
    ):
        """
        Get detailed information about a specific customer by ID.
        Can include additional related information like order history.
        """
        # Return a copy of the example customer with the requested ID
        customer_copy = example_customer.model_copy()
        customer_copy.id = customer_id
        return customer_copy

    return app


@pytest.fixture
def complex_fastapi_app(
    example_product: Product,
    example_customer: Customer,
    example_order_response: OrderResponse,
) -> FastAPI:
    return make_complex_fastapi_app(
        example_product=example_product,
        example_customer=example_customer,
        example_order_response=example_order_response,
    )
