package org.adrianvictor.lib.versioning;

import org.bukkit.Bukkit;

import java.util.Comparator;
import java.util.List;
import java.util.ArrayList;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class VersionMatcher {

    public VersionMatcher() {}

    private record Entry(String pattern, String classSuffix, int minMajor, int minMinor, int maxMajor, int maxMinor) {}

    public String getClassSuffix(String serverVersion) {
        if (serverVersion == null) {
            return null;
        }

        List<Entry> entries = populateEntries();
        List<Entry> applicableEntries = new ArrayList<>();

        int[] parsedServerVersion = parseVersion(serverVersion);
        int serverMajor = parsedServerVersion[0];
        int serverMinor = parsedServerVersion[1];

        for (Entry entry : entries) {
            Pattern p = Pattern.compile(entry.pattern());
            if (p.matcher(serverVersion).matches()) {
                if (serverMajor >= entry.minMajor() && serverMinor >= entry.minMinor() &&
                    serverMajor <= entry.maxMajor() && serverMinor <= entry.maxMinor()) {
                    applicableEntries.add(entry);
                }
            }
        }

        applicableEntries.sort(Comparator
                .comparing(Entry::maxMajor).reversed()
                .thenComparing(Entry::maxMinor).reversed()
                .thenComparing(Entry::minMajor).reversed()
                .thenComparing(Entry::minMinor).reversed());

        Optional<Entry> bestMatch = applicableEntries.stream().findFirst();

        return bestMatch.map(Entry::classSuffix).orElse(null);
    }

    public String getServerVersion() {
        String rawVersion = null;
        try {
            rawVersion = Bukkit.getMinecraftVersion();
        } catch (NoSuchMethodError ignored) {}

        if (rawVersion == null || rawVersion.isEmpty()) {
            String v = Bukkit.getVersion();
            int start = v.lastIndexOf("MC: ");
            if (start != -1) {
                rawVersion = v.substring(start + 4, v.length() - 1);
            } else {
                rawVersion = "unknown";
            }
        }

        return rawVersion;
    }

    private List<Entry> populateEntries() {
        return List.of(
            new Entry("^1\\.7\\.3$", "b1_7_3", 1, 7, 1, 7),
            // r1_1 covers versions from 1.1.x up to 1.16.4
            new Entry("^1\\.(1[0-5]|[1-9])(\\.\\d+)*$", "r1_1", 1, 1, 1, 16),
            // r1_16_5 covers versions from 1.16.5 up to 1.20.x
            new Entry("^1\\.(16\\.[5-9]|1[7-9]|20)(\\.\\d+)*$", "r1_16_5", 1, 16, 1, 20),
            // r1_21 covers 1.21.x and above
            new Entry("^1\\.21(\\.\\d+)*$", "r1_21", 1, 21, Integer.MAX_VALUE, Integer.MAX_VALUE)
        );
    }

    private int[] parseVersion(String versionString) {
        Matcher matcher = Pattern.compile("^(\\d+)\\.(\\d+).*").matcher(versionString);
        if (matcher.find()) {
            return new int[]{Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2))};
        }
        return new int[]{0, 0}; // Default for unknown format
    }
}