pub fn gen(pascal: &str, snake: &str, id: Option<&str>, auth: bool, _paginate: bool) -> String {
    let id_param_type = match id {
        Some("snowflake") => "i64",
        Some(_) => "String",
        None => "i64",
    };

    let auth_guard = if auth {
        "    ctx.require_auth()?;\n        "
    } else {
        ""
    };

    format!(
        r#"use axum::{{
    extract::{{Path, State}},
    response::IntoResponse,
    Json,
}};
use rok_auth::axum::{{Ctx, Response}};
use rok_auth_macros::controller;
use crate::app::validators::{{create_{snake}_request::Create{pascal}Request, update_{snake}_request::Update{pascal}Request}};
use crate::state::AppState;

#[controller]
pub struct {pascal}Controller;

impl {pascal}Controller {{
    pub async fn index(ctx: Ctx, State(_state): State<AppState>) -> impl IntoResponse {{
        {auth_guard}Response::json(serde_json::json!({{ "data": [] }}))
    }}

    pub async fn store(
        ctx: Ctx,
        State(_state): State<AppState>,
        Json(_body): Json<Create{pascal}Request>,
    ) -> impl IntoResponse {{
        {auth_guard}Response::json(serde_json::json!({{ "message": "created" }}))
    }}

    pub async fn show(
        ctx: Ctx,
        State(_state): State<AppState>,
        Path(id): Path<{id_param_type}>,
    ) -> impl IntoResponse {{
        {auth_guard}Response::json(serde_json::json!({{ "id": id.to_string() }}))
    }}

    pub async fn update(
        ctx: Ctx,
        State(_state): State<AppState>,
        Path(id): Path<{id_param_type}>,
        Json(_body): Json<Update{pascal}Request>,
    ) -> impl IntoResponse {{
        {auth_guard}Response::json(serde_json::json!({{ "id": id.to_string(), "message": "updated" }}))
    }}

    pub async fn destroy(
        ctx: Ctx,
        State(_state): State<AppState>,
        Path(id): Path<{id_param_type}>,
    ) -> impl IntoResponse {{
        {auth_guard}let _ = id;
        Response::no_content()
    }}
}}
"#
    )
}
