package de.avatic.taric.service;

import de.avatic.taric.model.Nomenclature;
import de.avatic.taric.repository.NomenclatureRepository;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class NomenclatureService {

    private final NomenclatureRepository nomenclatureRepository;

    public NomenclatureService(NomenclatureRepository nomenclatureRepository) {
        this.nomenclatureRepository = nomenclatureRepository;
    }


    public Optional<Nomenclature> getNomenclature(String hscode) {
        return nomenclatureRepository.findByHscode(normalize(hscode.replaceAll("[^0-9]", "")));
    }

    public boolean isDeclarable(String hscode) {
        var nomenclature = getNomenclature(hscode);
        if (nomenclature.isEmpty()) return false;
        return nomenclature.get().getIsLeaf();
    }

    public List<Nomenclature> getDeclarableChildren(String hscode) {
        var normalized = normalize(hscode.replaceAll("[^0-9]", ""));
        var level = getHierarchyLevel(normalized);
        return nomenclatureRepository.findDeclarableChildren(normalized.substring(0, level));
    }

    public List<Nomenclature> getNomenclatureCascade(String hscode) {
        if (hscode == null) return Collections.emptyList();
        List<String> cascade = getCascade(normalize(hscode.replaceAll("[^0-9]", "")));

        return cascade.stream().map(nomenclatureRepository::findByHscode).flatMap(Optional::stream).toList();
    }

    private List<String> getCascade(String hscode) {
        var set = new HashSet<String>();
        var parents = new ArrayList<String>();
        var hierarchyLevel = getHierarchyLevel(hscode);

        while (hierarchyLevel > 0) {
            var parent = getParent(hscode, hierarchyLevel);

            if (!set.contains(parent)) {
                set.add(parent);
                parents.add(parent);
            }

            hierarchyLevel -= 2;
        }

        return parents;
    }

    private String getParent(String hscode, int level) {
        return normalize(hscode.substring(0, level));
    }

    private int getHierarchyLevel(String hscode) {
        int idx = hscode.length();

        while (idx > 0) {
            idx--;
            if (hscode.charAt(idx) != '0') {
                break;
            }
        }

        return (idx + 1) % 2 == 0 ? idx + 1 : idx + 2;
    }

    private String normalize(String hscode) {

        StringBuilder normalizedHsCode = new StringBuilder(hscode);

        while (normalizedHsCode.length() < 10) {
            normalizedHsCode.append("0");
        }

        if (normalizedHsCode.length() > 10) {
            normalizedHsCode = new StringBuilder(normalizedHsCode.substring(0, 10));
        }

        return normalizedHsCode.toString();
    }

}
