package com.developx.szpitale.ingest.normalize;

import com.developx.szpitale.model.Person;
import org.apache.commons.text.similarity.JaroWinklerSimilarity;

import java.util.*;
import java.util.stream.Collectors;

public class Deduplicator {

    private static final double DUPLICATE_THRESHOLD = 0.85;
    private static final double SUSPECT_THRESHOLD = 0.70;

    private final NameNormalizer nameNormalizer = new NameNormalizer();

    public List<Person> deduplicate(List<Person> people) {
        List<String> personIds = new ArrayList<>();
        Map<String, List<Person>> bySlug = people.stream()
                .collect(Collectors.groupingBy(Person::id));

        List<Person> result = new ArrayList<>();
        Set<String> processed = new HashSet<>();

        for (Map.Entry<String, List<Person>> entry : bySlug.entrySet()) {
            List<Person> group = entry.getValue();
            if (group.size() == 1) {
                result.add(group.get(0));
            } else {
                // Same slug - merge source URLs
                Person merged = mergeBySlug(group);
                result.add(merged);
            }
        }

        // Check cross-slug candidates with fuzzy matching
        checkFuzzyDuplicates(result);

        return result;
    }

    private Person mergeBySlug(List<Person> duplicates) {
        Person first = duplicates.get(0);
        Set<String> allUrls = duplicates.stream()
                .flatMap(p -> p.sourceUrls().stream())
                .collect(Collectors.toSet());

        return new Person(
                first.id(),
                first.fullName(),
                first.displayName(),
                first.titles(),
                new ArrayList<>(allUrls)
        );
    }

    private void checkFuzzyDuplicates(List<Person> people) {
        Map<String, List<String>> groups = new HashMap<>();
        for (int i = 0; i < people.size(); i++) {
            Person person = people.get(i);
            List<String> candidates = new ArrayList<>();
            for (int j = 0; j < i; j++) {
                Person existing = people.get(j);
                double similarity = nameNormalizer.fuzzySimilarity(
                        person.fullName(),
                        existing.fullName()
                );
                if (similarity >= SUSPECT_THRESHOLD && similarity < DUPLICATE_THRESHOLD) {
                    candidates.add(existing.id());
                }
            }
            if (!candidates.isEmpty()) {
                groups.put(person.id(), candidates);
            }
        }

        if (!groups.isEmpty()) {
            System.out.println("Warning: Possible name similarity conflicts (manual review recommended):");
            groups.forEach((id, candidates) ->
                    System.out.println("  " + id + " -> similar to: " + String.join(", ", candidates)));
        }
    }
}
