# TODO: Fix this import statement, it should be from data_toolkit.validation import validate_mmsi.
#  Using poetry to manage dependencies and packaging with pyproject.toml may be a good idea.
from aau_ais_utilities.validate import MMSIValidator


# TODO: Do some additional research on the MMSI MID codes and determine if there are any missing codes.
"""
The following dictionary is created from a list of MMSI MID codes collected on the 10/04/2024.
This dictionary is mainly kept as a reference for the MMSI to country conversion.
Source: https://www.vtexplorer.com/mmsi-mid-codes-en/
"""
mid_to_country = {
    "201": "Albania (Republic of)",
    "202": "Andorra (Principality of)",
    "203": "Austria",
    "204": "Azores",
    "205": "Belgium",
    "206": "Belarus (Republic of)",
    "207": "Bulgaria (Republic of)",
    "208": "Vatican City State",
    "209": "Cyprus (Republic of)",
    "210": "Cyprus (Republic of)",
    "211": "Germany (Federal Republic of)",
    "212": "Cyprus (Republic of)",
    "213": "Georgia",
    "214": "Moldova (Republic of)",
    "215": "Malta",
    "216": "Armenia (Republic of)",
    "218": "Germany (Federal Republic of)",
    "219": "Denmark",
    "220": "Denmark",
    "224": "Spain",
    "225": "Spain",
    "226": "France",
    "227": "France",
    "228": "France",
    "230": "Finland",
    "231": "Faroe Islands",
    "232": "United Kingdom of Great Britain and Northern Ireland",
    "233": "United Kingdom of Great Britain and Northern Ireland",
    "234": "United Kingdom of Great Britain and Northern Ireland",
    "235": "United Kingdom of Great Britain and Northern Ireland",
    "236": "Gibraltar",
    "237": "Greece",
    "238": "Croatia (Republic of)",
    "239": "Greece",
    "240": "Greece",
    "241": "Greece",
    "242": "Morocco (Kingdom of)",
    "243": "Hungary (Republic of)",
    "244": "Netherlands (Kingdom of the)",
    "245": "Netherlands (Kingdom of the)",
    "246": "Netherlands (Kingdom of the)",
    "247": "Italy",
    "248": "Malta",
    "249": "Malta",
    "250": "Ireland",
    "251": "Iceland",
    "252": "Liechtenstein (Principality of)",
    "253": "Luxembourg",
    "254": "Monaco (Principality of)",
    "255": "Madeira",
    "256": "Malta",
    "257": "Norway",
    "258": "Norway",
    "259": "Norway",
    "261": "Poland (Republic of)",
    "262": "Montenegro",
    "263": "Portugal",
    "264": "Romania",
    "265": "Sweden",
    "266": "Sweden",
    "267": "Slovak Republic",
    "268": "San Marino (Republic of)",
    "269": "Switzerland (Confederation of)",
    "270": "Czech Republic",
    "271": "Turkey",
    "272": "Ukraine",
    "273": "Russian Federation",
    "274": "The Former Yugoslav Republic of Macedonia",
    "275": "Latvia (Republic of)",
    "276": "Estonia (Republic of)",
    "277": "Lithuania (Republic of)",
    "278": "Slovenia (Republic of)",
    "279": "Serbia (Republic of)",
    "301": "Anguilla",
    "303": "United States of America",
    "304": "Antigua and Barbuda",
    "305": "Antigua and Barbuda",
    "306": "Netherlands Antilles",
    "307": "Aruba",
    "308": "Bahamas (Commonwealth of the)",
    "309": "Bahamas (Commonwealth of the)",
    "310": "Bermuda",
    "311": "Bahamas (Commonwealth of the)",
    "312": "Belize",
    "314": "Barbados",
    "316": "Canada",
    "319": "Cayman Islands",
    "321": "Costa Rica",
    "323": "Cuba",
    "325": "Dominica (Commonwealth of)",
    "327": "Dominican Republic",
    "329": "Guadeloupe (French Department of)",
    "330": "Grenada",
    "331": "Greenland",
    "332": "Guatemala",
    "334": "Honduras (Republic of)",
    "336": "Haiti (Republic of)",
    "338": "United States of America",
    "339": "Jamaica",
    "341": "Saint Kitts and Nevis",
    "343": "Saint Lucia",
    "345": "Mexico",
    "347": "Martinique (French Department of)",
    "348": "Montserrat",
    "350": "Nicaragua",
    "351": "Panama (Republic of)",
    "352": "Panama (Republic of)",
    "353": "Panama (Republic of)",
    "354": "Panama (Republic of)",
    "355": "Panama (Republic of)",
    "356": "Panama (Republic of)",
    "357": "Panama (Republic of)",
    "358": "Puerto Rico",
    "359": "El Salvador",
    "361": "Saint Pierre and Miquelon (Territorial Collectivity of)",
    "362": "Trinidad and Tobago",
    "364": "Turks and Caicos Islands",
    "366": "United States of America",
    "367": "United States of America",
    "368": "United States of America",
    "369": "United States of America",
    "370": "Panama (Republic of)",
    "371": "Panama (Republic of)",
    "372": "Panama (Republic of)",
    "375": "Saint Vincent and the Grenadines",
    "376": "Saint Vincent and the Grenadines",
    "377": "Saint Vincent and the Grenadines",
    "378": "British Virgin Islands",
    "379": "United States Virgin Islands",
    "401": "Afghanistan",
    "403": "Saudi Arabia (Kingdom of)",
    "405": "Bangladesh (People's Republic of)",
    "408": "Bahrain (Kingdom of)",
    "410": "Bhutan (Kingdom of)",
    "412": "China (People's Republic of)",
    "413": "China (People's Republic of)",
    "416": "Taiwan (Province of China)",
    "417": "Sri Lanka (Democratic Socialist Republic of)",
    "419": "India (Republic of)",
    "422": "Iran (Islamic Republic of)",
    "423": "Azerbaijan (Republic of)",
    "425": "Iraq (Republic of)",
    "428": "Israel (State of)",
    "431": "Japan",
    "432": "Japan",
    "434": "Turkmenistan",
    "436": "Kazakhstan (Republic of)",
    "437": "Uzbekistan (Republic of)",
    "438": "Jordan (Hashemite Kingdom of)",
    "440": "Korea (Republic of)",
    "441": "Korea (Republic of)",
    "443": "Palestine (In accordance with Resolution 99 Rev. Antalya, 2006)",
    "445": "Democratic People's Republic of Korea",
    "447": "Kuwait (State of)",
    "450": "Lebanon",
    "451": "Kyrgyz Republic",
    "453": "Macao (Special Administrative Region of China)",
    "455": "Maldives (Republic of)",
    "457": "Mongolia",
    "459": "Nepal (Federal Democratic Republic of)",
    "461": "Oman (Sultanate of)",
    "463": "Pakistan (Islamic Republic of)",
    "466": "Qatar (State of)",
    "468": "Syrian Arab Republic",
    "470": "United Arab Emirates",
    "473": "Yemen (Republic of)",
    "475": "Yemen (Republic of)",
    "477": "Hong Kong (Special Administrative Region of China)",
    "478": "Bosnia and Herzegovina",
    "501": "Adélie Land",
    "503": "Australia",
    "506": "Myanmar (Union of)",
    "508": "Brunei Darussalam",
    "510": "Micronesia (Federated States of)",
    "511": "Palau (Republic of)",
    "512": "New Zealand",
    "514": "Cambodia (Kingdom of)",
    "515": "Cambodia (Kingdom of)",
    "516": "Christmas Island (Indian Ocean)",
    "518": "Cook Islands",
    "520": "Fiji (Republic of)",
    "523": "Cocos (Keeling) Islands",
    "525": "Indonesia (Republic of)",
    "529": "Kiribati (Republic of)",
    "531": "Lao People's Democratic Republic",
    "533": "Malaysia",
    "536": "Northern Mariana Islands (Commonwealth of the)",
    "538": "Marshall Islands (Republic of the)",
    "540": "New Caledonia",
    "542": "Niue",
    "544": "Nauru (Republic of)",
    "546": "French Polynesia",
    "548": "Philippines (Republic of the)",
    "553": "Papua New Guinea",
    "555": "Pitcairn Islands",
    "557": "Solomon Islands",
    "559": "American Samoa",
    "561": "Samoa (Independent State of)",
    "563": "Singapore (Republic of)",
    "564": "Singapore (Republic of)",
    "565": "Singapore (Republic of)",
    "567": "Thailand",
    "570": "Tonga (Kingdom of)",
    "572": "Tuvalu",
    "574": "Viet Nam (Socialist Republic of)",
    "576": "Vanuatu (Republic of)",
    "578": "Wallis and Futuna",
    "601": "South Africa (Republic of)",
    "603": "Angola (Republic of)",
    "605": "Algeria (People's Democratic Republic of)",
    "607": "Saint Paul and Amsterdam Islands",
    "608": "Ascension Island",
    "609": "Burundi (Republic of)",
    "610": "Benin (Republic of)",
    "611": "Botswana (Republic of)",
    "612": "Central African Republic",
    "613": "Cameroon (Republic of)",
    "615": "Congo (Republic of the)",
    "616": "Comoros (Union of the)",
    "617": "Cape Verde (Republic of)",
    "618": "Crozet Archipelago",
    "619": "Côte d'Ivoire (Republic of)",
    "621": "Djibouti (Republic of)",
    "622": "Egypt (Arab Republic of)",
    "624": "Ethiopia (Federal Democratic Republic of)",
    "625": "Eritrea",
    "626": "Gabonese Republic",
    "627": "Ghana",
    "629": "Gambia (Republic of the)",
    "630": "Guinea-Bissau (Republic of)",
    "631": "Equatorial Guinea (Republic of)",
    "632": "Guinea (Republic of)",
    "633": "Burkina Faso",
    "634": "Kenya (Republic of)",
    "635": "Kerguelen Islands",
    "636": "Liberia (Republic of)",
    "637": "Liberia (Republic of)",
    "642": "Socialist People's Libyan Arab Jamahiriya",
    "644": "Lesotho (Kingdom of)",
    "645": "Mauritius (Republic of)",
    "647": "Madagascar (Republic of)",
    "649": "Mali (Republic of)",
    "650": "Mozambique (Republic of)",
    "654": "Mauritania (Islamic Republic of)",
    "655": "Malawi",
    "656": "Niger (Republic of the)",
    "657": "Nigeria (Federal Republic of)",
    "659": "Namibia (Republic of)",
    "660": "Reunion (French Department of)",
    "661": "Rwanda (Republic of)",
    "662": "Sudan (Republic of the)",
    "663": "Senegal (Republic of)",
    "664": "Seychelles (Republic of)",
    "665": "Saint Helena",
    "666": "Somali Democratic Republic",
    "667": "Sierra Leone",
    "668": "Sao Tome and Principe (Democratic Republic of)",
    "669": "Swaziland (Kingdom of)",
    "670": "Chad (Republic of)",
    "671": "Togolese Republic",
    "672": "Tunisia",
    "674": "Tanzania (United Republic of)",
    "675": "Uganda (Republic of)",
    "676": "Democratic Republic of the Congo",
    "677": "Tanzania (United Republic of)",
    "678": "Zambia (Republic of)",
    "679": "Zimbabwe (Republic of)",
    "701": "Argentine Republic",
    "710": "Brazil (Federative Republic of)",
    "720": "Bolivia (Republic of)",
    "725": "Chile",
    "730": "Colombia (Republic of)",
    "735": "Ecuador",
    "740": "Falkland Islands (Malvinas)",
    "745": "Guiana (French Department of)",
    "750": "Guyana",
    "755": "Paraguay (Republic of)",
    "760": "Peru",
    "765": "Suriname (Republic of)",
    "770": "Uruguay (Eastern Republic of)",
    "775": "Venezuela (Bolivarian Republic of)"
}

"""
The following dictionary is created from the above dictionary, but with the country names replaced with their
corresponding country codes. The country codes are taken from the ISO 3166-1 alpha-3 standard.
Source: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3 at 16/04/2024.

Autonomous regions are replaced with their parent country, such as Azores with Portugal, see comments with format:
# Autonomous region --> Parent country 
"""
mid_to_alpha_3 = {
    "201": "ALB",
    "202": "AND",
    "203": "AUT",
    "204": "PRT",  # Azores --> Portugal
    "205": "BEL",
    "206": "BLR",
    "207": "BGR",
    "208": "VAT",
    "209": "CYP",
    "210": "CYP",
    "211": "DEU",
    "212": "CYP",
    "213": "GEO",
    "214": "MDA",
    "215": "MLT",
    "216": "ARM",
    "218": "DEU",
    "219": "DNK",
    "220": "DNK",
    "224": "ESP",
    "225": "ESP",
    "226": "FRA",
    "227": "FRA",
    "228": "FRA",
    "230": "FIN",
    "231": "FRO",
    "232": "GBR",
    "233": "GBR",
    "234": "GBR",
    "235": "GBR",
    "236": "GIB",
    "237": "GRC",
    "238": "HRV",
    "239": "GRC",
    "240": "GRC",
    "241": "GRC",
    "242": "MAR",
    "243": "HUN",
    "244": "NLD",
    "245": "NLD",
    "246": "NLD",
    "247": "ITA",
    "248": "MLT",
    "249": "MLT",
    "250": "IRL",
    "251": "ISL",
    "252": "LIE",
    "253": "LUX",
    "254": "MCO",
    "255": "PRT",  # Madeira --> Portugal
    "256": "MLT",
    "257": "NOR",
    "258": "NOR",
    "259": "NOR",
    "261": "POL",
    "262": "MNE",
    "263": "PRT",
    "264": "ROU",
    "265": "SWE",
    "266": "SWE",
    "267": "SVK",
    "268": "SMR",
    "269": "CHE",
    "270": "CZE",
    "271": "TUR",
    "272": "UKR",
    "273": "RUS",
    "274": "MKD",  # The Former Yugoslav Republic of Macedonia --> North Macedonia
    "275": "LVA",
    "276": "EST",
    "277": "LTU",
    "278": "SVN",
    "279": "SRB",
    "301": "AIA",
    "303": "USA",
    "304": "ATG",
    "305": "ATG",
    "306": "ANT",  # Special case for Netherlands Antilles, uses a transitional code, discontinued for new assignments
    "307": "ABW",
    "308": "BHS",
    "309": "BHS",
    "310": "BMU",
    "311": "BHS",
    "312": "BLZ",
    "314": "BRB",
    "316": "CAN",
    "319": "CYM",
    "321": "CRI",
    "323": "CUB",
    "325": "DMA",
    "327": "DOM",
    "329": "GLP",
    "330": "GRD",
    "331": "GRL",
    "332": "GTM",
    "334": "HND",
    "336": "HTI",
    "338": "USA",
    "339": "JAM",
    "341": "KNA",
    "343": "LCA",
    "345": "MEX",
    "347": "MTQ",
    "348": "MSR",
    "350": "NIC",
    "351": "PAN",
    "352": "PAN",
    "353": "PAN",
    "354": "PAN",
    "355": "PAN",
    "356": "PAN",
    "357": "PAN",
    "358": "PRI",
    "359": "SLV",
    "361": "SPM",
    "362": "TTO",
    "364": "TCA",
    "366": "USA",
    "367": "USA",
    "368": "USA",
    "369": "USA",
    "370": "PAN",
    "371": "PAN",
    "372": "PAN",
    "375": "VCT",
    "376": "VCT",
    "377": "VCT",
    "378": "VGB",
    "379": "VIR",
    "401": "AFG",
    "403": "SAU",
    "405": "BGD",
    "408": "BHR",
    "410": "BTN",
    "412": "CHN",
    "413": "CHN",
    "416": "TWN",
    "417": "LKA",
    "419": "IND",
    "422": "IRN",
    "423": "AZE",
    "425": "IRQ",
    "428": "ISR",
    "431": "JPN",
    "432": "JPN",
    "434": "TKM",
    "436": "KAZ",
    "437": "UZB",
    "438": "JOR",
    "440": "KOR",
    "441": "KOR",
    "443": "PSE",
    "445": "PRK",
    "447": "KWT",
    "450": "LBN",
    "451": "KGZ",
    "453": "MAC",
    "455": "MDV",
    "457": "MNG",
    "459": "NPL",
    "461": "OMN",
    "463": "PAK",
    "466": "QAT",
    "468": "SYR",
    "470": "ARE",
    "473": "YEM",
    "475": "YEM",
    "477": "HKG",
    "478": "BIH",
    "501": "FRA",  # Adélie Land --> France
    "503": "AUS",
    "506": "MMR",
    "508": "BRN",
    "510": "FSM",
    "511": "PLW",
    "512": "NZL",
    "514": "KHM",
    "515": "KHM",
    "516": "CXR",
    "518": "COK",
    "520": "FJI",
    "523": "CCK",
    "525": "IDN",
    "529": "KIR",
    "531": "LAO",
    "533": "MYS",
    "536": "MNP",
    "538": "MHL",
    "540": "NCL",
    "542": "NIU",
    "544": "NRU",
    "546": "PYF",
    "548": "PHL",
    "553": "PNG",
    "555": "PCN",
    "557": "SLB",
    "559": "ASM",
    "561": "WSM",
    "563": "SGP",
    "564": "SGP",
    "565": "SGP",
    "567": "THA",
    "570": "TON",
    "572": "TUV",
    "574": "VNM",
    "576": "VUT",
    "578": "WLF",
    "601": "ZAF",
    "603": "AGO",
    "605": "DZA",
    "607": "ATF",
    "609": "BDI",
    "610": "BEN",
    "611": "BWA",
    "612": "CAF",
    "613": "CMR",
    "615": "COG",
    "616": "COM",
    "617": "CPV",
    "618": "FRA",  # Crozet Archipelago --> France
    "619": "CIV",
    "621": "DJI",
    "622": "EGY",
    "624": "ETH",
    "625": "ERI",
    "626": "GAB",
    "627": "GHA",
    "629": "GMB",
    "630": "GNB",
    "631": "GNQ",
    "632": "GIN",
    "633": "BFA",
    "634": "KEN",
    "635": "FRA",  # Kerguelen Islands --> France
    "636": "LBR",
    "637": "LBR",
    "642": "LBY",
    "644": "LSO",
    "645": "MUS",
    "647": "MDG",
    "649": "MLI",
    "650": "MOZ",
    "654": "MRT",
    "655": "MWI",
    "656": "NER",
    "657": "NGA",
    "659": "NAM",
    "660": "REU",
    "661": "RWA",
    "662": "SDN",
    "663": "SEN",
    "664": "SYC",
    "665": "SHN",
    "666": "SOM",
    "667": "SLE",
    "668": "STP",
    "669": "SWZ",
    "670": "TCD",
    "671": "TGO",
    "672": "TUN",
    "674": "TZA",
    "675": "UGA",
    "676": "COD",
    "677": "TZA",
    "725": "CHL",
    "730": "COL",
    "735": "ECU",
    "740": "FLK",
    "745": "GUF",
    "750": "GUY",
    "755": "PRY",
    "760": "PER",
    "765": "SUR",
    "770": "URY",
    "775": "VEN"
}


def mmsi_to_mid(mmsi: str) -> str:
    """Parse MMSI number, removing any whitespace or MMSI prefix.

    Args:
        mmsi (str): MMSI number to parse.
    """
    validator = MMSIValidator()

    if not validator.validate(mmsi):
        return validator.get_last_error()[2]

    mmsi = mmsi.replace(" ", "")

    if mmsi.startswith("MMSI"):
        mmsi = mmsi[4:]

    return mmsi[:3]


class MMSILookup:

    def __init__(self):
        pass

    @staticmethod
    def to_country_alpha3(mmsi: str) -> str:
        """Looks up the MMSI number to retriever the country code of the vessel per the MMSI MID codes.

        The country code is returned in the ISO 3166-1 alpha-3 standard.

        Args:
            mmsi (str): MMSI number to convert.

        Returns:
            str: Country code.
        """
        mid = mmsi_to_mid(mmsi)

        return mid_to_alpha_3.get(
            mid,
            "MMSI not assigned to any country, maybe it's not a ship? (Handheld, AIS Base Station, etc.)"
        )

    @staticmethod
    def to_country_name(mmsi: str) -> str:
        """Looks up the MMSI number to retriever the country name of the vessel per the MMSI MID codes.

        Args:
            mmsi (str): MMSI number to convert.

        Returns:
            str: Country name.
        """
        mid = mmsi_to_mid(mmsi)

        return mid_to_country.get(
            mid,
            "MMSI not assigned to any country, maybe it's not a ship? (Handheld, AIS Base Station, etc.)"
        )
