package com.example.items.service;

import com.example.items.entity.Document;
import com.example.items.entity.Employee;
import com.example.items.entity.Location;
import com.example.items.entity.Request;
import com.example.items.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.ModelAndView;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;

@Service
public class EmployeeService {

    private final EmployeeRepository employeeRepo;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;
    private final JavaMailSender javaMailSender;
    private final RequestService requestService;
    private final LocationService locationService;
    private final DocService docService;

    @Autowired
    public EmployeeService(EmployeeRepository employeeRepo, LocationService locationService, BCryptPasswordEncoder bCryptPasswordEncoder, JavaMailSender javaMailSender, RequestService requestService, DocService docService) {
        this.employeeRepo = employeeRepo;
        this.locationService = locationService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
        this.javaMailSender = javaMailSender;
        this.requestService = requestService;
        this.docService = docService;
    }

    
    public ModelAndView saveEmployee(@Valid Employee employee, BindingResult bindingResult) throws MessagingException, IOException {
        Employee employeeExists = findByEmail(employee.getEmail());
        System.out.println(employee);
        if (employee.getId() == null) {
            if (employeeExists != null) {
                bindingResult.rejectValue("email", "email",
                        "Email already registered");
            }
            if (!employee.getPasscode().matches("^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{6,100}$") || employee.getPasscode() == null) {
                bindingResult.rejectValue("passcode", "passcode",
                        "Password must be at least 6 characters long and must contain at least one uppercase letter, one lower case letter, and one number.");
            }
            if (!employee.getPasscode().equals(employee.getPasscodeConfirm())) {
                bindingResult.rejectValue("passcode", "passcode",
                        "Passwords do not match");
            }
        }
        if (bindingResult.hasErrors()) {
            ModelAndView mavFail = new ModelAndView("register");
            List<Location> locations = locationService.getAllLocations();
            mavFail.addObject("locations", locations);
            mavFail.addObject("employee", employee);
            mavFail.addObject(bindingResult);
            return mavFail;
        } else {
            sendRegistrationEmail(employee);
            employee.setPasscode(bCryptPasswordEncoder.encode(employee.getPasscode()));
            employeeRepo.save(employee);
            ModelAndView mavSuccess = new ModelAndView("admin-list-employee");
            List<Employee> employeeList = getEmployeeList();
            mavSuccess.addObject("employees", employeeList);
            mavSuccess.addObject("message", "Employee Successfully added");
            return mavSuccess;
        }
    }


    public ModelAndView updateEmployee(@Valid Employee formEmployee, Employee currentEmployeeRecord, BindingResult bindingResult) {
        if(!formEmployee.getFirstName().isEmpty()){
            currentEmployeeRecord.setFirstName(formEmployee.getFirstName());
        }
        if(!formEmployee.getLastName().isEmpty()){
            currentEmployeeRecord.setLastName(formEmployee.getLastName());
        }
        if(!formEmployee.getPasscode().isEmpty()){
            if (!formEmployee.getPasscode().matches("^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{6,100}$") || formEmployee.getPasscode() == null) {
                bindingResult.rejectValue("passcode", "passcode",
                        "Password must be at least 6 characters long and must contain at least one uppercase letter, one lower case letter, and one number.");
            }
            if (!formEmployee.getPasscode().equals(formEmployee.getPasscodeConfirm())) {
                bindingResult.rejectValue("passcode", "passcode",
                        "Passwords do not match");
            }
            currentEmployeeRecord.setPasscode(bCryptPasswordEncoder.encode(formEmployee.getPasscode()));
        }
        if(!formEmployee.getPhone().isEmpty()){
            currentEmployeeRecord.setPhone(formEmployee.getPhone());
        }
        if(!formEmployee.getBirthDate().isEmpty()){
            currentEmployeeRecord.setBirthDate(formEmployee.getBirthDate());
        }
        if(formEmployee.getSalary() != null){
            currentEmployeeRecord.setSalary(formEmployee.getSalary());
        }
        if(!formEmployee.getEmergencyContactPhone().isEmpty()){
            currentEmployeeRecord.setEmergencyContactPhone(formEmployee.getEmergencyContactPhone());
        }
        if(!formEmployee.getEmergencyContactName().isEmpty()){
            currentEmployeeRecord.setEmergencyContactName(formEmployee.getEmergencyContactName());
        }
        currentEmployeeRecord.setRole(formEmployee.getRole());
        currentEmployeeRecord.setPosition(formEmployee.getPosition());
        currentEmployeeRecord.setDepartment(formEmployee.getDepartment());
        currentEmployeeRecord.setLocation(formEmployee.getLocation());


        if (bindingResult.hasErrors()) {
            ModelAndView mavFail = new ModelAndView("update-employee");
            List<Location> locations = locationService.getAllLocations();
            mavFail.addObject("locations", locations);
            mavFail.addObject("employee", formEmployee);
            mavFail.addObject(bindingResult);
            return mavFail;
        } else {
            employeeRepo.save(currentEmployeeRecord);
            if (!formEmployee.getId().equals(getSessionEmployee().getId())) {
                ModelAndView adminUpdateMav = new ModelAndView("admin-list-employee");
                List<Employee> employeeList = getEmployeeList();
                adminUpdateMav.addObject("employees", employeeList);
                adminUpdateMav.addObject("message", "Employee Successfully updated");
                return adminUpdateMav;
            } else {
                ModelAndView sessionUpdateMav = new ModelAndView("index");
                sessionUpdateMav.addObject("message", "Employee Successfully updated");
                return getSessionMav(sessionUpdateMav);
            }
        }
    }

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

    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;
    }

    public Employee findByEmail(String email){
        return employeeRepo.findByEmail(email);
    }

    public Employee findEmployeeById(Long employeeId){
        return employeeRepo.findById(employeeId).get();
    }

    public List<Employee> getEmployeeList(){
        return employeeRepo.findAll();
    }

    public void deleteEmployee(Long employeeId) {
        employeeRepo.deleteById(employeeId);
    }

    void sendRegistrationEmail(Employee employee) throws MessagingException, IOException {
        MimeMessage msg = javaMailSender.createMimeMessage();

        MimeMessageHelper helper = new MimeMessageHelper(msg, true);

        helper.setTo(employee.getEmail());
        helper.setFrom("itemsfsd01@gmail.com","ITems - Employee Management System");
        helper.setSubject("Welcome to our Team!");

        helper.setText("<h1>Welcome to the company</h1><br/>Your login credentials are below:&nbsp;<br/><br/>Username:&nbsp;"+ employee.getEmail() + "<br/>Password:&nbsp;" + employee.getPasscode() + "<br/>Link:&nbsp;" +
                "<a href='https://items-project.herokuapp.com/updateEmployeeForm'>Update Your Information</a><br/><p>Please click the link above to login and fill in your employee profile.</p><br/><p>" +
                "<b>Please save this email for your records<b></p><img src='https://travel.fsd01.ca/images/items.png'>", true);

        javaMailSender.send(msg);

    }
/////////////////////////////////////////////////////////////////////////////////////////////////////////
}