package com.example.backend.users.api;

import org.modelmapper.ModelMapper;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.bind.annotation.RequestMapping;

import com.example.backend.books.api.BookDto;
import com.example.backend.books.model.BookEntity;
import com.example.backend.core.api.PageAttributesMapper;
import com.example.backend.core.configuration.Constants;
import com.example.backend.core.security.UserPrincipal;
import com.example.backend.core.utils.Formatter;
import com.example.backend.orders.api.BookCountDto;
import com.example.backend.orders.api.OrderDto;
import com.example.backend.orders.model.OrderEntity;
import com.example.backend.orders.service.OrderService;
import com.example.backend.users.model.UserEntity;
import com.example.backend.users.service.UserService;

import jakarta.validation.Valid;

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

    private static final String PROFILE_VIEW = "profile";
    private static final String PROFILEEDIT_VIEW = "profile-edit";

    private static final String PAGE_ATTRIBUTE = "page";
    private static final String USER_ATTRIBUTE = "user";

    private final UserService userService;
    private final OrderService orderService;
    private final ModelMapper modelMapper;

    public UserProfileController(
            UserService userService,
            OrderService orderService,
            ModelMapper modelMapper) {
        this.userService = userService;
        this.orderService = orderService;
        this.modelMapper = modelMapper;
    }

    private UserEntity toUserEntity(UserDto dto) {
        return modelMapper.map(dto, UserEntity.class);
    }

    private UserDto toUserDto(UserEntity entity) {
        return modelMapper.map(entity, UserDto.class);
    }

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

    private OrderDto toOrderDto(OrderEntity entity) {
        final OrderDto dto = modelMapper.map(entity, OrderDto.class);
        dto.setDate(Formatter.format(entity.getDate()));
        dto.setSum(orderService.getSum(entity.getUser().getId(), entity.getId()));
        dto.setCount(orderService.getFullCount(entity.getUser().getId(), entity.getId()));
        dto.setBooks(orderService.getOrderBooks(entity.getUser().getId(), entity
                .getId()).stream()
                .map(orderBook -> {
                    BookCountDto bookCountDto = new BookCountDto();
                    bookCountDto.setBook(toBookDto(orderBook.getBook()));
                    bookCountDto.setCount(orderBook.getCount());
                    return bookCountDto;
                })
                .toList());
        return dto;
    }

    @GetMapping
    public String getProfile(@RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, Model model,
            @AuthenticationPrincipal UserPrincipal principal) {
        model.addAttribute(USER_ATTRIBUTE, toUserDto(userService.get(principal.getId())));
        model.addAttribute(PAGE_ATTRIBUTE, page);
        model.addAllAttributes(PageAttributesMapper.toAttributes(
                orderService.getAll(principal.getId(), page, 3),
                this::toOrderDto));
        return PROFILE_VIEW;
    }

    @GetMapping("/edit")
    public String changeUserInfo(@RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, Model model,
            @AuthenticationPrincipal UserPrincipal principal) {
        model.addAttribute(USER_ATTRIBUTE, toUserDto(userService.get(principal.getId())));
        model.addAttribute(PAGE_ATTRIBUTE, page);
        return PROFILEEDIT_VIEW;
    }

    @PostMapping("/edit")
    public String update(
            @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
            @ModelAttribute(name = USER_ATTRIBUTE) @Valid UserDto user,
            BindingResult bindingResult,
            Model model,
            RedirectAttributes redirectAttributes,
            @AuthenticationPrincipal UserPrincipal principal) {
        if (bindingResult.hasErrors()) {
            model.addAttribute(PAGE_ATTRIBUTE, page);
            return PROFILEEDIT_VIEW;
        }
        redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page);
        userService.update(principal.getId(), toUserEntity(user));
        return Constants.REDIRECT_VIEW + URL;
    }
}