package com.example.items.controller;

import com.example.items.config.MvcConfig;
import com.example.items.entity.*;
import com.example.items.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.mail.MessagingException;
import javax.validation.Valid;
import java.io.IOException;
import java.security.Principal;
import java.util.List;

@Controller
public class MainController implements WebMvcConfigurer {

    private final MvcConfig mvcConfig;
    private final EmployeeService employeeService;
    private final RequestService requestService;
    private final LocationService locationService;
    private final DocService docService;
    private final JobService jobService;

    @Autowired
    public MainController(MvcConfig mvcConfig, EmployeeService employeeService, RequestService requestService, LocationService locationService, DocService docService, JobService jobService) {
        this.mvcConfig = mvcConfig;
        this.employeeService = employeeService;
        this.requestService = requestService;
        this.locationService = locationService;
        this.docService = docService;
        this.jobService = jobService;
    }

    //Register Form
    @GetMapping("/admin/register")
    public ModelAndView addEmployeeForm() {
        ModelAndView mav = new ModelAndView("register");
        Employee employee = new Employee();
        List<Location> locations = locationService.getAllLocations();
        mav.addObject("locations", locations);
        mav.addObject("employee", employee);
        return mav;
    }

    //Added Request Param to grab file -- Added throws Message exception since this will send out an email
    @PostMapping("/admin/saveEmployee")
    public ModelAndView saveEmployee(@Valid Employee employee, BindingResult bindingResult) throws MessagingException, IOException {
        return employeeService.saveEmployee(employee, bindingResult);
    }

    //ADMIN HANDLERS
    @GetMapping({ "/admin/list/requests"})
    public ModelAndView showRequests() {
        ModelAndView mav = new ModelAndView("admin-list-requests");
        List<Request> requests = requestService.getAllRequests();
        mav.addObject("requests", requests);
        return mav;
    }

    @GetMapping("/admin/list/requests/deny")
    public String denyRequest(@RequestParam Long requestId) {
        Request denyRequest = requestService.findById(requestId);
        denyRequest.setStatus(Request.RequestStatus.DENIED);
        requestService.saveRequest(denyRequest);
        return "redirect:/admin/list/requests";
    }

    @GetMapping("/admin/list/requests/approve")
    public String approveRequest(@RequestParam Long requestId) {
        Request approveRequest = requestService.findById(requestId);
        approveRequest.setStatus(Request.RequestStatus.APPROVED);
        requestService.saveRequest(approveRequest);
        return "redirect:/admin/list/requests";
    }


    @GetMapping({"/admin/list/employees"})
    public ModelAndView showUsers(@RequestParam(value = "message", required = false) String message) {
        ModelAndView mav = new ModelAndView("admin-list-employee");
        List<Employee> employeeList = employeeService.getEmployeeList();
        mav.addObject("employees", employeeList);
        return mav;
    }

    @GetMapping("/admin/updateEmployee")
    public ModelAndView updateEmployee(@RequestParam Long employeeId){
        ModelAndView mav = new ModelAndView("update-employee");
        Employee employee = employeeService.findEmployeeById(employeeId);
        List<Location> locations = locationService.getAllLocations();
        mav.addObject("locations", locations);
        mav.addObject("employee",employee);
        return mav;
    }

    //Document
    @GetMapping({"/admin/list/documents"})
    public ModelAndView showDocuments(@RequestParam(value = "message", required = false) String message) {
        ModelAndView mav = new ModelAndView("admin-list-documents");
        List<Document> documentList = docService.getFiles();
        mav.addObject("documents", documentList);
        return mav;
    }

    //Location

    @GetMapping({"/admin/list/locations"})
    public ModelAndView showLocations(){
        ModelAndView mav = new ModelAndView("admin-list-locations");
        List<Location> list = locationService.getAllLocations();
        mav.addObject("locations",list);
        return mav;
    }

    @GetMapping("/admin/addLocation")
    public ModelAndView addLocation(@RequestParam(value = "message", required = false) String message){
        ModelAndView mav = new ModelAndView("add-location");
        Location newLocation = new Location();
        mav.addObject("location",newLocation);
        return mav;
    }

    @GetMapping("/admin/updateLocation")
    public ModelAndView updateLocation(@RequestParam Long locationId){
        ModelAndView mav = new ModelAndView("add-location");
        Location location = locationService.getLocationById(locationId);
        mav.addObject("location",location);
        return mav;
    }

    @PostMapping("/admin/saveLocation")
    public String saveLocation(@Valid Location location, BindingResult bindingResult, RedirectAttributes redirectAttributes){
        if(bindingResult.hasErrors()){
            return "add-location";
        }
        redirectAttributes.addFlashAttribute("message", "Location successfully added!");
        locationService.saveLocation(location);
        return "redirect:/admin/list/locations";
    }

    @GetMapping("/admin/deleteLocation")
    public String deleteLocation(@RequestParam Long locationId){
        locationService.deleteLocation(locationId);
        return "redirect:/admin/list/locations";
    }

    @GetMapping("/admin/showUpdateForm")
    public ModelAndView showUpdateForm(@RequestParam Long requestId) {
        ModelAndView mav = new ModelAndView("add-request-form");
        Request request = requestService.findById(requestId);
        mav.addObject("request", request);
        return mav;
    }

    @GetMapping("/admin/deleteEmployee")
    public String deleteUser(@RequestParam Long employeeId) {
        employeeService.deleteEmployee(employeeId);
        return "redirect:/admin/list/employees";
    }

    //Job

    @GetMapping({"/admin/list/jobs"})
    public ModelAndView showJobs(){
        ModelAndView mav = new ModelAndView("list-jobs");
        List<Job> list = jobService.getAllJobs();
        mav.addObject("jobs",list);
        return mav;
    }

    @GetMapping("/admin/addJob")
    public ModelAndView addJob(@RequestParam(value = "message", required = false) String message){
        ModelAndView mav = new ModelAndView("add-job");
        Job newJob = new Job();
        mav.addObject("job",newJob);
        return mav;
    }

    @GetMapping("/admin/updateJob")
    public ModelAndView updateJob(@RequestParam Long jobId){
        ModelAndView mav = new ModelAndView("add-job");
        Job job = jobService.getJobById(jobId);
        mav.addObject("job",job);
        return mav;
    }

    @PostMapping("/admin/saveJob")
    public String saveJob(@Valid Job job, BindingResult bindingResult, RedirectAttributes redirectAttributes){
        if(bindingResult.hasErrors()){
            return "add-job";
        }

        redirectAttributes.addFlashAttribute("message", "Job successfully added/updated!");
        jobService.saveJob(job);
        return "redirect:/admin/list/jobs";
    }

    @GetMapping("/admin/deleteJob")
    public String deleteJob(@RequestParam Long jobId){
        jobService.deleteJob(jobId);
        return "redirect:/admin/list/jobs";
    }
    ////////////////////////////////////////////////////////

    // Login form
    @GetMapping(value={"/login"})
    public String login(Model model){
        return "login";
    }

    @GetMapping(value={"/login-error"})
    public String loginError(Model model) {
        model.addAttribute("loginError", true);
        return "login";
    }

    @GetMapping(value={"/"})
    public ModelAndView home(@RequestParam(value = "message", required = false) String message){
        ModelAndView mav = new ModelAndView("index");
        return getSessionMav(mav);
    }

    //Request

    @GetMapping("/request")
    public ModelAndView showRequest(@RequestParam Long requestId) {
        ModelAndView mav = new ModelAndView("request");
        Request request = requestService.findById(requestId);
        mav.addObject("request", request);
        return mav;
    }

    @GetMapping("/addRequestForm")
    public ModelAndView addRequestForm(@RequestParam(value = "message", required = false) String message) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        Employee sessionEmployee = employeeService.findByEmail(auth.getName());
        ModelAndView mav = new ModelAndView("add-request-form");
        Request request = new Request();
        mav.addObject("sessionEmployee", sessionEmployee);
        mav.addObject("request", request);
        return mav;
    }

    @PostMapping("/saveRequest")
    public String saveRequest(@Valid Request request, BindingResult bindingResult, Principal employee, RedirectAttributes redirectAttributes) {
        request.setEmployee(employeeService.findByEmail(employee.getName()));
        if (bindingResult.hasErrors()) {
            return "add-request-form";
        }
        redirectAttributes.addFlashAttribute("message", "Request successfully submitted!");
        requestService.saveRequest(request);
        return "redirect:/";
    }

    /*
    @GetMapping("/updateEmployee")
    public ModelAndView updateEmployee(){
        ModelAndView mav = new ModelAndView("register");
        return getSessionMav(mav);
    }
    */

    //Update Form
    @GetMapping("/updateEmployeeForm")
    public ModelAndView updateEmployeeForm(@RequestParam(value = "message", required = false) String message) {
        ModelAndView mav = new ModelAndView("update-employee");
        Employee sessionEmployee = getSessionEmployee();
        List<Location> locations = locationService.getAllLocations();
        mav.addObject("locations", locations);
        mav.addObject("employee", sessionEmployee);
        return mav;
    }


    @PostMapping("/updateEmployee")
    public ModelAndView updateEmployee(@Valid Employee formEmployee, BindingResult bindingResult) {
        Employee currentEmployeeRecord = employeeService.findEmployeeById(formEmployee.getId());
        return employeeService.updateEmployee(formEmployee, currentEmployeeRecord , bindingResult);
    }

    @GetMapping("/deleteRequest")
    public String deleteRequest(@RequestParam Long requestId) {
        requestService.deleteRequest(requestId);
        return "redirect:/";
    }


    //Document

    @GetMapping("/document")
    public ModelAndView showDocument(@RequestParam Long documentId) {
        ModelAndView mav = new ModelAndView("document");
        Document document = docService.findById(documentId);
        mav.addObject("document", document);
        return mav;
    }


    @GetMapping("/submitDocument")
    public ModelAndView submitDocument(@RequestParam(value = "errorMessage", required = false) String message) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        Employee sessionEmployee = employeeService.findByEmail(auth.getName());
        ModelAndView mav = new ModelAndView("add-document-form");
        Document document = new Document();
        mav.addObject("sessionEmployee", sessionEmployee);
        mav.addObject("document", document);
        return mav;
    }

    @GetMapping("/showDocumentForm")
    public ModelAndView showDocumentForm(@RequestParam Long documentId) {
        ModelAndView mav = new ModelAndView("add-document-form");
        Document document = docService.findById(documentId);
        mav.addObject("document", document);
        return mav;
    }

    @PostMapping("/saveDocument")
    public String saveDocument(@RequestParam("documents") MultipartFile[] documents, RedirectAttributes redirectAttributes) {
        Employee sessionEmployee = getSessionEmployee();
        for(MultipartFile doc: documents){
            docService.saveFile(doc, sessionEmployee);
        }
        redirectAttributes.addFlashAttribute("message", "Document successfully added!");
        return "redirect:/";
    }

    @GetMapping("/download-file")
    public ResponseEntity<ByteArrayResource> downloadFile(@RequestParam Long fileid) {
        Document document = docService.getFile(fileid);
        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType(document.getDocType()))
                .contentLength(document.getData().length)
                .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=" + document.getDocName())
                .body(new ByteArrayResource(document.getData()));
    }

    private ModelAndView getSessionMav(ModelAndView mav) {
        Employee sessionEmployee = getSessionEmployee();
        List<Location> locations = locationService.getAllLocations();
        List<Request> requests = requestService.getAllRequestsById(sessionEmployee.getId());
        List<Document> documents = docService.getAllDocumentsById(sessionEmployee.getId());
        mav.addObject("locations", locations);
        mav.addObject("employee",sessionEmployee);
        mav.addObject("requests",requests);
        mav.addObject("documents",documents);
        return mav;
    }

    private Employee getSessionEmployee() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return employeeService.findByEmail(auth.getName());
    }

}