package com.example.nto.service.impl;

import com.example.nto.mapper.EmployeeDTOMapper;
import com.example.nto.model.EmployeeRoleType;
import com.example.nto.model.dto.EmployeeDTO;
import com.example.nto.model.entity.Employee;
import com.example.nto.model.entity.Entry;
import com.example.nto.repository.CodeRepository;
import com.example.nto.repository.EmployeeRepository;
import com.example.nto.repository.EntryRepository;
import com.example.nto.service.EmployeeService;
import com.example.nto.service.exception.*;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

@Service
@RequiredArgsConstructor
public class EmployeeServiceImpl implements EmployeeService {

    private final EmployeeRepository employeeRepository;

    private final PasswordEncoder passwordEncoder;

    private final CodeRepository codeRepository;

    private final EmployeeDTOMapper employeeDTOMapper;

    private final EntryRepository entryRepository;

    private void employeeExists(final String login) {
        if (!employeeRepository.existsByLogin(login)) {
            throw new EmployeeNotFoundException();
        }
    }

    @Override
    public EmployeeDTO getEmployeeDTO(final String login, final String recipientLogin) {
        employeeExists(login);
        if (!Objects.equals(login, recipientLogin)) {
            var recipient = getEmployee(recipientLogin);
            if (recipient.getRole() != EmployeeRoleType.ADMIN) {
                throw new NotAnAdminException();
            }
        }
        return employeeDTOMapper.map(employeeRepository.findEmployeeByLogin(login));
    }

    private Employee getEmployee(final String login) {
        employeeExists(login);
        return employeeRepository.findEmployeeByLogin(login);
    }

    @Override
    public void updateVisit(Entry entry) {
        employeeExists(entry.getLogin());
        if (!codeRepository.existsByValue(entry.getValue())) {
            throw new CodeNotFoundException();
        }
        final Employee employee = getEmployee(entry.getLogin());
        if (employee.getIsBanned()) {
            throw new EmployeeBannedException();
        }
        employee.setLastVisit(entry.getDateTime());
        employeeRepository.save(employee);
        addEntry(entry);
    }

    @Override
    public void addEmployee(Employee employee) {
        employee.setPassword(passwordEncoder.encode(employee.getPassword()));
        employeeRepository.save(employee);
    }

    @Override
    public void banEmployee(String login) {
        employeeExists(login);
        var e = getEmployee(login);
        if (e.getRole() == EmployeeRoleType.ADMIN) {
            throw new CantBanAnAdminException();
        }
        var employee = getEmployee(login);
        employee.setIsBanned(true);
        employeeRepository.save(employee);
    }

    @Override
    public void unbanEmployee(String login) {
        employeeExists(login);
        var employee = getEmployee(login);
        employee.setIsBanned(false);
        employeeRepository.save(employee);
    }

    @Override
    public void addEntry(Entry entry) {
        entryRepository.save(entry);
    }

    @Override
    public List<Entry> getAllEntriesByLogin(String login, String recipientLogin) {
        employeeExists(login);
        if (!Objects.equals(login, recipientLogin)) {
            var recipient = getEmployee(recipientLogin);
            if (recipient.getRole() != EmployeeRoleType.ADMIN) {
                throw new NotAnAdminException();
            }
        }
        return entryRepository.findAllEntryByLogin(login);
    }
}
