package de.effigenix.infrastructure.shared;

import de.effigenix.shared.common.Country;
import de.effigenix.shared.common.CountryRepository;

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

public class InMemoryCountryRepository implements CountryRepository {

    private static final Set<String> DACH_CODES = Set.of("DE", "AT", "CH");

    private final Map<String, Country> byCode;
    private final List<Country> allSorted;

    public InMemoryCountryRepository() {
        var countries = List.of(
            new Country("AF", "Afghanistan"),
            new Country("EG", "Ägypten"),
            new Country("AX", "Åland-Inseln"),
            new Country("AL", "Albanien"),
            new Country("DZ", "Algerien"),
            new Country("AS", "Amerikanisch-Samoa"),
            new Country("VI", "Amerikanische Jungferninseln"),
            new Country("AD", "Andorra"),
            new Country("AO", "Angola"),
            new Country("AI", "Anguilla"),
            new Country("AQ", "Antarktis"),
            new Country("AG", "Antigua und Barbuda"),
            new Country("GQ", "Äquatorialguinea"),
            new Country("AR", "Argentinien"),
            new Country("AM", "Armenien"),
            new Country("AW", "Aruba"),
            new Country("AZ", "Aserbaidschan"),
            new Country("ET", "Äthiopien"),
            new Country("AU", "Australien"),
            new Country("BS", "Bahamas"),
            new Country("BH", "Bahrain"),
            new Country("BD", "Bangladesch"),
            new Country("BB", "Barbados"),
            new Country("BY", "Belarus"),
            new Country("BE", "Belgien"),
            new Country("BZ", "Belize"),
            new Country("BJ", "Benin"),
            new Country("BM", "Bermuda"),
            new Country("BT", "Bhutan"),
            new Country("BO", "Bolivien"),
            new Country("BQ", "Bonaire, Sint Eustatius und Saba"),
            new Country("BA", "Bosnien und Herzegowina"),
            new Country("BW", "Botsuana"),
            new Country("BV", "Bouvetinsel"),
            new Country("BR", "Brasilien"),
            new Country("VG", "Britische Jungferninseln"),
            new Country("IO", "Britisches Territorium im Indischen Ozean"),
            new Country("BN", "Brunei Darussalam"),
            new Country("BG", "Bulgarien"),
            new Country("BF", "Burkina Faso"),
            new Country("BI", "Burundi"),
            new Country("CV", "Cabo Verde"),
            new Country("CL", "Chile"),
            new Country("CN", "China"),
            new Country("CK", "Cookinseln"),
            new Country("CR", "Costa Rica"),
            new Country("CI", "Côte d'Ivoire"),
            new Country("CW", "Curaçao"),
            new Country("DK", "Dänemark"),
            new Country("DE", "Deutschland"),
            new Country("DM", "Dominica"),
            new Country("DO", "Dominikanische Republik"),
            new Country("DJ", "Dschibuti"),
            new Country("EC", "Ecuador"),
            new Country("SV", "El Salvador"),
            new Country("ER", "Eritrea"),
            new Country("EE", "Estland"),
            new Country("SZ", "Eswatini"),
            new Country("FK", "Falklandinseln"),
            new Country("FO", "Färöer"),
            new Country("FJ", "Fidschi"),
            new Country("FI", "Finnland"),
            new Country("FR", "Frankreich"),
            new Country("GF", "Französisch-Guayana"),
            new Country("PF", "Französisch-Polynesien"),
            new Country("TF", "Französische Süd- und Antarktisgebiete"),
            new Country("GA", "Gabun"),
            new Country("GM", "Gambia"),
            new Country("GE", "Georgien"),
            new Country("GH", "Ghana"),
            new Country("GI", "Gibraltar"),
            new Country("GD", "Grenada"),
            new Country("GR", "Griechenland"),
            new Country("GL", "Grönland"),
            new Country("GP", "Guadeloupe"),
            new Country("GU", "Guam"),
            new Country("GT", "Guatemala"),
            new Country("GG", "Guernsey"),
            new Country("GN", "Guinea"),
            new Country("GW", "Guinea-Bissau"),
            new Country("GY", "Guyana"),
            new Country("HT", "Haiti"),
            new Country("HM", "Heard und McDonaldinseln"),
            new Country("HN", "Honduras"),
            new Country("HK", "Hongkong"),
            new Country("IN", "Indien"),
            new Country("ID", "Indonesien"),
            new Country("IQ", "Irak"),
            new Country("IR", "Iran"),
            new Country("IE", "Irland"),
            new Country("IS", "Island"),
            new Country("IM", "Isle of Man"),
            new Country("IL", "Israel"),
            new Country("IT", "Italien"),
            new Country("JM", "Jamaika"),
            new Country("JP", "Japan"),
            new Country("YE", "Jemen"),
            new Country("JE", "Jersey"),
            new Country("JO", "Jordanien"),
            new Country("KY", "Kaimaninseln"),
            new Country("KH", "Kambodscha"),
            new Country("CM", "Kamerun"),
            new Country("CA", "Kanada"),
            new Country("KZ", "Kasachstan"),
            new Country("QA", "Katar"),
            new Country("KE", "Kenia"),
            new Country("KG", "Kirgisistan"),
            new Country("KI", "Kiribati"),
            new Country("CC", "Kokosinseln"),
            new Country("CO", "Kolumbien"),
            new Country("KM", "Komoren"),
            new Country("CD", "Kongo, Demokratische Republik"),
            new Country("CG", "Kongo, Republik"),
            new Country("KP", "Korea, Demokratische Volksrepublik"),
            new Country("KR", "Korea, Republik"),
            new Country("HR", "Kroatien"),
            new Country("CU", "Kuba"),
            new Country("KW", "Kuwait"),
            new Country("LA", "Laos"),
            new Country("LS", "Lesotho"),
            new Country("LV", "Lettland"),
            new Country("LB", "Libanon"),
            new Country("LR", "Liberia"),
            new Country("LY", "Libyen"),
            new Country("LI", "Liechtenstein"),
            new Country("LT", "Litauen"),
            new Country("LU", "Luxemburg"),
            new Country("MO", "Macao"),
            new Country("MG", "Madagaskar"),
            new Country("MW", "Malawi"),
            new Country("MY", "Malaysia"),
            new Country("MV", "Malediven"),
            new Country("ML", "Mali"),
            new Country("MT", "Malta"),
            new Country("MA", "Marokko"),
            new Country("MH", "Marshallinseln"),
            new Country("MQ", "Martinique"),
            new Country("MR", "Mauretanien"),
            new Country("MU", "Mauritius"),
            new Country("YT", "Mayotte"),
            new Country("MX", "Mexiko"),
            new Country("FM", "Mikronesien"),
            new Country("MD", "Moldau"),
            new Country("MC", "Monaco"),
            new Country("MN", "Mongolei"),
            new Country("ME", "Montenegro"),
            new Country("MS", "Montserrat"),
            new Country("MZ", "Mosambik"),
            new Country("MM", "Myanmar"),
            new Country("NA", "Namibia"),
            new Country("NR", "Nauru"),
            new Country("NP", "Nepal"),
            new Country("NC", "Neukaledonien"),
            new Country("NZ", "Neuseeland"),
            new Country("NI", "Nicaragua"),
            new Country("NL", "Niederlande"),
            new Country("NE", "Niger"),
            new Country("NG", "Nigeria"),
            new Country("NU", "Niue"),
            new Country("MK", "Nordmazedonien"),
            new Country("MP", "Nördliche Marianen"),
            new Country("NF", "Norfolkinsel"),
            new Country("NO", "Norwegen"),
            new Country("OM", "Oman"),
            new Country("AT", "Österreich"),
            new Country("TL", "Osttimor"),
            new Country("PK", "Pakistan"),
            new Country("PW", "Palau"),
            new Country("PS", "Palästina"),
            new Country("PA", "Panama"),
            new Country("PG", "Papua-Neuguinea"),
            new Country("PY", "Paraguay"),
            new Country("PE", "Peru"),
            new Country("PH", "Philippinen"),
            new Country("PN", "Pitcairninseln"),
            new Country("PL", "Polen"),
            new Country("PT", "Portugal"),
            new Country("PR", "Puerto Rico"),
            new Country("RE", "Réunion"),
            new Country("RW", "Ruanda"),
            new Country("RO", "Rumänien"),
            new Country("RU", "Russland"),
            new Country("SB", "Salomonen"),
            new Country("ZM", "Sambia"),
            new Country("WS", "Samoa"),
            new Country("SM", "San Marino"),
            new Country("ST", "São Tomé und Príncipe"),
            new Country("SA", "Saudi-Arabien"),
            new Country("SE", "Schweden"),
            new Country("CH", "Schweiz"),
            new Country("SN", "Senegal"),
            new Country("RS", "Serbien"),
            new Country("SC", "Seychellen"),
            new Country("SL", "Sierra Leone"),
            new Country("ZW", "Simbabwe"),
            new Country("SG", "Singapur"),
            new Country("SX", "Sint Maarten"),
            new Country("SK", "Slowakei"),
            new Country("SI", "Slowenien"),
            new Country("SO", "Somalia"),
            new Country("ES", "Spanien"),
            new Country("LK", "Sri Lanka"),
            new Country("BL", "St. Barthélemy"),
            new Country("SH", "St. Helena"),
            new Country("KN", "St. Kitts und Nevis"),
            new Country("LC", "St. Lucia"),
            new Country("MF", "St. Martin"),
            new Country("PM", "St. Pierre und Miquelon"),
            new Country("VC", "St. Vincent und die Grenadinen"),
            new Country("ZA", "Südafrika"),
            new Country("SD", "Sudan"),
            new Country("GS", "Südgeorgien und die Südlichen Sandwichinseln"),
            new Country("SS", "Südsudan"),
            new Country("SR", "Suriname"),
            new Country("SJ", "Svalbard und Jan Mayen"),
            new Country("SY", "Syrien"),
            new Country("TJ", "Tadschikistan"),
            new Country("TW", "Taiwan"),
            new Country("TZ", "Tansania"),
            new Country("TH", "Thailand"),
            new Country("TG", "Togo"),
            new Country("TK", "Tokelau"),
            new Country("TO", "Tonga"),
            new Country("TT", "Trinidad und Tobago"),
            new Country("TD", "Tschad"),
            new Country("CZ", "Tschechien"),
            new Country("TN", "Tunesien"),
            new Country("TR", "Türkei"),
            new Country("TM", "Turkmenistan"),
            new Country("TC", "Turks- und Caicosinseln"),
            new Country("TV", "Tuvalu"),
            new Country("UG", "Uganda"),
            new Country("UA", "Ukraine"),
            new Country("HU", "Ungarn"),
            new Country("UM", "United States Minor Outlying Islands"),
            new Country("UY", "Uruguay"),
            new Country("UZ", "Usbekistan"),
            new Country("VU", "Vanuatu"),
            new Country("VA", "Vatikanstadt"),
            new Country("VE", "Venezuela"),
            new Country("AE", "Vereinigte Arabische Emirate"),
            new Country("US", "Vereinigte Staaten"),
            new Country("GB", "Vereinigtes Königreich"),
            new Country("VN", "Vietnam"),
            new Country("WF", "Wallis und Futuna"),
            new Country("CX", "Weihnachtsinsel"),
            new Country("EH", "Westsahara"),
            new Country("CF", "Zentralafrikanische Republik"),
            new Country("CY", "Zypern")
        );

        this.byCode = countries.stream().collect(Collectors.toMap(Country::code, c -> c));

        // Sort: DACH first (DE, AT, CH), then rest alphabetically by name
        var dach = countries.stream()
                .filter(c -> DACH_CODES.contains(c.code()))
                .sorted(Comparator.comparing(c -> List.of("DE", "AT", "CH").indexOf(c.code())))
                .toList();
        var rest = countries.stream()
                .filter(c -> !DACH_CODES.contains(c.code()))
                .sorted(Comparator.comparing(Country::name))
                .toList();
        this.allSorted = Stream.concat(dach.stream(), rest.stream()).toList();
    }

    @Override
    public List<Country> findAll() {
        return allSorted;
    }

    @Override
    public List<Country> search(String query) {
        if (query == null || query.isBlank()) {
            return findAll();
        }
        var q = query.toLowerCase();
        var matches = allSorted.stream()
                .filter(c -> c.name().toLowerCase().contains(q) || c.code().toLowerCase().contains(q))
                .toList();
        // DACH countries first in results too
        var dach = matches.stream().filter(c -> DACH_CODES.contains(c.code())).toList();
        var rest = matches.stream().filter(c -> !DACH_CODES.contains(c.code())).toList();
        return Stream.concat(dach.stream(), rest.stream()).toList();
    }

    @Override
    public Optional<Country> findByCode(String code) {
        return Optional.ofNullable(byCode.get(code));
    }
}
