package com.example.demo.entrysData.api;

import java.util.List;
import java.util.Map;

import org.modelmapper.ModelMapper;
import org.modelmapper.TypeToken;
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.example.demo.core.api.PageAttributesMapper;
import com.example.demo.core.configuration.Constants;
import com.example.demo.department.api.DepartmentDto;
import com.example.demo.department.service.DepartmentService;
import com.example.demo.entrysData.model.EntrysDataEntity;
import com.example.demo.entrysData.model.EntrysDataGroupedDepartment;
import com.example.demo.entrysData.service.EntrysDataService;

import jakarta.validation.Valid;

@Controller
@RequestMapping(EntrysDataController.URL)
public class EntrysDataController {
    public static final String URL = "/users";
    private static final String USERS_VIEW = "users";
    private static final String USERS_EDIT_VIEW = "user-edit";
    private static final String DEPARTMENTS_ATTRIBUTE = "departments";
    private static final String DEPARTMENT_ITEM_ATTRIBUTE = "departmentItem";
    private static final String USERS_ATTRIBUTE = "users";
    private static final String PAGE_ATTRIBUTE = "page";
    private final EntrysDataService entrysDataService;
    private final ModelMapper modelMapper;
    private final DepartmentService departmentService;

    public EntrysDataController(EntrysDataService entrysDataService, ModelMapper modelMapper,
            DepartmentService departmentService) {
        this.entrysDataService = entrysDataService;
        this.modelMapper = modelMapper;
        this.departmentService = departmentService;
    }

    private EntrysDataDto toDto(EntrysDataEntity entity){
        return modelMapper.map(entity, EntrysDataDto.class);
    }

    private EntrysDataGroupedDepartmentDto toDto(EntrysDataGroupedDepartment entity){
        return modelMapper.map(entity, EntrysDataGroupedDepartmentDto.class);
    }

    private EntrysDataEntity toEntity(EntrysDataDto dto) {
        final EntrysDataEntity entity = modelMapper.map(dto, EntrysDataEntity.class);
        entity.setDepartment(departmentService.get(dto.getDepartmentId()));
        return entity;
    }

    private List<DepartmentDto> getDepartments(){
       return modelMapper.map(departmentService.getAll(), new TypeToken<List<DepartmentDto>>(){}.getType());
    }

    private DepartmentDto getDepartment(Long id){
        return modelMapper.map(departmentService.get(id), new TypeToken<DepartmentDto>(){}.getType());
    }

    @GetMapping
    public String getAll(
        @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
        Model model){
        final Map<String, Object> attributes = PageAttributesMapper.
            toAttributes(entrysDataService.getAllWithDepartment(page, Constants.DEFAULT_PAGE_SIZE),
             this::toDto);
        model.addAllAttributes(attributes);
        model.addAttribute(PAGE_ATTRIBUTE, page);
        return USERS_VIEW;
    }

    @GetMapping("/edit/")
    public String create(Model model,
    @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page) {
        model.addAttribute(USERS_ATTRIBUTE, new EntrysDataDto());
        model.addAttribute(DEPARTMENTS_ATTRIBUTE, getDepartments());
        model.addAttribute(PAGE_ATTRIBUTE, page);
        return USERS_EDIT_VIEW;
    }

    @PostMapping("/edit/")
    public String create(
        @ModelAttribute(name = USERS_ATTRIBUTE) @Valid EntrysDataDto dto,
        @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
        BindingResult bindingResult,
        Model model,
        RedirectAttributes redirectAttributes){
            if (bindingResult.hasErrors()) {
                model.addAttribute(PAGE_ATTRIBUTE, page);
                return USERS_EDIT_VIEW;
            }
            redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page);
            entrysDataService.create(toEntity(dto));
            return Constants.REDIRECT_VIEW + URL;
        }
    
    @GetMapping("/edit/{id}")
    public String update(
            @PathVariable(name = "id") Long id,
            @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
            Model model) {
        if (id <= 0) {
            throw new IllegalArgumentException();
        }
        EntrysDataEntity entity = entrysDataService.get(id);
        model.addAttribute(USERS_ATTRIBUTE, toDto(entity));
        model.addAttribute(DEPARTMENTS_ATTRIBUTE, getDepartments());
        model.addAttribute(PAGE_ATTRIBUTE, page);
        return USERS_EDIT_VIEW;
    }
    
    @PostMapping("/edit/{id}")
    public String update(
            @PathVariable(name = "id") Long id,
            @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
            @ModelAttribute(name = USERS_ATTRIBUTE) @Valid EntrysDataDto dto,
            BindingResult bindingResult,
            Model model,
            RedirectAttributes redirectAttributes) {
        if (bindingResult.hasErrors()) {
            return USERS_EDIT_VIEW;
        }
        if (id <= 0) {
            throw new IllegalArgumentException();
        }
        redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page);
        entrysDataService.update(id, toEntity(dto));
        return Constants.REDIRECT_VIEW + URL;
    }

    @PostMapping("/delete/{id}")
    public String delete(
        @PathVariable(name = "id") Long id,
        @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
        RedirectAttributes redirectAttributes) {
    redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page);
    entrysDataService.delete(id);
    return Constants.REDIRECT_VIEW + URL;
}
}
