package com.mzh.library.controller;

import com.mzh.library.dao.impl.JdbcBookDao;
import com.mzh.library.entity.AuthenticatedUser;
import com.mzh.library.entity.Book;
import com.mzh.library.entity.BookCategory;
import com.mzh.library.entity.BookSearchCriteria;
import com.mzh.library.entity.Permission;
import com.mzh.library.service.BookService;
import com.mzh.library.service.PermissionPolicy;
import com.mzh.library.service.ServiceResult;
import com.mzh.library.service.impl.BookServiceImpl;
import com.mzh.library.util.SessionAttributes;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class BookCatalogServlet extends HttpServlet {
    private static final String CATALOG_JSP = "/WEB-INF/jsp/books/catalog.jsp";

    private BookService bookService;
    private PermissionPolicy permissionPolicy;

    @Override
    public void init() {
        this.bookService = new BookServiceImpl(new JdbcBookDao());
        this.permissionPolicy = new PermissionPolicy();
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        BookSearchCriteria criteria = searchCriteria(request);
        request.setAttribute("criteria", criteria);
        request.setAttribute("canManageBooks", canManageBooks(request));

        ServiceResult<List<BookCategory>> categoryResult = bookService.listCategories();
        request.setAttribute("categories", categoryResult.isSuccessful()
            ? categoryResult.getData()
            : Collections.emptyList());
        if (!categoryResult.isSuccessful()) {
            request.setAttribute("errorMessage", categoryResult.getMessage());
        }

        ServiceResult<List<Book>> searchResult = bookService.searchBooks(criteria);
        request.setAttribute("books", searchResult.isSuccessful()
            ? searchResult.getData()
            : Collections.emptyList());
        if (!searchResult.isSuccessful()) {
            request.setAttribute("errorMessage", searchResult.getMessage());
            request.setAttribute("errors", searchResult.getErrors());
        }

        request.getRequestDispatcher(CATALOG_JSP).forward(request, response);
    }

    private BookSearchCriteria searchCriteria(HttpServletRequest request) {
        return new BookSearchCriteria(
            request.getParameter("identifier"),
            request.getParameter("title"),
            request.getParameter("author"),
            optionalLong(request.getParameter("categoryId"))
        );
    }

    private Long optionalLong(String value) {
        String trimmed = trim(value);
        if (trimmed.isEmpty()) {
            return null;
        }
        try {
            return Long.valueOf(trimmed);
        } catch (NumberFormatException ex) {
            return -1L;
        }
    }

    private boolean canManageBooks(HttpServletRequest request) {
        AuthenticatedUser user = currentUser(request);
        return user != null && permissionPolicy.allows(user.getRole(), Permission.MANAGE_BOOKS);
    }

    private AuthenticatedUser currentUser(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        Object value = session == null ? null : session.getAttribute(SessionAttributes.AUTHENTICATED_USER);
        return value instanceof AuthenticatedUser ? (AuthenticatedUser) value : null;
    }

    private String trim(String value) {
        return value == null ? "" : value.trim();
    }
}
