package com.iqser.red.service.persistence.management.v1.processor.service.persistence;

import java.time.OffsetDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ComponentDefinitionEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ComponentDefinitionRepository;
import com.iqser.red.service.persistence.management.v1.processor.utils.SnakeCaseUtils;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionAddRequest;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class ComponentDefinitionPersistenceService {

    private final ComponentDefinitionRepository componentDefinitionRepository;


    public ComponentDefinitionEntity insert(ComponentDefinitionAddRequest component, String dossierTemplateId) {

        return insert(component, maxRankByDossierTemplateId(dossierTemplateId) + 1, dossierTemplateId);
    }


    public ComponentDefinitionEntity insert(ComponentDefinitionEntity componentDefinition) {

        return componentDefinitionRepository.saveAndFlush(componentDefinition);
    }


    public ComponentDefinitionEntity insert(ComponentDefinitionAddRequest component, int rank, String dossierTemplateId) {

        ComponentDefinitionEntity componentDefinitionEntity = new ComponentDefinitionEntity();
        componentDefinitionEntity.setId(UUID.randomUUID().toString());
        componentDefinitionEntity.setDossierTemplateId(dossierTemplateId);
        componentDefinitionEntity.setTechnicalName(SnakeCaseUtils.toSnakeCase(component.getTechnicalName()));
        componentDefinitionEntity.setDisplayName(StringUtils.isEmpty(component.getDisplayName()) ? component.getTechnicalName() : component.getDisplayName());
        componentDefinitionEntity.setDescription(component.getDescription());
        componentDefinitionEntity.setRank(rank);
        return componentDefinitionRepository.saveAndFlush(componentDefinitionEntity);
    }


    public void delete(String id) {

        componentDefinitionRepository.deleteById(id);
    }


    public int maxRankByDossierTemplateId(String dossierTemplateId) {

        return componentDefinitionRepository.maxRankByDossierTemplateId(dossierTemplateId);
    }


    public ComponentDefinitionEntity update(ComponentDefinitionEntity componentDefinitionEntity) {

        return componentDefinitionRepository.saveAndFlush(componentDefinitionEntity);
    }


    public ComponentDefinitionEntity findComponent(String dossierTemplateId, String componentId) {

        return componentDefinitionRepository.findByIdAndDossierTemplateId(componentId, dossierTemplateId)
                .orElseThrow(() -> new NotFoundException("Component with id: " + componentId + " not found"));
    }


    @Transactional
    public List<ComponentDefinitionEntity> softDeleteComponents(String dossierTemplateId, List<String> componentIds, OffsetDateTime softDeleteTime) {

        componentDefinitionRepository.updateSoftDeleteForIds(componentIds, dossierTemplateId, softDeleteTime);
        return componentDefinitionRepository.findByIdsAndDossierTemplateId(componentIds, dossierTemplateId);
    }


    @Transactional
    public List<ComponentDefinitionEntity> restoreComponents(String dossierTemplateId, List<String> componentIds) {

        componentDefinitionRepository.updateSoftDeleteForIds(componentIds, dossierTemplateId, null);
        return componentDefinitionRepository.findByIdsAndDossierTemplateId(componentIds, dossierTemplateId);
    }


    @Transactional
    public ComponentDefinitionEntity restoreComponent(String dossierTemplateId, String componentId) {

        componentDefinitionRepository.updateSoftDeleteForIds(List.of(componentId), dossierTemplateId, null);
        return componentDefinitionRepository.findById(componentId)
                .orElseThrow(() -> new NotFoundException("Component with id: " + componentId + " not found"));
    }


    public ComponentDefinitionEntity findComponentByDossierTemplateIdAndComponentId(String dossierTemplateId, String componentId) {

        return componentDefinitionRepository.findByIdAndDossierTemplateId(componentId, dossierTemplateId)
                .orElseThrow(() -> new NotFoundException(String.format("Component with id %s not found in dossier template %s", componentId, dossierTemplateId)));
    }


    public List<ComponentDefinitionEntity> findComponentsByDossierTemplateId(String dossierTemplateId) {

        return componentDefinitionRepository.findByDossierTemplateId(dossierTemplateId);
    }


    public List<ComponentDefinitionEntity> findByDossierTemplateIdAndNotSoftDeleted(String dossierTemplateId) {

        return componentDefinitionRepository.findByDossierTemplateIdAndSoftDeletedTimeIsNull(dossierTemplateId);
    }


    public Optional<String> findIdByDossierTemplateIdAndTechnicalNameAndIsSoftDeleted(String dossierTemplateId, String technicalName) {

        return componentDefinitionRepository.findIdByDossierTemplateIdAndTechnicalNameAndIsSoftDeleted(dossierTemplateId, technicalName);
    }

}
