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

import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Optional;

import jakarta.transaction.Transactional;

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

import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.WatermarkEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierRepository;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.WatermarkRepository;
import com.iqser.red.service.persistence.management.v1.processor.utils.ColorUtils;
import com.iqser.red.service.persistence.service.v1.api.shared.model.WatermarkModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.HorizontalTextAlignment;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.VerticalTextAlignment;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class WatermarkService {

    private final static String DEFAULT_HEX_COLOR = "#000000";
    private final static int DEFAULT_OPACITY = 30;
    private final WatermarkRepository watermarkRepository;
    private final DossierRepository dossierRepository;
    private final DossierTemplatePersistenceService dossierTemplatePersistenceService;


    @Transactional
    public void deleteWatermark(long watermarkId) {

        watermarkRepository.findById(watermarkId).ifPresentOrElse(loadedWatermark -> {
            dossierRepository.countDeleteWatermark(watermarkId);
            dossierRepository.countDeletePreviewWatermark(watermarkId);
            watermarkRepository.deleteById(watermarkId);
        }, () -> log.debug("Watermark with id '{}' was already deleted.", watermarkId));
    }


    public WatermarkEntity getWatermark(long watermarkId) {

        return watermarkRepository.findById(watermarkId).orElseThrow(() -> new NotFoundException("Watermark Configuration not found"));
    }


    @Transactional
    public WatermarkEntity createOrUpdateWatermark(WatermarkModel watermark) {

        validateWatermarkNameIsPresent(watermark);
        validateHexColorAndSetDefaultIfNeeded(watermark);
        validateOpacityAndSetDefaultIfNeeded(watermark);
        setDefaultTextAlignmentIfNeeded(watermark);
        if (watermark.getId() != null) { // update
            Optional<WatermarkEntity> loadedWatermark = watermarkRepository.findById(watermark.getId());
            if (loadedWatermark.isPresent()) {
                validateDossierTemplateId(watermark.getDossierTemplateId(), loadedWatermark.get().getDossierTemplateId());
                validateWatermarkNameIsUnique(watermark.getName(), loadedWatermark.get().getDossierTemplateId(), loadedWatermark.get().getId());
                BeanUtils.copyProperties(watermark, loadedWatermark.get(), "dossierTemplateId", "createdBy", "dateAdded", "dateModified");
                loadedWatermark.get().setDateModified(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
                var dossierTemplate = dossierTemplatePersistenceService.getDossierTemplate(loadedWatermark.get().getDossierTemplateId());
                loadedWatermark.get().setDossierTemplate(dossierTemplate);
                return loadedWatermark.get();
            } else { // if not found by id -> add it as a new watermark
                validateDossierTemplateId(watermark.getDossierTemplateId(), null);
                validateWatermarkNameIsUnique(watermark.getName(), watermark.getDossierTemplateId(), 0);
                WatermarkEntity watermarkEntity = new WatermarkEntity();
                BeanUtils.copyProperties(watermark, watermarkEntity, "id", "dateAdded", "dateModified");
                watermarkEntity.setDateAdded(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
                var dossierTemplate = dossierTemplatePersistenceService.getDossierTemplate(watermark.getDossierTemplateId());
                watermarkEntity.setDossierTemplate(dossierTemplate);
                return watermarkRepository.save(watermarkEntity);
            }
        } else {
            validateDossierTemplateId(watermark.getDossierTemplateId(), null);
            validateWatermarkNameIsUnique(watermark.getName(), watermark.getDossierTemplateId(), 0);
            WatermarkEntity watermarkEntity = new WatermarkEntity();
            BeanUtils.copyProperties(watermark, watermarkEntity, "id", "dateAdded", "dateModified");
            watermarkEntity.setDateAdded(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
            var dossierTemplate = dossierTemplatePersistenceService.getDossierTemplate(watermark.getDossierTemplateId());
            watermarkEntity.setDossierTemplate(dossierTemplate);
            return watermarkRepository.save(watermarkEntity);
        }
    }


    private void validateOpacityAndSetDefaultIfNeeded(WatermarkModel watermark) {
        if (watermark.getOpacity() < 0) {
            watermark.setOpacity(DEFAULT_OPACITY);
        }
    }

    private void setDefaultTextAlignmentIfNeeded(WatermarkModel watermark) {
        if (watermark.getHorizontalTextAlignment() == null) {
            watermark.setHorizontalTextAlignment(HorizontalTextAlignment.CENTER);
        }

        if (watermark.getVerticalTextAlignment() == null) {
            watermark.setVerticalTextAlignment(VerticalTextAlignment.CENTER);
        }
    }

    private void validateHexColorAndSetDefaultIfNeeded(WatermarkModel watermark) {
        if (StringUtils.isBlank(watermark.getHexColor())) {
            watermark.setHexColor(DEFAULT_HEX_COLOR);
        }

        ColorUtils.validateColor(watermark.getHexColor());
    }

    private void validateWatermarkNameIsPresent(WatermarkModel watermark) {

        if (StringUtils.isBlank(watermark.getName())) {
            throw new BadRequestException("The watermark name must not be empty");
        }
    }


    private void validateDossierTemplateId(String newDossierTemplateId, String existingDossierTemplateId) {

        if (newDossierTemplateId == null && existingDossierTemplateId == null) {
            throw new BadRequestException("The dossier template id is not provided");
        }
        if (newDossierTemplateId != null && existingDossierTemplateId != null && !existingDossierTemplateId.equals(newDossierTemplateId)) {
            throw new ConflictException("The watermark dossier template id does not match");
        }
    }


    private void validateWatermarkNameIsUnique(String watermarkName, String dossierTemplateId, long watermarkId) {

        getWatermarksForDossierTemplateId(dossierTemplateId).forEach(existing -> {
            if (existing.getName().equals(watermarkName) && existing.getId() != watermarkId) {
                throw new ConflictException("Watermark name must be unique within the same dossier template");
            }
        });
    }


    public List<WatermarkEntity> getWatermarksForDossierTemplateId(String dossierTemplateId) {

        return watermarkRepository.findByDossierTemplateId(dossierTemplateId);
    }


    public boolean isWatermarkUsed(long watermarkId) {

        watermarkRepository.findById(watermarkId); //check if watermark exists
        int count = dossierRepository.countDossiersWithWatermarkInUse(watermarkId);
        return count != 0;
    }

}
