package com.example.backend.books.api;

import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.example.backend.books.model.BookEntity;
import com.example.backend.books.service.BookService;
import com.example.backend.categories.api.CategoryDto;
import com.example.backend.categories.model.CategoryEntity;
import com.example.backend.categories.service.CategoryService;
import com.example.backend.core.api.PageAttributesMapper;
import com.example.backend.core.configuration.Constants;
import com.example.backend.core.session.SessionCart;
import com.example.backend.orders.api.BookCountDto;

@Controller
@RequestMapping(CatalogController.URL)
public class CatalogController {
    public static final String URL = "/catalog";

    private static final String CATALOG_VIEW = "catalog";

    private static final String SORT_ATTRIBUTE = "filter";
    private static final String PAGE_ATTRIBUTE = "page";
    private static final String CART_ATTRIBUTE = "cart";
    private static final String CATEGORIES_ATTRIBUTE = "categories";
    private static final String BOOKID_ATTRIBUTE = "bookId";
    private static final String CATEGORYNAME_ATTRIBUTE = "activeName";
    private static final String CATEGORYID_ATTRIBUTE = "activeId";

    private final BookService bookService;
    private final CategoryService categoryService;
    private final ModelMapper modelMapper;
    private final SessionCart cart;

    public CatalogController(
            BookService bookService,
            CategoryService categoryService,
            ModelMapper modelMapper,
            SessionCart cart) {
        this.bookService = bookService;
        this.categoryService = categoryService;
        this.modelMapper = modelMapper;
        this.cart = cart;
    }

    private BookDto toBookDto(BookEntity entity) {
        return modelMapper.map(entity, BookDto.class);
    }

    private CategoryDto toCategoryDto(CategoryEntity entity) {
        return modelMapper.map(entity, CategoryDto.class);
    }

    @GetMapping
    public String getCatalog(
            @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
            @RequestParam(name = SORT_ATTRIBUTE, defaultValue = "new") String filter,
            Model model) {
        model.addAttribute(PAGE_ATTRIBUTE, page);
        model.addAttribute(SORT_ATTRIBUTE, filter);
        model.addAttribute(CATEGORYNAME_ATTRIBUTE, "Все книги");
        model.addAttribute(CART_ATTRIBUTE, cart);
        model.addAllAttributes(PageAttributesMapper.toAttributes(
                bookService.getAllByFilters(0, page, Constants.DEFAULT_PAGE_SIZE, filter, null),
                this::toBookDto));
        model.addAttribute(
                CATEGORIES_ATTRIBUTE,
                categoryService.getAll().stream()
                        .map(this::toCategoryDto)
                        .toList());
        return CATALOG_VIEW;
    }

    @GetMapping("/{id}")
    public String getCatalog(
            @PathVariable(name = "id") Long id,
            @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
            @RequestParam(name = SORT_ATTRIBUTE, defaultValue = "new") String filter,
            Model model) {
        CategoryEntity category = categoryService.get(id);
        model.addAttribute(PAGE_ATTRIBUTE, page);
        model.addAttribute(SORT_ATTRIBUTE, filter);
        model.addAttribute(CATEGORYNAME_ATTRIBUTE, category.getName());
        model.addAttribute(CATEGORYID_ATTRIBUTE, id);
        model.addAttribute(CART_ATTRIBUTE, cart);
        model.addAllAttributes(PageAttributesMapper.toAttributes(
                bookService.getAllByFilters(id, page, Constants.DEFAULT_PAGE_SIZE, filter, null),
                this::toBookDto));
        model.addAttribute(
                CATEGORIES_ATTRIBUTE,
                categoryService.getAll().stream()
                        .map(this::toCategoryDto)
                        .toList());
        return CATALOG_VIEW;
    }

    @PostMapping
    public String addCartItem(
            @RequestParam(name = BOOKID_ATTRIBUTE) Long bookId,
            @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
            @RequestParam(name = SORT_ATTRIBUTE, defaultValue = "new") String filter,
            Model model,
            RedirectAttributes redirectAttributes) {
        BookEntity book = bookService.get(bookId);
        BookCountDto bookCountDto = new BookCountDto();
        bookCountDto.setBook(toBookDto(book));
        bookCountDto.setCount(1);
        cart.put(bookId, bookCountDto);

        redirectAttributes.addAttribute(CATEGORYNAME_ATTRIBUTE, "Все книги");
        redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page);
        redirectAttributes.addAttribute(SORT_ATTRIBUTE, filter);

        return Constants.REDIRECT_VIEW + URL;
    }

    @PostMapping("/{id}")
    public String addCartItem(
            @PathVariable(name = "id") Long id,
            @RequestParam(name = BOOKID_ATTRIBUTE) Long bookId,
            @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
            @RequestParam(name = SORT_ATTRIBUTE, defaultValue = "new") String filter,
            Model model,
            RedirectAttributes redirectAttributes) {
        BookEntity book = bookService.get(bookId);
        BookCountDto bookCountDto = new BookCountDto();
        bookCountDto.setBook(toBookDto(book));
        bookCountDto.setCount(1);
        cart.put(bookId, bookCountDto);

        CategoryEntity category = categoryService.get(id);

        redirectAttributes.addAttribute(CATEGORYID_ATTRIBUTE, id);
        redirectAttributes.addAttribute(CATEGORYNAME_ATTRIBUTE, category.getName());
        redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page);
        redirectAttributes.addAttribute(SORT_ATTRIBUTE, filter);

        return Constants.REDIRECT_VIEW + URL + "/" + id;
    }
}
