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

import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.LegalBasisEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogLegalBasis;

import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class LegalBasisMappingService {

    private final HashFunction hashFunction;
    private final LegalBasisMappingPersistenceService legalBasisMappingPersistenceService;


    public LegalBasisMappingService(LegalBasisMappingPersistenceService legalBasisMappingPersistenceService) {

        this.hashFunction = Hashing.murmur3_128();
        this.legalBasisMappingPersistenceService = legalBasisMappingPersistenceService;
    }


    public TechnicalNameResult processLegalBasisAndEntityLogLegalBasisList(String currentLegalBasis,
                                                                           Map<String, String> reasonToTechnicalNameMap,
                                                                           List<EntityLogLegalBasis> legalBasisList) {

        TechnicalNameResult result = computeTechnicalName(currentLegalBasis, reasonToTechnicalNameMap);

        if (result == null) {
            return null;
        }

        addToLegalBasisList(result.technicalName(), currentLegalBasis, legalBasisList);

        return result;
    }


    public TechnicalNameResult processLegalBasis(String currentLegalBasis, Map<String, String> reasonToTechnicalNameMap) {

        return computeTechnicalName(currentLegalBasis, reasonToTechnicalNameMap);
    }


    private TechnicalNameResult computeTechnicalName(String currentLegalBasis, Map<String, String> reasonToTechnicalNameMap) {

        if (currentLegalBasis == null || currentLegalBasis.isEmpty()) {
            return null;
        }

        if (reasonToTechnicalNameMap.containsValue(currentLegalBasis)) {
            return new TechnicalNameResult(currentLegalBasis, false);
        }

        if (reasonToTechnicalNameMap.containsKey(currentLegalBasis)) {
            String technicalName = reasonToTechnicalNameMap.get(currentLegalBasis);
            return new TechnicalNameResult(technicalName, false);
        }

        String technicalName = hashFunction.hashString(currentLegalBasis, StandardCharsets.UTF_8).toString();

        return new TechnicalNameResult(technicalName, true);
    }


    public String processTextAndEntityLogLegalBasisList(String text, Map<String, String> reasonToTechnicalNameMap, List<EntityLogLegalBasis> legalBasisList) {

        if (text == null || text.isEmpty()) {
            return text;
        }

        String updatedValue = text;
        boolean updated = false;

        for (Map.Entry<String, String> entry : reasonToTechnicalNameMap.entrySet()) {
            String reason = entry.getKey();
            String technicalName = entry.getValue();

            if (updatedValue.contains(reason)) {
                updatedValue = updatedValue.replace(reason, technicalName);
                addToLegalBasisList(technicalName, reason, legalBasisList);
                updated = true;
            }
        }

        if (!updated) {
            String technicalName = hashFunction.hashString(text, StandardCharsets.UTF_8).toString();
            updatedValue = technicalName;
            addToLegalBasisList(technicalName, text, legalBasisList);
        }

        return updatedValue;
    }


    private void addToLegalBasisList(String technicalName, String reason, List<EntityLogLegalBasis> legalBasisList) {

        boolean exists = legalBasisList.stream()
                .anyMatch(lb -> lb.getTechnicalName().equals(technicalName));

        if (!exists) {
            EntityLogLegalBasis newLegalBasis = createEntityLogLegalBasis(technicalName, reason);
            legalBasisList.add(newLegalBasis);
        }
    }


    private EntityLogLegalBasis createEntityLogLegalBasis(String technicalName, String reason) {

        EntityLogLegalBasis newLegalBasis = new EntityLogLegalBasis();
        newLegalBasis.setTechnicalName(technicalName);
        newLegalBasis.setReason(reason);
        newLegalBasis.setName("Generated Legal Basis");
        newLegalBasis.setDescription("");
        return newLegalBasis;
    }


    public Map<String, String> getReasonToTechnicalNameMap(String dossierTemplateId) {

        List<LegalBasisEntity> legalBasisMappings = legalBasisMappingPersistenceService.getLegalBasisMapping(dossierTemplateId);

        if (legalBasisMappings == null) {
            legalBasisMappings = new ArrayList<>();
        }

        Map<String, String> reasonToTechnicalNameMap = new HashMap<>();
        for (LegalBasisEntity lbEntity : legalBasisMappings) {
            reasonToTechnicalNameMap.put(lbEntity.getReason(), lbEntity.getTechnicalName());
        }
        return reasonToTechnicalNameMap;

    }


    public record TechnicalNameResult(String technicalName, boolean hashed) {

    }

}
