import { pond } from "protobuf-ts/pond";
import { or } from "utils/types";
import { cloneDeep } from "lodash";
import { MarkerData } from "maps/mapMarkers/Markers";

interface FeatureVersionByPlatform {
  photon: string;
  electron: string;
  v2Wifi: string;
  v2Cell: string;
  v2WifiS3: string;
  v2CellS3: string;
  v2CellBlack: string;
  v2CellGreen: string;
  v2WifiBlue: string;
  v2CellBlue: string;
  v2EthBlue: string;
}

const featureVersions: Map<string, FeatureVersionByPlatform> = new Map([
  [
    "individualCalibrations",
    {
      photon: "1.19.64",
      electron: "1.19.64",
      v2Cell: "2.0.44",
      v2Wifi: "2.0.44",
      v2WifiS3: "2.0.44",
      v2CellS3: "2.0.44",
      v2CellBlack: "2.0.44",
      v2CellGreen: "2.0.44",
      v2WifiBlue: "2.0.44",
      v2CellBlue: "2.0.44",
      v2EthBlue: "2.0.44"
    }
  ],[
    "reverseNodes",
    {
      photon: "N/A",
      electron: "N/A",
      v2Wifi: "N/A",
      v2Cell: "N/A",
      v2WifiS3: "N/A",
      v2CellS3: "N/A",
      v2CellBlack: "2.1.8",
      v2CellGreen: "N/A",
      v2WifiBlue: "2.1.8",
      v2CellBlue: "2.1.8",
      v2EthBlue: "2.1.8"
    }
  ],
  [
    "detectI2C",
    {
      photon: "N/A",
      electron: "N/A",
      v2Wifi: "N/A",
      v2Cell: "N/A",
      v2WifiS3: "N/A",
      v2CellS3: "N/A",
      v2CellBlack: "2.1.7",
      v2CellGreen: "N/A",
      v2WifiBlue: "2.1.7",
      v2CellBlue: "2.1.7",
      v2EthBlue: "2.1.7"
    }
    ],[
    "detectOneWire",
    {
      photon: "N/A",
      electron: "N/A",
      v2Wifi: "N/A",
      v2Cell: "N/A",
      v2WifiS3: "N/A",
      v2CellS3: "N/A",
      v2CellBlack: "2.1.10",
      v2CellGreen: "N/A",
      v2WifiBlue: "2.1.10",
      v2CellBlue: "2.1.10",
      v2EthBlue: "2.1.10"
    }
  ]
]);
export class Device {
  public settings: pond.DeviceSettings = pond.DeviceSettings.create();
  public status: pond.DeviceStatus = pond.DeviceStatus.create();

  public static create(pb?: pond.Device): Device {
    let my = new Device();
    if (pb) {
      my.settings = pond.DeviceSettings.fromObject(or(pb.settings, {}));
      my.status = pond.DeviceStatus.fromObject(or(pb.status, {}));
    }
    return my;
  }

  public static any(data: any): Device {
    if (data.device) return Device.create(pond.Device.fromObject(cloneDeep(data.device)));
    return Device.create(pond.Device.fromObject(cloneDeep(data)));
  }

  public static clone(other: Device): Device {
    let my = new Device();
    my.settings = pond.DeviceSettings.fromObject(cloneDeep(other.settings));
    my.status = pond.DeviceStatus.fromObject(cloneDeep(other.status));
    return my;
  }

  public id(): number {
    return Number(this.settings.deviceId);
  }

  public name(): string {
    return this.settings.name !== ""
      ? this.settings.name
      : this.id() > 0
      ? "Device " + this.id()
      : "";
  }

  public location(): pond.Location {
    let loc = pond.Location.create();
    loc.longitude = this.settings.longitude;
    loc.latitude = this.settings.latitude;
    return loc;
  }

  public getMarkerData(
    clickFunc?: (event: React.PointerEvent<HTMLElement>, index: number, isMobile: boolean) => void,
    updateFunc?: (location: pond.Location) => void
  ): MarkerData {
    let m: MarkerData = {
      longitude: this.location()?.longitude ?? 0,
      latitude: this.location()?.latitude ?? 0,
      title: this.name(),
      colour: this.settings.theme?.color ?? "blue",
      clickFunc: clickFunc,
      updateFunc: updateFunc
    };
    return m;
  }

  public platformName(): string {
      switch (this.settings.platform) {
      case pond.DevicePlatform.DEVICE_PLATFORM_PHOTON:
        return "Photon"
      case pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON:
        return "Electron"
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR:
        return "V2 Cellular"
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI:
        return "V2 Wifi"
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_S3:
        return "V2 Wifi S3"
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_S3:
        return "V2 Cellular S3"
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLACK:
        return "V2 Cellular Black"
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_GREEN:
        return "V2 Callular Green"
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_BLUE:
        return "V2 Wifi Blue"
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLUE:
        return "V2 Cellular Blue"
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_ETHERNET_BLUE:
        return "V2 Ethernet Blue"
      default:
        return "";
    }
  }

  public maxConditions(): number {
    let max = 2
    switch (this.settings.platform) {
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLACK:
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_BLUE:
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLUE:
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_ETHERNET_BLUE:
        max = this.versionComparison(this.status.firmwareVersion, "2.1.9") ? 4 : 2;
    }
    return max
  }

  private versionComparison(deviceVersion: string, requiredVersion: string): boolean {
    // Feature explicitly not supported on this platform
    if (!requiredVersion || requiredVersion === "N/A") {
      return false;
    }
  
    // Device firmware missing / unset
    if (!deviceVersion || deviceVersion.trim() === "") {
      return false;
    }

    //compare the versions
    const parse = (v: string) => {
      const [core, pre] = v.split("-");
      const parts = core.split(".").map(n => parseInt(n, 10));
  
      let preLabel = "";
      let preNum = 0;
  
      if (pre) {
        const match = pre.match(/^([a-zA-Z]+)(\d*)$/);
        if (match) {
          preLabel = match[1].toLowerCase();
          preNum = match[2] ? parseInt(match[2], 10) : 0;
        }
      }
  
      return { parts, preLabel, preNum };
    };
  
    const rank = (label: string): number => {
      switch (label) {
        case "alpha": return 1;
        case "beta":  return 2;
        case "rc":    return 3;
        default:      return 0; // release
      }
    };
  
    const a = parse(deviceVersion);
    const b = parse(requiredVersion);
  
    // Compare major/minor/patch
    const len = Math.max(a.parts.length, b.parts.length);
    for (let i = 0; i < len; i++) {
      const av = a.parts[i] ?? 0;
      const bv = b.parts[i] ?? 0;
      if (av > bv) return true;
      if (av < bv) return false;
    }
  
    // Handle prerelease vs release
    if (!a.preLabel && b.preLabel) return true;   // release > prerelease
    if (a.preLabel && !b.preLabel) return false;
  
    // Both prereleases → compare rank
    if (a.preLabel !== b.preLabel) {
      return rank(a.preLabel) >= rank(b.preLabel);
    }
  
    // Same prerelease label → compare numeric suffix
    return a.preNum >= b.preNum;
  }

  public featureSupported(feature: string): boolean {
    let versions = featureVersions.get(feature);
    if (!versions) {
      return false;
    }
    switch (this.settings.platform) {
      case pond.DevicePlatform.DEVICE_PLATFORM_PHOTON:
        return this.versionComparison(this.status.firmwareVersion, versions.photon);
      case pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON:
        return this.versionComparison(this.status.firmwareVersion, versions.electron);
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR:
        return this.versionComparison(this.status.firmwareVersion, versions.v2Cell);
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI:
        return this.versionComparison(this.status.firmwareVersion, versions.v2Wifi);
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_S3:
        return this.versionComparison(this.status.firmwareVersion, versions.v2WifiS3);
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_S3:
        return this.versionComparison(this.status.firmwareVersion, versions.v2CellS3);
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLACK:
        return this.versionComparison(this.status.firmwareVersion, versions.v2CellBlack);
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_GREEN:
        return this.versionComparison(this.status.firmwareVersion, versions.v2CellGreen);
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_BLUE:
        return this.versionComparison(this.status.firmwareVersion, versions.v2WifiBlue);
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLUE:
        return this.versionComparison(this.status.firmwareVersion, versions.v2CellBlue);
      case pond.DevicePlatform.DEVICE_PLATFORM_V2_ETHERNET_BLUE:
        return this.versionComparison(this.status.firmwareVersion, versions.v2EthBlue);
      default:
        return false;
    }
  }
}
