"""List of airOS products."""

from .exceptions import AirOSMultipleMatchesFoundException

# Generated list from https://store.ui.com/us/en/category/wireless
SITE_MODELS: dict[str, str] = {
    "Wave MLO5": "Wave-MLO5",
    "airMAX Rocket Prism 5AC": "RP-5AC-Gen2",
    "airFiber 5XHD": "AF-5XHD",
    "airMAX Lite AP GPS": "LAP-GPS",
    "airMAX PowerBeam 5AC": "PBE-5AC-Gen2",
    "airMAX PowerBeam 5AC ISO": "PBE-5AC-ISO-Gen2",
    "airMAX PowerBeam 5AC 620": "PBE-5AC-620",
    "airMAX LiteBeam 5AC": "LBE-5AC-GEN2",
    "airMAX LiteBeam 5AC Long-Range": "LBE-5AC-LR",
    "airMAX NanoBeam 5AC": "NBE-5AC-GEN2",
    "airMAX NanoStation 5AC": "NS-5AC",
    "airMAX NanoStation 5AC Loco": "Loco5AC",
    "LTU Rocket": "LTU-Rocket",
    "LTU Instant (5-pack)": "LTU-Instant",
    "LTU Pro": "LTU-PRO",
    "LTU Long-Range": "LTU-LR",
    "LTU Extreme-Range": "LTU-XR",
    "airMAX NanoBeam 2AC": "NBE-2AC-13",
    "airMAX PowerBeam 2AC 400": "PBE-2AC-400",
    "airMAX Rocket AC Lite": "R5AC-LITE",
    "airMAX LiteBeam M5": "LBE-M5-23",
    "airMAX PowerBeam 5AC 500": "PBE-5AC-500",
    "airMAX PrismStation 5AC": "PS-5AC",
    "airMAX IsoStation 5AC": "IS-5AC",
    "airMAX Lite AP": "LAP-120",
    "airMAX PowerBeam M5 400": "PBE-M5-400",
    "airMAX PowerBeam M5 300 ISO": "PBE-M5-300-ISO",
    "airMAX PowerBeam M5 300": "PBE-M5-300",
    "airMAX PowerBeam M2 400": "PBE-M2-400",
    "airMAX Bullet AC": "B-DB-AC",
    "airMAX Bullet AC IP67": "BulletAC-IP67",
    "airMAX Bullet M2": "BulletM2-HP",
    "airMAX IsoStation M5": "IS-M5",
    "airMAX NanoStation M5": "NSM5",
    "airMAX NanoStation M5 loco": "LocoM5",
    "airMAX NanoStation M2 loco": "LocoM2",
    "UISP Horn": "UISP-Horn",
    "UISP Dish": "UISP-Dish",
    "UISP Dish Mini": "UISP-Dish-Mini",
    "airMAX AC 5 GHz, 31 dBi RocketDish": "RD-5G31-AC",
    "airMAX 5 GHz, 30 dBi RocketDish LW": "RD-5G30-LW",
    "airMAX AC 5 GHz, 30/34 dBi RocketDish": "RD-5G",
    "airPRISM 3x30° HD Sector": "AP-5AC-90-HD",
    "airMAX 5 GHz, 16/17 dBi Sector": "AM-5G1",
    "airMAX PrismStation Horn": "Horn-5",
    "airMAX 5 GHz, 10 dBi Omni": "AMO-5G10",
    "airMAX 5 GHz, 13 dBi, Omni": "AMO-5G13",
    "airMAX Sector 2.4 GHz Titanium": "AM-V2G-Ti",
    "airMAX AC 5 GHz, 21 dBi, 60º Sector": "AM-5AC21-60",
    "airMAX AC 5 GHz, 22 dBi, 45º Sector": "AM-5AC22-45",
    "airMAX 2.4 GHz, 16 dBi, 90º Sector": "AM-2G16-90",
    "airMAX 900 MHz, 13 dBi, 120º Sector": "AM-9M13-120",
    "airMAX 900 MHz, 16 dBi Yagi": "AMY-9M16x2",
    "airMAX NanoBeam M5": "NBE-M5-16",
    "airMAX Rocket Prism 2AC": "R2AC-PRISM",
    "airFiber 5 Mid-Band": "AF-5",
    "airFiber 5 High-Band": "AF-5U",
    "airFiber 24": "AF-24",
    "airFiber 24 Hi-Density": "AF-24HD",
    "airFiber 2X": "AF-2X",
    "airFiber 11": "AF-11",
    "airFiber 11 Low-Band Backhaul Radio with Dish Antenna": "AF11-Complete-LB",
    "airFiber 11 High-Band Backhaul Radio with Dish Antenna": "AF11-Complete-HB",
    "airMAX LiteBeam 5AC Extreme-Range": "LBE-5AC-XR",
    "airMAX PowerBeam M5 400 ISO": "PBE-M5-400-ISO",
    "airMAX NanoStation M2": "NSM2",
    "airFiber X 5 GHz, 23 dBi, Slant 45": "AF-5G23-S45",
    "airFiber X 5 GHz, 30 dBi, Slant 45": "AF-5G30-S45",
    "airFiber X 5 GHz, 34 dBi, Slant 45": "AF-5G34-S45",
    "airMAX 5 GHz, 19/20 dBi Sector": "AM-5G2",
    "airMAX 2.4 GHz, 10 dBi Omni": "AMO-2G10",
    "airMAX 2.4 GHz, 15 dBi, 120º Sector": "AM-2G15-120",
}

# Manually added entries for common unofficial names
# When adding a LiteBeam: update tests/test_model_map.py assert for count as well
MANUAL_MODELS: dict[str, str] = {
    "LiteAP AC": "LAP-120",  # Shortened name for airMAX Lite Access Point AC, Issue 137
    "LiteAP GPS": "LAP-GPS",  # Shortened name for airMAX Lite Access Point GPS
    "LiteBeam 5AC 23": "LBE-5AC-23",
    "NanoStation loco M5": "LocoM5",  # XM firmware version 6 - note the reversed names
    "NanoStation loco M900": "LocoM900",  # XM firmware version 6, 900 MHz variant
}

MODELS: dict[str, str] = {**SITE_MODELS, **MANUAL_MODELS}


class UispAirOSProductMapper:
    """Utility class to map product model names to SKUs and vice versa."""

    def __init__(self) -> None:
        """Provide reversed map for SKUs."""
        self._SKUS = {v: k for k, v in MODELS.items()}

    def get_sku_by_devmodel(self, devmodel: str) -> str:
        """Retrieves the SKU for a given device model name."""
        devmodel = devmodel.strip()
        if devmodel in MODELS:
            return MODELS[devmodel]

        match_key: str | None = None
        matches_found: int = 0

        best_match_key: str | None = None
        best_match_is_prefix = False

        lower_devmodel = devmodel.lower()

        for model_name in MODELS:
            lower_model_name = model_name.lower()

            if lower_model_name.endswith(lower_devmodel):
                if not best_match_is_prefix or len(lower_model_name) == len(
                    lower_devmodel
                ):
                    best_match_key = model_name
                    best_match_is_prefix = True
                    matches_found = 1
                    match_key = model_name
                else:
                    matches_found += 1
                    best_match_key = None

            elif not best_match_is_prefix and lower_devmodel in lower_model_name:
                matches_found += 1
                match_key = model_name

        if best_match_key and best_match_is_prefix and matches_found == 1:
            # If a unique prefix match was found ("LiteBeam 5AC" -> "airMAX LiteBeam 5AC")
            return MODELS[best_match_key]

        if best_match_key and best_match_is_prefix and matches_found > 1:
            pass  # fall through exception

        if match_key is None or matches_found == 0:
            raise KeyError(f"No product found for devmodel: {devmodel}")

        if match_key and matches_found == 1:
            return MODELS[match_key]

        raise AirOSMultipleMatchesFoundException(
            f"Partial model '{devmodel}' matched multiple ({matches_found}) products."
        )

    def get_devmodel_by_sku(self, sku: str) -> str:
        """Retrieves the full device model name for an exact SKU match."""
        if sku in self._SKUS:
            return self._SKUS[sku]
        raise KeyError(f"No product found for SKU: {sku}")
