use axum::extract::{Path, Query, State};
use axum::routing::get;
use axum::{Json, Router};
use serde::Deserialize;
use uuid::Uuid;

use crate::api::pagination::PagedResponse;
use crate::app::AppState;
use crate::domain::author::{Author, AuthorWithCount};
use crate::domain::manga::Manga;
use crate::error::AppResult;
use crate::repo;

pub fn routes() -> Router<AppState> {
    Router::new()
        .route("/authors", get(list))
        .route("/authors/:id", get(get_one))
        .route("/authors/:id/mangas", get(list_mangas))
}

#[derive(Debug, Deserialize)]
pub struct ListParams {
    #[serde(default)]
    pub search: Option<String>,
    #[serde(default = "default_limit")]
    pub limit: i64,
    #[serde(default)]
    pub offset: i64,
}

fn default_limit() -> i64 {
    10
}

#[derive(Debug, Deserialize)]
pub struct MangaListParams {
    #[serde(default = "default_manga_limit")]
    pub limit: i64,
    #[serde(default)]
    pub offset: i64,
}

fn default_manga_limit() -> i64 {
    50
}

async fn list(
    State(state): State<AppState>,
    Query(params): Query<ListParams>,
) -> AppResult<Json<Vec<Author>>> {
    let limit = params.limit.clamp(1, 50);
    let offset = params.offset.max(0);
    let search = params.search.as_deref().and_then(|s| {
        let t = s.trim();
        if t.is_empty() { None } else { Some(t) }
    });
    Ok(Json(repo::author::list(&state.db, search, limit, offset).await?))
}

async fn get_one(
    State(state): State<AppState>,
    Path(id): Path<Uuid>,
) -> AppResult<Json<AuthorWithCount>> {
    Ok(Json(repo::author::find_with_count(&state.db, id).await?))
}

async fn list_mangas(
    State(state): State<AppState>,
    Path(id): Path<Uuid>,
    Query(params): Query<MangaListParams>,
) -> AppResult<Json<PagedResponse<Manga>>> {
    let limit = params.limit.clamp(1, 200);
    let offset = params.offset.max(0);
    // Intentionally does NOT 404 on unknown id — the join naturally
    // returns zero rows, and the page envelope already conveys that.
    // Saves a round-trip and matches the shape of GET /mangas.
    let (items, total) =
        repo::author::list_mangas_for_author(&state.db, id, limit, offset).await?;
    Ok(Json(PagedResponse::with_total(items, limit, offset, total)))
}
