import { DeviceAvailabilityMap, DevicePositions } from "pbHelpers/DeviceAvailability";
import { pond, quack } from "protobuf-ts/pond";
import {
  BindaptMini,
  BindaptPlus,
  BindaptPlusLite,
  BindaptPlusMod,
  BindaptPlusPro,
  BindaptPlusProMod,
  BindaptV2Monitor,
  BindaptV2Automate,
  BinHalo,
  BinMonitor,
  BinUltimate,
  StreamlineMonitor,
  StreamlineAutomate
} from "./Bindapt/BindaptDescriber";
import { NexusST } from "./Nexus/NexusDescriber";
import { MiPCAV2, OmniAir } from "./OmniAir/OmniAirDescriber";
import { ConfigurablePin } from "pbHelpers/AddressTypes";
import { useTheme } from "@mui/material";
import { Device } from "models";
import { or } from "utils";
import { MiVent, MiVentV2 } from "./MiVent/MiVentDescriber";

export type ProductTab = "components" | "presets";

export interface DeviceProductDescriber {
  product: pond.DeviceProduct;
  label: string;
  icon: (platform: pond.DevicePlatform, theme?: "light" | "dark") => string | undefined;
  tabs: ProductTab[];
  view?: "default" | "controller";
  availability?: DeviceAvailabilityMap;
  componentExtension?: Boolean;
  defaultAddressMap?: Map<string, string[]>;
}

const None: DeviceProductDescriber = {
  product: pond.DeviceProduct.DEVICE_PRODUCT_NONE,
  label: "None",
  icon: () => undefined,
  tabs: ["components"]
};

//think about making weather describer
const weatherStationPins: ConfigurablePin[] = [
  { address: 4, label: "1" },
  { address: 8, label: "2" },
  { address: 16, label: "3" },
  { address: 32, label: "4" }
];

const Weather: DeviceProductDescriber = {
  product: pond.DeviceProduct.DEVICE_PRODUCT_WEATHER_STATION,
  label: "Weather Station",
  icon: () => undefined,
  tabs: ["components"],
  availability: new Map<quack.AddressType, DevicePositions>([
    [quack.AddressType.ADDRESS_TYPE_INVALID, []],
    [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY, weatherStationPins],
    [
      quack.AddressType.ADDRESS_TYPE_I2C,
      new Map<quack.ComponentType, number[]>([
        [quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18]],
        [quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]],
        // [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //deprecated?
        [quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]]
      ])
    ],
    [quack.AddressType.ADDRESS_TYPE_POWER, [0]],
    [quack.AddressType.ADDRESS_TYPE_GPS, [0]],
    [quack.AddressType.ADDRESS_TYPE_MODEM, [0]]
  ])
};

const DEVICE_PRODUCT_MAP = new Map<pond.DeviceProduct, DeviceProductDescriber>([
  [pond.DeviceProduct.DEVICE_PRODUCT_NONE, None],
  [pond.DeviceProduct.DEVICE_PRODUCT_BINDAPT_PLUS, BindaptPlus],
  [pond.DeviceProduct.DEVICE_PRODUCT_BINDAPT_PLUS_PRO, BindaptPlusPro],
  [pond.DeviceProduct.DEVICE_PRODUCT_BINDAPT_PLUS_LITE, BindaptPlusLite],
  [pond.DeviceProduct.DEVICE_PRODUCT_BINDAPT_MINI, BindaptMini],
  [pond.DeviceProduct.DEVICE_PRODUCT_WEATHER_STATION, Weather],
  [pond.DeviceProduct.DEVICE_PRODUCT_NEXUS_ST, NexusST],
  [pond.DeviceProduct.DEVICE_PRODUCT_OMNIAIR, OmniAir],
  [pond.DeviceProduct.DEVICE_PRODUCT_BIN_HALO, BinHalo],
  [pond.DeviceProduct.DEVICE_PRODUCT_BIN_ULTIMATE, BinUltimate],
  [pond.DeviceProduct.DEVICE_PRODUCT_BIN_MONITOR, BinMonitor],
  [pond.DeviceProduct.DEVICE_PRODUCT_MIPCA_V2, MiPCAV2],
  [pond.DeviceProduct.DEVICE_PRODUCT_BINDAPT_PLUS_MOD, BindaptPlusMod],
  [pond.DeviceProduct.DEVICE_PRODUCT_BINDAPT_PLUS_PRO_MOD, BindaptPlusProMod],
  [pond.DeviceProduct.DEVICE_PRODUCT_BINDAPT_V2_MONITOR, BindaptV2Monitor],
  [pond.DeviceProduct.DEVICE_PRODUCT_BINDAPT_V2_AUTOMATE, BindaptV2Automate],
  [pond.DeviceProduct.DEVICE_PRODUCT_MIVENT, MiVent],
  [pond.DeviceProduct.DEVICE_PRODUCT_MIVENT_V2, MiVentV2],
  [pond.DeviceProduct.DEVICE_PRODUCT_STREAMLINE_MONITOR, StreamlineMonitor],
  [pond.DeviceProduct.DEVICE_PRODUCT_STREAMLINE_AUTOMATE, StreamlineAutomate]
]);

export function ListDeviceProductDescribers(): DeviceProductDescriber[] {
  return [...DEVICE_PRODUCT_MAP.values()];
}

function getDescriber(product: pond.DeviceProduct): DeviceProductDescriber {
  let describer = DEVICE_PRODUCT_MAP.get(product);
  return describer ? describer : None;
}

export function GetDeviceProductLabel(product: pond.DeviceProduct): string {
  return getDescriber(product).label;
}

export function GetDeviceProductIcon(
  device: pond.Device | Device
): string | undefined {
  const theme = useTheme()
  const product = or(device.settings?.product, pond.DeviceProduct.DEVICE_PRODUCT_NONE)
  const platform = or(device.settings?.platform, pond.DevicePlatform.DEVICE_PLATFORM_INVALID)
  return getDescriber(product).icon(platform, theme.palette.mode);
}

export function IsCardController(product?: pond.DeviceProduct): boolean {
  return product ? getDescriber(product).view === "controller" : false;
}

export function GetDeviceProductViews(product?: pond.DeviceProduct): boolean {
  return product ? getDescriber(product).view === "controller" : false;
}

export function GetDeviceProductTabs(product?: pond.DeviceProduct): ProductTab[] {
  return product ? getDescriber(product).tabs : ["components"];
}

export function GetProductAvailability(
  product?: pond.DeviceProduct
): DeviceAvailabilityMap | undefined {
  return product ? getDescriber(product).availability : undefined;
}

export function IsExtended(product: pond.DeviceProduct): boolean {
  let isExtended = getDescriber(product).componentExtension;
  if (isExtended) {
    return true;
  } else {
    return false;
  }
}

export function GetProductDefaults(product: pond.DeviceProduct): Map<string, string[]> | undefined {
  return getDescriber(product).defaultAddressMap;
}
