package ru.soune.nocopy.handler; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Component; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BindingResult; import ru.soune.nocopy.dto.BaseRequest; import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.company.CompanyActionRequestDto; import ru.soune.nocopy.dto.company.CompanyResponseDto; import ru.soune.nocopy.entity.company.Company; import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.exception.ResourceNotFoundException; import ru.soune.nocopy.exception.ValidationException; import ru.soune.nocopy.handler.validator.RegRequestValidator; import ru.soune.nocopy.service.CompanyService; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Slf4j @Component @RequiredArgsConstructor public class CompanyHandler implements RequestHandler { private final CompanyService companyService; private final RegRequestValidator regRequestValidator; private final ObjectMapper objectMapper; @Override public BaseResponse handle(BaseRequest request) { try { CompanyActionRequestDto actionRequest = objectMapper.convertValue( request.getMessageBody(), CompanyActionRequestDto.class ); String action = actionRequest.getAction(); return switch (action) { case "create" -> handleCreate(actionRequest, request.getMsgId()); case "update" -> handleUpdate(actionRequest, request.getMsgId()); case "delete" -> handleDelete(actionRequest, request.getMsgId()); case "getCompany" -> handleGet(actionRequest, request.getMsgId()); case "getAll" -> handleGetAll(actionRequest, request.getMsgId()); case "addUser" -> handleAddUser(actionRequest, request.getMsgId()); case "removeUser" -> handleRemoveUser(actionRequest, request.getMsgId()); case "getUsers" -> handleGetUsers(actionRequest, request.getMsgId()); case "search" -> handleSearch(actionRequest, request.getMsgId()); case "countUser" -> handleCountUsers(actionRequest, request.getMsgId()); default -> new BaseResponse( request.getMsgId(), MessageCode.INVALID_ACTION.getCode(), "Invalid action: " + action, null ); }; } catch (ValidationException e) { Map errors = e.getBindingResult().getFieldErrors().stream() .collect(Collectors.toMap( error -> error.getField(), error -> error.getDefaultMessage() != null ? error.getDefaultMessage() : "Validation error" )); return new BaseResponse( request.getMsgId(), MessageCode.VALIDATION_ERROR.getCode(), "Validation failed", Map.of("errors", errors) ); } catch (ResourceNotFoundException e) { return new BaseResponse( request.getMsgId(), MessageCode.COMPANY_NOT_FOUND.getCode(), e.getMessage(), null ); } catch (IllegalArgumentException e) { return new BaseResponse( request.getMsgId(), MessageCode.VALIDATION_ERROR.getCode(), e.getMessage(), null ); } catch (Exception e) { log.error("Error handling company action", e); return new BaseResponse( request.getMsgId(), MessageCode.INTERNAL_ERROR.getCode(), "Error processing request: " + e.getMessage(), null ); } } private BaseResponse handleCreate(CompanyActionRequestDto request, Integer msgId) { if (companyService.companyExistsByName(request.getCompanyName())) { return new BaseResponse( msgId, MessageCode.COMPANY_ALREADY_EXISTS.getCode(), "Company with this name already exists", null ); } validateCompanyCreateData(request); Company company = companyService.addCompany( request.getCompanyName(), getStringParam(request, "phone"), getStringParam(request, "address"), getStringParam(request, "email") ); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "Company created successfully", mapToResponseDto(company) ); } private BaseResponse handleUpdate(CompanyActionRequestDto request, Integer msgId) { if (request.getCompanyId() == null) { throw new IllegalArgumentException("Company ID is required for update"); } Map companyData = request.getCompanyData(); if (companyData == null) { companyData = new HashMap<>(); } Company company = companyService.updateCompany( request.getCompanyId(), (String) companyData.get("companyName"), (String) companyData.get("phone"), (String) companyData.get("address"), (String) companyData.get("email") ); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "Company updated successfully", mapToResponseDto(company) ); } private BaseResponse handleDelete(CompanyActionRequestDto request, Integer msgId) { if (request.getCompanyId() == null) { throw new IllegalArgumentException("Company ID is required for deletion"); } companyService.deleteCompany(request.getCompanyId()); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "Company deleted successfully", Map.of("deletedCompanyId", request.getCompanyId()) ); } private BaseResponse handleGet(CompanyActionRequestDto request, Integer msgId) { Company company; if (request.getCompanyId() != null) { company = companyService.getCompanyById(request.getCompanyId()); } else if (request.getCompanyName() != null) { company = companyService.getCompanyByName(request.getCompanyName()); } else { throw new IllegalArgumentException("Either companyId or companyName is required"); } return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "Company retrieved successfully", mapToResponseDto(company) ); } private BaseResponse handleGetAll(CompanyActionRequestDto request, Integer msgId) { List companies; if (request.getPageable() != null) { Pageable pageable = createPageable(request.getPageable()); Page companyPage = companyService.getAllCompanies(pageable); List companyDtos = companyPage.getContent().stream() .map(this::mapToResponseDto) .collect(Collectors.toList()); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "Companies retrieved successfully", Map.of( "companies", companyDtos, "totalElements", companyPage.getTotalElements(), "totalPages", companyPage.getTotalPages(), "currentPage", companyPage.getNumber(), "pageSize", companyPage.getSize() ) ); } else { companies = companyService.getAllCompanies(); List companyDtos = companies.stream() .map(this::mapToResponseDto) .collect(Collectors.toList()); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "Companies retrieved successfully", Map.of("companies", companyDtos) ); } } private BaseResponse handleAddUser(CompanyActionRequestDto request, Integer msgId) { if (request.getCompanyId() == null || request.getUserId() == null) { throw new IllegalArgumentException("Company ID and User ID are required"); } companyService.addUserToCompany(request.getCompanyId(), request.getUserId()); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "User added to company successfully", Map.of( "companyId", request.getCompanyId(), "userId", request.getUserId() ) ); } private BaseResponse handleRemoveUser(CompanyActionRequestDto request, Integer msgId) { if (request.getUserId() == null) { throw new IllegalArgumentException("User ID is required"); } companyService.deleteUserFromCompany(request.getUserId()); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "User removed from company successfully", Map.of("userId", request.getUserId()) ); } private BaseResponse handleGetUsers(CompanyActionRequestDto request, Integer msgId) { if (request.getCompanyId() == null) { throw new IllegalArgumentException("Company ID is required"); } List users = companyService.getCompanyUsers(request.getCompanyId()); List> userDtos = users.stream() .map(user -> { Map map = new HashMap<>(); map.put("id", user.getId()); map.put("email", user.getEmail()); map.put("phone", user.getPhone()); map.put("fullName", user.getFullName()); return map; }).toList(); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "Company users retrieved successfully", Map.of( "companyId", request.getCompanyId(), "users", userDtos, "count", userDtos.size() ) ); } private BaseResponse handleSearch(CompanyActionRequestDto request, Integer msgId) { String searchTerm = getStringParam(request, "name"); if (searchTerm == null) { throw new IllegalArgumentException("Search term is required"); } List companies = companyService.searchCompaniesByName(searchTerm); List companyDtos = companies.stream() .map(this::mapToResponseDto) .collect(Collectors.toList()); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "Companies search completed", Map.of( "searchTerm", searchTerm, "companies", companyDtos, "count", companyDtos.size() ) ); } private BaseResponse handleCountUsers(CompanyActionRequestDto request, Integer msgId) { if (request.getCompanyId() == null) { throw new IllegalArgumentException("Company ID is required"); } long count = companyService.countCompanyUsers(request.getCompanyId()); return new BaseResponse( msgId, MessageCode.SUCCESS.getCode(), "User count retrieved", Map.of( "companyId", request.getCompanyId(), "userCount", count ) ); } private void validateCompanyCreateData(CompanyActionRequestDto request) throws ValidationException { BindingResult bindingResult = new BeanPropertyBindingResult(request, "companyRequest"); if (request.getCompanyName() != null) { regRequestValidator.validateCompanyName(request.getCompanyName(), bindingResult); } String email = getStringParam(request, "email"); if (email != null) { regRequestValidator.validateEmail(email, bindingResult); } String phone = getStringParam(request, "phone"); if (phone != null) { regRequestValidator.validatePhone(phone, bindingResult); } if (bindingResult.hasErrors()) { throw new ValidationException(bindingResult, null); } } private String getStringParam(CompanyActionRequestDto request, String paramName) { if (request.getCompanyData() != null) { Object value = request.getCompanyData().get(paramName); return value != null ? value.toString() : null; } Map searchParams = request.getSearchParams(); if (searchParams != null) { Object value = searchParams.get(paramName); return value != null ? value.toString() : null; } return null; } private CompanyResponseDto mapToResponseDto(Company company) { CompanyResponseDto dto = new CompanyResponseDto(); dto.setId(company.getId()); dto.setCompanyName(company.getCompanyName()); dto.setPhone(company.getPhone()); dto.setAddress(company.getAddress()); dto.setEmail(company.getEmail()); dto.setRegisterDate(company.getRegisterDate()); dto.setUpdateDate(company.getUpdateDate()); try { dto.setUserCount(companyService.countCompanyUsers(company.getId())); } catch (Exception e) { dto.setUserCount(0); } return dto; } private Pageable createPageable(CompanyActionRequestDto.PageableParams params) { Sort sort = Sort.unsorted(); if (params.getSort() != null) { Sort.Direction direction = params.getDirection() != null && "desc".equalsIgnoreCase(params.getDirection()) ? Sort.Direction.DESC : Sort.Direction.ASC; sort = Sort.by(direction, params.getSort()); } return PageRequest.of( params.getPage(), params.getSize(), sort ); } }