package library;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import io.javalin.Javalin;
import io.javalin.http.staticfiles.Location;
import io.javalin.json.JavalinJackson;
import library.dao.BookDao;
import library.dao.LoanDao;
import library.dao.MemberDao;
import library.dao.SessionDao;
import library.routes.AuthFilter;
import library.routes.AuthRoutes;
import library.routes.BookRoutes;
import library.routes.LoanRoutes;
import library.routes.MemberRoutes;
import library.service.BookService;
import library.service.LoanService;
import library.service.MemberService;
import library.service.SessionService;

/**
 * Starts the library API on port 7000.
 *
 * The only class that knows every layer: it builds them bottom-up and hands
 * each one the layer below.
 */
public class Main {

	public static void main(String[] args) {
		// DAOs
		BookDao bookDao = new BookDao();
		MemberDao memberDao = new MemberDao();
		LoanDao loanDao = new LoanDao();
		SessionDao sessionDao = new SessionDao();

		// Services
		BookService bookService = new BookService(bookDao);
		SessionService sessionService = new SessionService(sessionDao);
		MemberService memberService = new MemberService(memberDao, sessionService);
		LoanService loanService = new LoanService(loanDao, bookDao);

		// Routes
		BookRoutes bookRoutes = new BookRoutes(bookService);
		AuthRoutes authRoutes = new AuthRoutes(memberService, sessionService);
		MemberRoutes memberRoutes = new MemberRoutes(memberService);
		LoanRoutes loanRoutes = new LoanRoutes(loanService);

		// Javalin 7: all configuration and routes go inside the config block
		Javalin.create(config -> {
			config.jetty.port = 7000;

			// JSON: dates as "1979-10-12" rather than [1979,10,12],
			// and ignore JSON fields a DTO doesn't have (e.g. a client-sent "bookId" or
			// "role")
			config.jsonMapper(new JavalinJackson().updateMapper(mapper -> {
				mapper.registerModule(new JavaTimeModule());
				mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
				mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
			}));

			// A small browser front end: src/main/resources/public/index.html,
			// served at http://localhost:7000/
			config.staticFiles.add("/public", Location.CLASSPATH);

			// runs before every request; 401 unless public or a valid token
			config.routes.before(new AuthFilter(sessionService));

			authRoutes.register(config);
			memberRoutes.register(config);
			bookRoutes.register(config);
			loanRoutes.register(config);
		}).start();
	}
}
