//! Manga reactions (like/dislike) — a private, per-user taste signal.
//! Writes require auth; the read is scoped under `/me/` so the URL can't be
//! used to peek at another user's reactions.

use axum::extract::{Path, State};
use axum::http::StatusCode;
use axum::routing::{get, put};
use axum::{Json, Router};
use serde::Deserialize;
use serde_json::json;
use uuid::Uuid;

use crate::app::AppState;
use crate::auth::extractor::CurrentUser;
use crate::domain::reaction::{MangaReaction, Reaction};
use crate::error::{AppError, AppResult};
use crate::repo;

pub fn routes() -> Router<AppState> {
    Router::new()
        .route(
            "/mangas/:id/reaction",
            put(set_reaction).delete(clear_reaction),
        )
        .route("/me/reactions/:manga_id", get(get_reaction))
}

#[derive(Debug, Deserialize)]
pub struct SetReactionBody {
    pub reaction: String,
}

async fn set_reaction(
    State(state): State<AppState>,
    CurrentUser(user): CurrentUser,
    Path(manga_id): Path<Uuid>,
    Json(body): Json<SetReactionBody>,
) -> AppResult<Json<MangaReaction>> {
    // Validate against the closed vocabulary here so a bad value is a clean
    // 422 rather than relying on the DB CHECK to surface as a 500.
    let reaction = Reaction::parse(&body.reaction).ok_or_else(|| AppError::ValidationFailed {
        message: "reaction must be 'like' or 'dislike'".into(),
        details: json!({ "reaction": "must be 'like' or 'dislike'" }),
    })?;
    // Unknown manga → 404 via the FK-violation mapping in repo::reaction.
    repo::reaction::upsert(&state.db, user.id, manga_id, reaction).await?;
    Ok(Json(MangaReaction {
        manga_id,
        reaction: Some(reaction),
    }))
}

async fn clear_reaction(
    State(state): State<AppState>,
    CurrentUser(user): CurrentUser,
    Path(manga_id): Path<Uuid>,
) -> AppResult<StatusCode> {
    repo::reaction::clear(&state.db, user.id, manga_id).await?;
    Ok(StatusCode::NO_CONTENT)
}

async fn get_reaction(
    State(state): State<AppState>,
    CurrentUser(user): CurrentUser,
    Path(manga_id): Path<Uuid>,
) -> AppResult<Json<MangaReaction>> {
    let reaction = repo::reaction::get(&state.db, user.id, manga_id).await?;
    Ok(Json(MangaReaction { manga_id, reaction }))
}
