package com.clanstop.healing.locator;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * Produces a short, human-readable description of what changed between the element we
 * remembered (stored fingerprint) and the element we healed to. This is the "what changed
 * when it found a fix" detail, saved to {@code heal_event.changes} and logged.
 */
public final class FingerprintDiff {

    private FingerprintDiff() {}

    public static String describe(Fingerprint stored, Fingerprint healed) {
        if (stored == null || healed == null) {
            return "(no fingerprint available to diff)";
        }
        List<String> parts = new ArrayList<>();

        if (!stored.tag().equalsIgnoreCase(healed.tag())) {
            parts.add("tag " + q(stored.tag()) + "→" + q(healed.tag()));
        }
        diffField(parts, "id", stored.id(), healed.id());
        diffField(parts, "name", stored.name(), healed.name());

        // Class list add/remove.
        Set<String> added = new LinkedHashSet<>(healed.classList());
        added.removeAll(stored.classList());
        Set<String> removed = new LinkedHashSet<>(stored.classList());
        removed.removeAll(healed.classList());
        if (!added.isEmpty() || !removed.isEmpty()) {
            StringBuilder sb = new StringBuilder("class");
            if (!added.isEmpty())   sb.append(" +").append(added);
            if (!removed.isEmpty()) sb.append(" -").append(removed);
            parts.add(sb.toString());
        }

        // Visible text.
        if (!stored.visibleText().equals(healed.visibleText())) {
            double sim = SimilarityScorer.levenshteinRatio(stored.visibleText(), healed.visibleText());
            if (sim > 0.85) {
                parts.add("text ~similar");
            } else {
                parts.add("text " + q(clip(stored.visibleText())) + "→" + q(clip(healed.visibleText())));
            }
        }

        // Tracked attributes.
        for (String key : Fingerprint.TRACKED_ATTRS) {
            diffField(parts, key, stored.attrs().get(key), healed.attrs().get(key));
        }

        // Position shift (only if meaningful).
        double dx = healed.centerX() - stored.centerX();
        double dy = healed.centerY() - stored.centerY();
        if (Math.hypot(dx, dy) > 20) {
            parts.add(String.format("moved ~(%+.0f,%+.0f)px", dx, dy));
        }

        return parts.isEmpty()
                ? "identical fingerprint (locator broke but element unchanged)"
                : String.join("; ", parts);
    }

    private static void diffField(List<String> parts, String label, String a, String b) {
        a = a == null ? "" : a;
        b = b == null ? "" : b;
        if (!a.equals(b) && !(a.isEmpty() && b.isEmpty())) {
            parts.add(label + " " + q(a) + "→" + q(b));
        }
    }

    private static String q(String s) {
        return "'" + (s == null ? "" : s) + "'";
    }

    private static String clip(String s) {
        if (s == null) return "";
        return s.length() > 40 ? s.substring(0, 40) + "…" : s;
    }
}
