package library.routes;

import static library.routes.Params.pathId;

import java.util.List;

import io.javalin.config.JavalinConfig;
import io.javalin.http.Context;
import library.domain.Book;
import library.dto.NewBook;
import library.service.BookService;

/**
 * HTTP in, HTTP out for /books.
 *
 * Each handler describes the success path: parse the request, call one service
 * method, send the result. Failures are exceptions thrown where they're noticed
 * and turned into responses in one place, ErrorHandler. No SQL here, and no
 * try/catch.
 */
public class BookRoutes {

	private final BookService service;

	public BookRoutes(BookService service) {
		this.service = service;
	}

	// Javalin 7: called from inside Javalin.create(config -> { ... })
	public void register(JavalinConfig config) {
		config.routes.get("/books", ctx -> list(ctx));
		config.routes.get("/books/{id}", ctx -> getOne(ctx));
		config.routes.post("/books", ctx -> create(ctx));
		config.routes.put("/books/{id}", ctx -> update(ctx));
		config.routes.delete("/books/{id}", ctx -> delete(ctx));
	}

	// GET /books and GET /books?author=...
	private void list(Context ctx) {
		String author = ctx.queryParam("author");
		List<Book> books = (author == null) ? service.findAll() : service.findByAuthor(author);
		ctx.json(books);
	}

	// GET /books/{id}
	private void getOne(Context ctx) {
		ctx.json(service.get(pathId(ctx)));
	}

	// POST /books → 201 with Location
	private void create(Context ctx) {
		Book created = service.create(ctx.bodyAsClass(NewBook.class));
		ctx.status(201).header("Location", "/books/" + created.bookId()).json(created);
	}

	// PUT /books/{id} → 200 with the updated book
	private void update(Context ctx) {
		int id = pathId(ctx);
		ctx.json(service.update(id, ctx.bodyAsClass(NewBook.class)));
	}

	// DELETE /books/{id} → 204
	private void delete(Context ctx) {
		service.delete(pathId(ctx));
		ctx.status(204);
	}
}
