package de.votian.services.security;

import de.votian.services.config.ParameterKeys;
import de.votian.services.dto.EmployeeDetailDto;
import de.votian.services.dto.UserSessionDto;
import de.votian.services.entity.CostCenter;
import de.votian.services.entity.Job;
import de.votian.services.entity.Tour;
import de.votian.services.service.JobService;
import de.votian.services.service.ParameterService;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class AccessControlService {

    private final JobService jobService;
    private final ParameterService parameterService;

    public AccessControlService(JobService jobService, ParameterService parameterService) {
        this.jobService = jobService;
        this.parameterService = parameterService;
    }

    public UserSessionDto sessionUser(Authentication authentication) {
        if (authentication == null || !(authentication.getPrincipal() instanceof UserSessionDto user)) {
            return null;
        }
        return user;
    }

    public boolean isHeadquartersUser(UserSessionDto user) {
        return user != null && Integer.valueOf(1).equals(user.getUserType());
    }

    public boolean isCustomerUser(UserSessionDto user) {
        return user != null && Integer.valueOf(2).equals(user.getUserType());
    }

    public boolean isCourierUser(UserSessionDto user) {
        return user != null && Integer.valueOf(3).equals(user.getUserType());
    }

    public boolean isWarehouseUser(UserSessionDto user) {
        return user != null && Integer.valueOf(4).equals(user.getUserType());
    }

    public boolean hasCostCenterAccess(UserSessionDto user, Long costCenterId) {
        return costCenterId == null
                || costCenterId <= 0
                || user != null
                && user.getAccessibleCostCenterIds() != null
                && user.getAccessibleCostCenterIds().contains(costCenterId);
    }

    public boolean canViewCustomers(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 0);
    }

    public boolean canManageCustomers(UserSessionDto user) {
        return canViewCustomers(user);
    }

    public boolean canViewCouriers(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 1);
    }

    public boolean canManageCouriers(UserSessionDto user) {
        return canViewCouriers(user);
    }

    public boolean canViewEmployees(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return hqRight(user, 3);
        }
        if (isCustomerUser(user)) {
            return true;
        }
        return false;
    }

    public boolean canManageEmployees(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return hqRight(user, 3);
        }
        return isCustomerUser(user) && customerRight(user, 2);
    }

    public boolean canManageEmployeeMatrixRights(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 3);
    }

    public boolean canManageEmployeeCostCenterMatrix(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return canManageEmployees(user);
        }
        return isCustomerUser(user) && customerRight(user, 2) && customerRight(user, 12);
    }

    public boolean canViewCostCenters(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return canViewCustomers(user);
        }
        return isCustomerUser(user) && customerRight(user, 0);
    }

    public boolean canManageCostCenters(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return canManageCustomers(user);
        }
        return isCustomerUser(user) && customerRight(user, 1);
    }

    public boolean canViewJobs(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return hqRight(user, 4) || hqRight(user, 7);
        }
        if (isCustomerUser(user)) {
            return customerRight(user, 4);
        }
        return false;
    }

    public boolean canManageJobs(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return hqRight(user, 7);
        }
        return isCustomerUser(user) && customerRight(user, 4);
    }

    public boolean canBatchJobs(UserSessionDto user) {
        return canManageJobs(user);
    }

    public boolean canExportJobs(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return canViewJobs(user) && hqRight(user, 42);
        }
        return isCustomerUser(user) && canViewJobs(user) && customerRight(user, 7);
    }

    public boolean canViewInvoices(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return hqRight(user, 5);
        }
        if (isCustomerUser(user)) {
            return customerRight(user, 5);
        }
        return isCourierUser(user);
    }

    public boolean canExportInvoices(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return hqRight(user, 5);
        }
        if (isCustomerUser(user)) {
            return customerRight(user, 7);
        }
        return isCourierUser(user);
    }

    public boolean canViewStatistics(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return hqRight(user, 8);
        }
        return isCustomerUser(user) && customerRight(user, 8);
    }

    public boolean canViewDisposition(UserSessionDto user) {
        return isHeadquartersUser(user) && (hqRight(user, 7) || hqRight(user, 19));
    }

    public boolean canManageDisposition(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 7);
    }

    public boolean canViewLonghaul(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 10);
    }

    public boolean canManageLonghaul(UserSessionDto user) {
        return canViewLonghaul(user);
    }

    public boolean canViewGroupware(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 11);
    }

    public boolean canManageGroupware(UserSessionDto user) {
        return canViewGroupware(user);
    }

    public boolean canViewGenericExports(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return hqRight(user, 6);
        }
        return isCustomerUser(user) && customerRight(user, 7);
    }

    public boolean canManageGenericExports(UserSessionDto user) {
        return canViewGenericExports(user);
    }

    public boolean canViewCustomerReports(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 16) && hqRight(user, 0);
    }

    public boolean canViewCourierReports(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 16) && hqRight(user, 1);
    }

    public boolean canViewProspectReports(UserSessionDto user) {
        return canViewCustomerReports(user);
    }

    public boolean canViewReports(UserSessionDto user) {
        return canViewCustomerReports(user) || canViewCourierReports(user) || canViewProspectReports(user);
    }

    public boolean canManageReports(UserSessionDto user) {
        return canViewReports(user);
    }

    public boolean canViewConfidentialReports(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 10);
    }

    public boolean canManageCourierMessageGroups(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 1);
    }

    public boolean canManageDeviceMessages(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 4);
    }

    public boolean canManageTicker(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 18);
    }

    public boolean canManageNewsletter(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 17);
    }

    public boolean canViewCommunication(UserSessionDto user) {
        return canManageCourierMessageGroups(user)
                || canManageDeviceMessages(user)
                || canManageTicker(user)
                || canManageNewsletter(user);
    }

    public boolean canManageCommunication(UserSessionDto user) {
        return canViewCommunication(user);
    }

    public boolean canViewGlobalMap(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 19);
    }

    public boolean canViewSimilaritySearch(UserSessionDto user) {
        return isHeadquartersUser(user) && (hqRight(user, 0) || hqRight(user, 1));
    }

    public boolean canManageAddressDirectory(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 2);
    }

    public boolean canManageTravelTimes(UserSessionDto user) {
        return canManageAddressDirectory(user);
    }

    public boolean canViewGeoOperations(UserSessionDto user) {
        return canViewGlobalMap(user)
                || canViewSimilaritySearch(user)
                || canManageAddressDirectory(user);
    }

    public boolean canManageGeoOperations(UserSessionDto user) {
        return canViewGeoOperations(user);
    }

    public boolean canViewTracking(UserSessionDto user) {
        if (isHeadquartersUser(user)) {
            return canViewDisposition(user) || canViewJobs(user);
        }
        if (!isCustomerUser(user) || !canViewJobs(user)) {
            return false;
        }
        long hqId = user.getHeadquartersId() != null ? user.getHeadquartersId() : 0L;
        long empId = user.getEmployeeId() != null ? user.getEmployeeId() : 0L;
        Long customerId = user.getCustomerId();
        if (customerId == null || customerId <= 0) {
            return false;
        }

        String value = parameterService.getParameterValueFullFallback(
                empId,
                ParameterKeys.TRACKING_ENABLED_CS + customerId,
                hqId
        );
        if (value == null || value.isBlank()) {
            value = parameterService.getParameterValueFullFallback(
                    empId,
                    ParameterKeys.CS_TRACKING_ENABLED,
                    hqId
            );
        }
        return "1".equals(value);
    }

    public boolean canUseLonghaulRemoteDb(UserSessionDto user) {
        if (!canViewLonghaul(user) || user == null || user.getEmployeeId() == null) {
            return false;
        }
        String configuredEmployees = parameterService.getParameterValueWithFallback(
                ParameterKeys.LONGHAUL_REMOTE_DB_EMPLOYEE_IDS,
                0L
        );
        if (configuredEmployees == null || configuredEmployees.isBlank()) {
            return false;
        }
        String needle = "," + user.getEmployeeId() + ",";
        String haystack = configuredEmployees.startsWith(",")
                ? configuredEmployees
                : "," + configuredEmployees;
        if (!haystack.endsWith(",")) {
            haystack = haystack + ",";
        }
        return haystack.contains(needle);
    }

    public boolean canManagePricing(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 2) && hqRight(user, 29);
    }

    public boolean canManageHeadquarters(UserSessionDto user) {
        return isHeadquartersUser(user) && hqRight(user, 2);
    }

    public boolean canManageMetaFields(UserSessionDto user) {
        return canManageHeadquarters(user);
    }

    public boolean canManageImports(UserSessionDto user) {
        return isHeadquartersUser(user) && (hqRight(user, 15) || hqRight(user, 22) || hqRight(user, 23));
    }

    public boolean canManageEmployeeWarehouseConfig(UserSessionDto user) {
        return isHeadquartersUser(user) && canManageEmployees(user);
    }

    public boolean canViewWarehouse(UserSessionDto user) {
        return isWarehouseUser(user) || (isHeadquartersUser(user) && hqRight(user, 14));
    }

    public boolean canEditOwnEmployeeAccount(UserSessionDto user) {
        if (!isCustomerUser(user)) {
            return false;
        }
        if (customerRight(user, 10)) {
            return true;
        }
        long employeeId = user.getEmployeeId() != null ? user.getEmployeeId() : 0L;
        long headquartersId = user.getHeadquartersId() != null ? user.getHeadquartersId() : 0L;
        return "1".equals(parameterService.getParameterValueFullFallback(
                employeeId,
                ParameterKeys.GLOBAL_CUSTOMER_READONLY_DISABLED,
                headquartersId
        ));
    }

    public boolean canAccessHeadquarters(UserSessionDto user, Long hqId) {
        return user != null
                && hqId != null
                && user.getHeadquartersId() != null
                && user.getHeadquartersId().equals(hqId);
    }

    public boolean canAccessCustomer(UserSessionDto user, Long customerId) {
        if (customerId == null || user == null) {
            return false;
        }
        if (isHeadquartersUser(user)) {
            return canViewCustomers(user);
        }
        return isCustomerUser(user) && customerId.equals(user.getCustomerId());
    }

    public boolean canAccessCostCenter(UserSessionDto user, CostCenter costCenter) {
        if (costCenter == null) {
            return false;
        }
        if (isHeadquartersUser(user)) {
            return canViewCostCenters(user);
        }
        return isCustomerUser(user)
                && costCenter.getCustomerId() != null
                && costCenter.getCustomerId().equals(user.getCustomerId())
                && hasCostCenterAccess(user, costCenter.getId());
    }

    public boolean canAccessEmployee(UserSessionDto user, EmployeeDetailDto employee) {
        if (employee == null || user == null) {
            return false;
        }
        if (isHeadquartersUser(user)) {
            return canViewEmployees(user)
                    && employee.getHeadquartersId() != null
                    && canAccessHeadquarters(user, employee.getHeadquartersId());
        }
        return isCustomerUser(user)
                && employee.getCustomerId() != null
                && employee.getCustomerId().equals(user.getCustomerId())
                && (canManageEmployees(user) || isOwnEmployee(user, employee.getId()));
    }

    public boolean canEditEmployee(UserSessionDto user, EmployeeDetailDto employee) {
        if (employee == null || user == null) {
            return false;
        }
        if (isHeadquartersUser(user)) {
            return canManageEmployees(user)
                    && employee.getHeadquartersId() != null
                    && canAccessHeadquarters(user, employee.getHeadquartersId());
        }
        return isCustomerUser(user)
                && employee.getCustomerId() != null
                && employee.getCustomerId().equals(user.getCustomerId())
                && (canManageEmployees(user)
                || (isOwnEmployee(user, employee.getId()) && canEditOwnEmployeeAccount(user)));
    }

    public boolean canAccessJob(UserSessionDto user, Job job) {
        if (user == null || job == null) {
            return false;
        }
        if (isHeadquartersUser(user)) {
            return canAccessHeadquarters(user, job.getHeadquartersId())
                    && (canViewJobs(user) || canViewInvoices(user) || canViewDisposition(user));
        }
        if (isCourierUser(user)) {
            return user.getCourierId() != null && user.getCourierId().equals(job.getCourierId());
        }
        if (isCustomerUser(user)) {
            return jobMatchesCostCenters(job, user.getAccessibleCostCenterIds());
        }
        return false;
    }

    private boolean jobMatchesCostCenters(Job job, List<Long> accessibleCostCenterIds) {
        if (accessibleCostCenterIds == null || accessibleCostCenterIds.isEmpty()) {
            return false;
        }
        if (matchesCostCenter(accessibleCostCenterIds, job.getCostCenterPayerId())
                || matchesCostCenter(accessibleCostCenterIds, job.getCostCenterPayerCashId())
                || matchesCostCenter(accessibleCostCenterIds, job.getCostCenterRelatedId())) {
            return true;
        }
        for (Tour tour : jobService.getTours(job.getId())) {
            if (matchesCostCenter(accessibleCostCenterIds, tour.getCostCenterId())) {
                return true;
            }
        }
        return false;
    }

    private boolean matchesCostCenter(List<Long> accessibleCostCenterIds, Long costCenterId) {
        return costCenterId != null && accessibleCostCenterIds != null && accessibleCostCenterIds.contains(costCenterId);
    }

    private boolean isOwnEmployee(UserSessionDto user, Long employeeId) {
        return user != null
                && user.getEmployeeId() != null
                && employeeId != null
                && user.getEmployeeId().equals(employeeId);
    }

    private boolean hqRight(UserSessionDto user, int index) {
        return legacyRight(user, index, true);
    }

    private boolean customerRight(UserSessionDto user, int index) {
        return legacyRight(user, index, false);
    }

    private boolean legacyRight(UserSessionDto user, int index, boolean defaultIfMissing) {
        if (user == null || index < 0) {
            return false;
        }
        String rights = user.getLegacyRights();
        if (rights == null || rights.isBlank()) {
            return defaultIfMissing;
        }
        if (index >= rights.length()) {
            return false;
        }
        return rights.charAt(index) == '1';
    }
}
