package de.votian.services.controller;

import de.votian.services.dto.EmployeeDetailDto;
import de.votian.services.dto.EmployeeListItemDto;
import de.votian.services.dto.EmployeeWarehouseConfigDto;
import de.votian.services.dto.EmployeeWarehouseConfigRequest;
import de.votian.services.dto.UserSessionDto;
import de.votian.services.entity.CostCenter;
import de.votian.services.entity.Employee;
import de.votian.services.entity.EmployeeCostCenter;
import de.votian.services.entity.EmployeeRights;
import de.votian.services.entity.User;
import de.votian.services.repository.CostCenterRepository;
import de.votian.services.security.AccessControlService;
import de.votian.services.service.EmployeeService;
import de.votian.services.service.EmployeeWarehouseConfigService;
import de.votian.services.service.ViewDataService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/employees")
public class EmployeeController {

    private final EmployeeService employeeService;
    private final ViewDataService viewDataService;
    private final CostCenterRepository costCenterRepository;
    private final AccessControlService accessControlService;
    private final EmployeeWarehouseConfigService employeeWarehouseConfigService;

    public EmployeeController(EmployeeService employeeService,
                              ViewDataService viewDataService,
                              CostCenterRepository costCenterRepository,
                              AccessControlService accessControlService,
                              EmployeeWarehouseConfigService employeeWarehouseConfigService) {
        this.employeeService = employeeService;
        this.viewDataService = viewDataService;
        this.costCenterRepository = costCenterRepository;
        this.accessControlService = accessControlService;
        this.employeeWarehouseConfigService = employeeWarehouseConfigService;
    }

    @GetMapping("/{id}")
    public ResponseEntity<EmployeeDetailDto> findById(@PathVariable Long id, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!accessControlService.canViewEmployees(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return viewDataService.findEmployeeDetail(id)
                .map(employee -> accessControlService.canAccessEmployee(user, employee)
                        ? ResponseEntity.ok(employee)
                        : ResponseEntity.status(HttpStatus.FORBIDDEN).<EmployeeDetailDto>build())
                .orElse(ResponseEntity.notFound().build());
    }

    @GetMapping
    public ResponseEntity<List<EmployeeListItemDto>> findAll(Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!accessControlService.canViewEmployees(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(viewDataService.findEmployees().stream()
                .filter(employee -> canAccessEmployeeListItem(user, employee))
                .toList());
    }

    @PostMapping
    public ResponseEntity<Employee> create(@RequestBody EmployeeCreateRequest request, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (request == null || request.employee == null || request.user == null
                || !accessControlService.canManageEmployees(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        if (!prepareAndValidateRequest(user, request.employee, request.user, null)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        Employee created = employeeService.createEmployee(request.employee, request.user, request.password);
        return ResponseEntity.ok(created);
    }

    @PutMapping("/{id}")
    public ResponseEntity<Employee> update(@PathVariable Long id,
                                           @RequestBody EmployeeUpdateRequest request,
                                           Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (request == null || request.employee == null || request.user == null) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }

        EmployeeDetailDto existingDetail = viewDataService.findEmployeeDetail(id).orElse(null);
        if (existingDetail == null) {
            return ResponseEntity.notFound().build();
        }
        if (!accessControlService.canEditEmployee(user, existingDetail)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        if (!prepareAndValidateRequest(user, request.employee, request.user, existingDetail)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }

        Employee updated = employeeService.updateEmployee(id, request.employee, request.user);
        return ResponseEntity.ok(updated);
    }

    @GetMapping("/{id}/rights")
    public ResponseEntity<List<EmployeeRights>> getRights(@PathVariable Long id, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        EmployeeDetailDto existingDetail = viewDataService.findEmployeeDetail(id).orElse(null);
        if (existingDetail == null) {
            return ResponseEntity.notFound().build();
        }
        if (!accessControlService.canManageEmployeeMatrixRights(user)
                || !accessControlService.canAccessEmployee(user, existingDetail)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(employeeService.getRights(id));
    }

    @PutMapping("/{id}/rights")
    public ResponseEntity<Void> setRights(@PathVariable Long id,
                                          @RequestBody List<EmployeeRights> rights,
                                          Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        EmployeeDetailDto existingDetail = viewDataService.findEmployeeDetail(id).orElse(null);
        if (existingDetail == null) {
            return ResponseEntity.notFound().build();
        }
        if (!accessControlService.canManageEmployeeMatrixRights(user)
                || !accessControlService.canAccessEmployee(user, existingDetail)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        employeeService.setRights(id, rights);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/{id}/costcenters")
    public ResponseEntity<List<EmployeeCostCenter>> getCostCenterAccess(@PathVariable Long id,
                                                                        Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        EmployeeDetailDto existingDetail = viewDataService.findEmployeeDetail(id).orElse(null);
        if (existingDetail == null) {
            return ResponseEntity.notFound().build();
        }
        if (!accessControlService.canManageEmployeeCostCenterMatrix(user)
                || !accessControlService.canAccessEmployee(user, existingDetail)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(employeeService.getCostCenterAccess(id));
    }

    @PutMapping("/{id}/costcenters")
    public ResponseEntity<Void> setCostCenterAccess(@PathVariable Long id,
                                                    @RequestBody List<EmployeeCostCenter> costCenters,
                                                    Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        EmployeeDetailDto existingDetail = viewDataService.findEmployeeDetail(id).orElse(null);
        if (existingDetail == null) {
            return ResponseEntity.notFound().build();
        }
        if (!accessControlService.canManageEmployeeCostCenterMatrix(user)
                || !accessControlService.canAccessEmployee(user, existingDetail)
                || !allCostCentersAllowed(user, costCenters)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        employeeService.setCostCenterAccess(id, costCenters);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/warehouse-config-template")
    public ResponseEntity<EmployeeWarehouseConfigDto> warehouseConfigTemplate(Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!accessControlService.canManageEmployeeWarehouseConfig(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(employeeWarehouseConfigService.loadTemplate(user.getHeadquartersId()));
    }

    @GetMapping("/{id}/warehouse-config")
    public ResponseEntity<EmployeeWarehouseConfigDto> getWarehouseConfig(@PathVariable Long id,
                                                                         Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        EmployeeDetailDto existingDetail = viewDataService.findEmployeeDetail(id).orElse(null);
        if (existingDetail == null) {
            return ResponseEntity.notFound().build();
        }
        if (!accessControlService.canManageEmployeeWarehouseConfig(user)
                || !accessControlService.canAccessEmployee(user, existingDetail)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(employeeWarehouseConfigService.loadConfig(id));
    }

    @PutMapping("/{id}/warehouse-config")
    public ResponseEntity<Void> setWarehouseConfig(@PathVariable Long id,
                                                   @RequestBody EmployeeWarehouseConfigRequest request,
                                                   Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        EmployeeDetailDto existingDetail = viewDataService.findEmployeeDetail(id).orElse(null);
        if (existingDetail == null) {
            return ResponseEntity.notFound().build();
        }
        if (!accessControlService.canManageEmployeeWarehouseConfig(user)
                || !accessControlService.canEditEmployee(user, existingDetail)
                || !accessControlService.canAccessEmployee(user, existingDetail)
                || (user != null && user.getEmployeeId() != null && user.getEmployeeId().equals(id))) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        employeeWarehouseConfigService.saveConfig(id, request);
        return ResponseEntity.ok().build();
    }

    private boolean prepareAndValidateRequest(UserSessionDto sessionUser,
                                              Employee employee,
                                              User user,
                                              EmployeeDetailDto existingDetail) {
        if (accessControlService.isHeadquartersUser(sessionUser)) {
            Long effectiveHqId = employee.getHeadquartersId() != null ? employee.getHeadquartersId() : sessionUser.getHeadquartersId();
            employee.setHeadquartersId(effectiveHqId);
            if (user.getHeadquartersId() == null) {
                user.setHeadquartersId(effectiveHqId);
            }
            return accessControlService.canAccessHeadquarters(sessionUser, effectiveHqId);
        }

        if (!accessControlService.isCustomerUser(sessionUser)) {
            return false;
        }

        if (existingDetail != null && !Integer.valueOf(2).equals(existingDetail.getUserType())) {
            return false;
        }
        if (user.getType() != null && user.getType() != 2) {
            return false;
        }

        if (!accessControlService.canManageEmployees(sessionUser)) {
            if (existingDetail == null
                    || !accessControlService.canEditEmployee(sessionUser, existingDetail)
                    || !accessControlService.canEditOwnEmployeeAccount(sessionUser)) {
                return false;
            }
            employee.setCostCenterId(existingDetail.getCostCenterId());
            employee.setRights(existingDetail.getRights());
            employee.setHeadquartersId(existingDetail.getHeadquartersId());
            employee.setHeadquarters(existingDetail.getHeadquarters());
        } else {
            employee.setHeadquartersId(sessionUser.getHeadquartersId());
            employee.setHeadquarters("");
        }

        user.setType(2);
        user.setHeadquartersId(sessionUser.getHeadquartersId());

        if (employee.getCostCenterId() == null) {
            return false;
        }
        CostCenter primaryCostCenter = costCenterRepository.findById(Objects.requireNonNull(employee.getCostCenterId())).orElse(null);
        return primaryCostCenter != null
                && sessionUser.getCustomerId() != null
                && sessionUser.getCustomerId().equals(primaryCostCenter.getCustomerId())
                && accessControlService.hasCostCenterAccess(sessionUser, Objects.requireNonNull(primaryCostCenter.getId()));
    }

    private boolean allCostCentersAllowed(UserSessionDto user, List<EmployeeCostCenter> costCenters) {
        if (costCenters == null || costCenters.isEmpty()) {
            return true;
        }
        if (accessControlService.isHeadquartersUser(user)) {
            return true;
        }
        for (EmployeeCostCenter row : costCenters) {
            if (row == null || row.getCostCenterId() == null) {
                return false;
            }
            CostCenter costCenter = costCenterRepository.findById(Objects.requireNonNull(row.getCostCenterId())).orElse(null);
            if (costCenter == null
                    || user.getCustomerId() == null
                    || !user.getCustomerId().equals(costCenter.getCustomerId())
                    || !accessControlService.hasCostCenterAccess(user, costCenter.getId())) {
                return false;
            }
        }
        return true;
    }

    private boolean canAccessEmployeeListItem(UserSessionDto user, EmployeeListItemDto employee) {
        if (employee == null || user == null) {
            return false;
        }
        if (accessControlService.isHeadquartersUser(user)) {
            return employee.getHeadquartersId() != null
                    && accessControlService.canAccessHeadquarters(user, employee.getHeadquartersId());
        }
        return accessControlService.isCustomerUser(user)
                && employee.getCustomerId() != null
                && employee.getCustomerId().equals(user.getCustomerId())
                && (accessControlService.canManageEmployees(user)
                || (user.getEmployeeId() != null && user.getEmployeeId().equals(employee.getId())));
    }

    public static class EmployeeCreateRequest {
        public Employee employee;
        public User user;
        public String password;
    }

    public static class EmployeeUpdateRequest {
        public Employee employee;
        public User user;
    }
}
