package com.developx.szpitale.ingest.normalize;

import org.apache.commons.text.similarity.JaroWinklerSimilarity;

import java.text.Normalizer;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class NameNormalizer {

    private static final Set<String> TITLE_TOKENS = Set.of(
            "prof.", "prof", "dr hab.", "dr.hab.", "dr.", "mgr", "mgr in\u017c.", "in\u017c.",
            "licencjat in\u017c.", "lek.", "lek.med.", "n. med.", "n. o zdr."
    );

    private final JaroWinklerSimilarity jaroWinkler = new JaroWinklerSimilarity();

    public String makeSlug(String fullName) {
        String normalized = Normalizer.normalize(fullName, Normalizer.Form.NFKD);
        normalized = normalized.replaceAll("\\p{M}", "");
        normalized = normalized.replaceAll("[^\\p{L}\\s-]", "");
        normalized = transliteratePolish(normalized.toLowerCase());
        normalized = normalized.replaceAll("\\s+", "-").replaceAll("-+", "-");
        normalized = normalized.replaceAll("^-|-$", "");
        return normalized;
    }

    private String transliteratePolish(String input) {
        Map<String, String> map = new HashMap<>();
        map.put("ł", "l");  map.put("Ł", "l");
        map.put("ę", "e");  map.put("Ĕ", "e");
        map.put("ó", "o");  map.put("Ō", "o");
        map.put("ą", "a");  map.put("Ą", "a");
        map.put("ś", "s");  map.put("Ś", "s");
        map.put("ź", "z");  map.put("Ź", "z");
        map.put("ż", "z");  map.put("Ż", "z");
        map.put("ć", "c");  map.put("Ć", "c");
        map.put("ń", "n");  map.put("Ń", "n");
        String result = input;
        for (Map.Entry<String, String> entry : map.entrySet()) {
            result = result.replace(entry.getKey(), entry.getValue());
        }
        return result;
    }

    public String extractFullName(String rawName) {
        return extractGivenAndFamilyNames(rawName);
    }

    public List<String> extractTitles(String rawName) {
        List<String> titles = new ArrayList<>();
        String lower = rawName.toLowerCase();
        for (String title : TITLE_TOKENS) {
            if (lower.contains(title.toLowerCase())) {
                titles.add(title.trim());
            }
        }
        return titles;
    }

    public String makePersonId(String fullName) {
        String slug = makeSlug(fullName);
        return "person:" + slug;
    }

    public String makeHospitalId(String voivodeship, String hospitalName) {
        String slug = makeSlug(hospitalName);
        return "hosp:" + voivodeship + ":" + slug;
    }

    public double fuzzySimilarity(String a, String b) {
        return jaroWinkler.apply(a.toLowerCase(), b.toLowerCase());
    }

    public List<String> findDuplicateCandidates(List<String> names, String targetName, double threshold) {
        return names.stream()
                .filter(name -> fuzzySimilarity(name, targetName) >= threshold)
                .filter(name -> !name.equals(targetName))
                .collect(Collectors.toList());
    }

    static final List<String> TITLE_PREFIXES = List.of(
            "prof. dr hab.", "prof.dr hab.", "prof. dr.", "prof. dr",
            "dr hab.", "dr.hab.", "dr. hab.", "dr.hab",
            "mgr inż.", "mgr inż", "mgr.inż.", "mgr.inż",
            "prof.", "prof", "dr.", "dr",
            "mgr.", "mgr", "inż.", "inż",
            "lek.", "lek.med.", "n. med.", "n. o zdr.",
            "licencjat inż.", "licencjat inż"
    );

    private String extractGivenAndFamilyNames(String rawName) {
        String name = rawName.trim();
        String lower = name.toLowerCase();
        for (String prefix : TITLE_PREFIXES) {
            if (lower.startsWith(prefix.toLowerCase())) {
                name = name.substring(prefix.length()).trim();
                lower = name.toLowerCase();
            }
        }
        return name;
    }
}
