package br.gov.sigefp.org.service;

import br.gov.sigefp.org.api.dto.PositionDTO;
import br.gov.sigefp.org.domain.OrgUnit;
import br.gov.sigefp.org.domain.Position;
import br.gov.sigefp.org.repository.OrgUnitRepository;
import br.gov.sigefp.org.repository.PositionRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * Serviço de aplicação para gestão de posições/cargos.
 */
@Service
@RequiredArgsConstructor
@Transactional
public class PositionService {

    private final PositionRepository positionRepository;
    private final OrgUnitRepository orgUnitRepository;
    private final br.gov.sigefp.common.service.GlobalAuditLogService auditLogService;

    public PositionDTO create(PositionDTO dto) {
        // Validação: unicidade de código
        if (positionRepository.existsByCode(dto.getCode())) {
            throw new IllegalArgumentException("Código de posição já existe: " + dto.getCode());
        }

        OrgUnit orgUnit = orgUnitRepository.findById(dto.getOrgUnitId())
                .orElseThrow(() -> new IllegalArgumentException(
                        "Unidade organizacional não encontrada: " + dto.getOrgUnitId()));

        Position position = Position.builder()
                .orgUnit(orgUnit)
                .code(dto.getCode())
                .title(dto.getTitle())
                .level(dto.getLevel())
                .isActive(dto.getIsActive() != null ? dto.getIsActive() : true)
                .build();

        Position saved = positionRepository.save(position);
        return toDTO(saved);
    }

    public PositionDTO update(UUID id, PositionDTO dto) {
        Position position = positionRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Posição não encontrada: " + id));

        StringBuilder log = new StringBuilder();

        if (dto.getCode() != null && !dto.getCode().equals(position.getCode())) {
            if (positionRepository.existsByCode(dto.getCode())) {
                throw new IllegalArgumentException("Código de posição já existe: " + dto.getCode());
            }
            log.append("Código: [").append(position.getCode()).append("] -> [").append(dto.getCode()).append("]. ");
            position.setCode(dto.getCode());
        }

        if (dto.getOrgUnitId() != null && !dto.getOrgUnitId().equals(position.getOrgUnit().getId())) {
            OrgUnit orgUnit = orgUnitRepository.findById(dto.getOrgUnitId())
                    .orElseThrow(() -> new IllegalArgumentException(
                            "Unidade organizacional não encontrada: " + dto.getOrgUnitId()));
            log.append("Unidade: [").append(position.getOrgUnit().getName()).append("] -> [").append(orgUnit.getName())
                    .append("]. ");
            position.setOrgUnit(orgUnit);
        }

        if (dto.getTitle() != null && !dto.getTitle().equals(position.getTitle())) {
            log.append("Título: [").append(position.getTitle()).append("] -> [").append(dto.getTitle()).append("]. ");
            position.setTitle(dto.getTitle());
        }
        if (dto.getLevel() != null && !dto.getLevel().equals(position.getLevel())) {
            log.append("Nível: [").append(position.getLevel()).append("] -> [").append(dto.getLevel()).append("]. ");
            position.setLevel(dto.getLevel());
        }
        if (dto.getIsActive() != null && !dto.getIsActive().equals(position.getIsActive())) {
            log.append("Ativo: [").append(position.getIsActive()).append("] -> [").append(dto.getIsActive())
                    .append("]. ");
            position.setIsActive(dto.getIsActive());
        }

        Position saved = positionRepository.save(position);

        if (log.length() > 0) {
            // Nota: id do usuário viria do SecurityContext em produção
            auditLogService.logAction(null, "system", "ORG", "UPDATE", "Position", id, log.toString());
        }

        return toDTO(saved);
    }

    @Transactional(readOnly = true)
    public PositionDTO findById(UUID id) {
        Position position = positionRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Posição não encontrada: " + id));
        return toDTO(position);
    }

    @Transactional(readOnly = true)
    public Page<PositionDTO> findAll(Pageable pageable) {
        return positionRepository.findAll(pageable).map(this::toDTO);
    }

    @Transactional(readOnly = true)
    public List<PositionDTO> findByOrgUnitId(UUID orgUnitId) {
        return positionRepository.findByOrgUnitId(orgUnitId).stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    private PositionDTO toDTO(Position position) {
        return PositionDTO.builder()
                .id(position.getId())
                .orgUnitId(position.getOrgUnit().getId())
                .code(position.getCode())
                .title(position.getTitle())
                .level(position.getLevel())
                .isActive(position.getIsActive())
                .build();
    }
}
