from fastapi import FastAPI, HTTPException, Path, Query, status
from pydantic import BaseModel, Field
from typing import List, Optional

app = FastAPI(
    title="User Service API",
    description="Simple CRUD API to demonstrate Code First OpenAPI generation with FastAPI",
    version="1.0.0"
)

# --------------------
# Models
# --------------------

class UserBase(BaseModel):
    name: str = Field(..., example="Alice")
    age: int = Field(..., example="22")
    email: str = Field(..., example="alice@example.com")

class UserCreate(UserBase):
    pass

class User(UserBase):
    id: int = Field(..., example=1)

# --------------------
# Fake database
# --------------------

users_db: dict[int, User] = {}

# --------------------
# CRUD Endpoints
# --------------------

@app.post(
    "/users",
    response_model=User,
    status_code=status.HTTP_201_CREATED,
    summary="Create a new user",
    description="Creates a new user and returns the created resource",
    tags=["Users"]
)
def create_user(user: UserCreate):
    user_id = len(users_db) + 1
    new_user = User(id=user_id, **user.dict())
    users_db[user_id] = new_user
    return new_user


@app.get(
    "/users",
    response_model=List[User],
    summary="List all users",
    description="Returns a list of all users",
    tags=["Users"]
)
def list_users(
    limit: int = Query(10, ge=1, le=100, description="Maximum number of users to return")
):
    return list(users_db.values())[:limit]


@app.get(
    "/users/{user_id}",
    response_model=User,
    summary="Get user by ID",
    description="Returns a single user by its ID",
    tags=["Users"]
)
def get_user(
    user_id: int = Path(..., ge=1, description="The ID of the user")
):
    user = users_db.get(user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user


@app.put(
    "/users/{user_id}",
    response_model=User,
    summary="Update a user",
    description="Updates an existing user",
    tags=["Users"]
)
def update_user(
    user_id: int = Path(..., ge=1, description="The ID of the user"),
    user: UserCreate = ...
):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="User not found")
    updated_user = User(id=user_id, **user.dict())
    users_db[user_id] = updated_user
    return updated_user


@app.delete(
    "/users/{user_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Delete a user",
    description="Deletes a user by its ID",
    tags=["Users"]
)
def delete_user(
    user_id: int = Path(..., ge=1, description="The ID of the user")
):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="User not found")
    del users_db[user_id]