use axum::{debug_handler, routing::delete as axum_delete};
use loco_rs::prelude::*;
use serde::{Deserialize, Serialize};

use crate::models::books::{CreateBookParams, Model as BookModel};

#[derive(Debug, Deserialize, Serialize)]
pub struct Params {
    pub title: String,
    pub author: String,
    pub description: Option<String>,
    pub cover: Option<String>,
    pub content: String,
}

impl From<Params> for CreateBookParams {
    fn from(params: Params) -> Self {
        Self {
            title: params.title,
            author: params.author,
            description: params.description,
            cover: params.cover,
            content: params.content,
        }
    }
}

/// Simple test endpoint
#[debug_handler]
pub async fn test(State(_ctx): State<AppContext>) -> Result<Response> {
    format::json(serde_json::json!({"message": "Books controller is working!"}))
}

/// List all books with pagination
#[debug_handler]
pub async fn list(
    Query(params): Query<PaginationParams>,
    State(ctx): State<AppContext>,
) -> Result<Response> {
    let page = params.page.unwrap_or(1);
    let per_page = params.per_page.unwrap_or(12);
    
    let paginated_books = BookModel::list_paginated(&ctx.db, page, per_page).await?;
    format::json(paginated_books)
}

#[derive(Debug, Deserialize)]
pub struct PaginationParams {
    pub page: Option<i32>,
    pub per_page: Option<i32>,
}

/// Get a single book by ID
#[debug_handler]
pub async fn get_one(Path(id): Path<i32>, State(ctx): State<AppContext>) -> Result<Response> {
    let book = BookModel::find_by_id(&ctx.db, id).await?;
    format::json(book)
}

/// Create a new book (requires authentication)
#[debug_handler]
pub async fn create(
    State(ctx): State<AppContext>,
    auth: auth::JWT,
    Json(params): Json<Params>,
) -> Result<Response> {
    // Only authenticated users can create books
    let _user = crate::models::users::Model::find_by_pid(&ctx.db, &auth.claims.pid.to_string())
        .await?;

    let book_params: CreateBookParams = params.into();
    let book = BookModel::create(&ctx.db, &book_params).await?;
    format::json(book)
}

/// Update a book (requires authentication)
#[debug_handler]
pub async fn update(
    Path(id): Path<i32>,
    State(ctx): State<AppContext>,
    auth: auth::JWT,
    Json(params): Json<Params>,
) -> Result<Response> {
    let _user = crate::models::users::Model::find_by_pid(&ctx.db, &auth.claims.pid.to_string())
        .await?;

    let book = BookModel::find_by_id(&ctx.db, id).await?;
    let book_params: CreateBookParams = params.into();
    let updated_book = book.update(&ctx.db, &book_params).await?;
    format::json(updated_book)
}

/// Delete a book (requires authentication)
#[debug_handler]
pub async fn delete(
    Path(id): Path<i32>,
    State(ctx): State<AppContext>,
    auth: auth::JWT,
) -> Result<Response> {
    let _user = crate::models::users::Model::find_by_pid(&ctx.db, &auth.claims.pid.to_string())
        .await?;

    let book = BookModel::find_by_id(&ctx.db, id).await?;
    book.delete(&ctx.db).await?;
    format::empty()
}

pub fn routes() -> Routes {
    Routes::new()
        .prefix("books")
        .add("/test", get(test))
        .add("/", get(list))
        .add("/", post(create))
        .add("/{id}", get(get_one))
}
