import { Device, Tag } from "models";
import moment from "moment";
import { filterByTags } from "pbHelpers/Tag";
import { GetDeviceProductLabel } from "products/DeviceProduct";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { capitalize } from "utils/strings";
import { getDevicePlatformLabel } from "./DevicePlatform";
import { filterByDeviceState } from "./DeviceState";
import { filterByPower } from "./Power";
import { getUpgradeChannelLabel } from "./UpgradeChannel";

//complex filter algorithm for searching a list of devices
export function filterDevices(searchValue: string, devices: Device[], tags: Tag[]): Device[] {
  return devices.filter(device =>
    filterDevice(searchValue.toLowerCase(), device, deviceTags(device, tags))
  );
}

//helper function for filterDevices
export function filterDevice(searchValue: string, device: Device, tags: Tag[]): boolean {
  const idMatch: boolean = filterByDeviceID(searchValue, device.settings.deviceId.toString());
  const nameMatch: boolean = filterByDeviceName(searchValue, device.name());
  const tagsMatch: boolean = filterByTags(searchValue, tags);
  const deviceStateMatch: boolean = filterByDeviceState(searchValue, device.status.state);
  const powerMatch: boolean = filterByPower(
    searchValue,
    device.status.power ? pond.DevicePower.create(device.status.power) : undefined
  );
  const lastActiveMatch: boolean = filterByLastActive(searchValue, device.status.lastActive);
  return idMatch || nameMatch || tagsMatch || powerMatch || deviceStateMatch || lastActiveMatch;
}

export function filterByDeviceID(searchValue: string, deviceIDString: string): boolean {
  return searchValue.replace("id:", "").trim() === deviceIDString;
}

export function filterByDeviceName(searchValue: string, deviceName: string): boolean {
  return (
    deviceName.toLowerCase().indexOf(
      searchValue
        .replace("name:", "")
        .trim()
        .toLowerCase()
    ) > -1
  );
}

export function filterByDeviceDescription(searchValue: string, deviceDescription: string): boolean {
  return (
    deviceDescription.toLowerCase().indexOf(
      searchValue
        .replace("description:", "")
        .trim()
        .toLowerCase()
    ) > -1
  );
}

export function filterByLastActive(searchValue: string, lastActive: string): boolean {
  return (
    moment(lastActive)
      .fromNow()
      .indexOf(searchValue.replace("last active:", "")) > -1
  );
}

export function deviceTags(device: Device, tags: Tag[]): Tag[] {
  return tags.filter(tag => device.status.tagKeys.some(key => key === tag.settings.key));
}

const keyTranslator = new Map<keyof pond.DeviceSettings, string>([
  ["deviceId", "Device ID"],
  ["name", "Name"],
  ["description", "Description"],
  ["sleepType", "Sleep Type"],
  ["sleepDurationS", "Sleep Duration"],
  ["sleepDelayMs", "Sleep Delay"],
  ["pondCheckPeriodS", "Check Period"],
  ["removed", "Removed"],
  ["platform", "Platform"],
  ["wakePin", "Wake Pin"],
  ["platform", "Platform"],
  ["automaticallyUpgrade", "Upgrades Automatically"],
  ["product", "Product"],
  ["upgradeChannel", "Upgrade Channel"],
  ["latitude", "Latitude"],
  ["longitude", "Longitude"],
  ["theme", "Marker Theme"],
  ["extensionComponents", "Extension Components"],
  ["mutations", "Device Mutations"]
]);

// Keys will be stringified by default if not found in the keyTranslator
export function TranslateKey(key: keyof pond.DeviceSettings): string {
  let translatedKey = keyTranslator.get(key);
  return translatedKey ? translatedKey : capitalize(key.toString());
}

const valueTranslator = new Map<keyof pond.DeviceSettings, (device: pond.DeviceSettings) => string>(
  [
    ["name", device => device.name],
    ["description", device => device.description],
    [
      "sleepType",
      device => {
        switch (device.sleepType) {
          case quack.SleepType.SLEEP_TYPE_DEEP:
            return "Deep Sleep";
          case quack.SleepType.SLEEP_TYPE_HIBERNATE:
            return "Hibernate";
          case quack.SleepType.SLEEP_TYPE_NAP:
            return "Nap";
          default:
            return "None";
        }
      }
    ],
    ["sleepDurationS", device => device.sleepDurationS.toString() + "s"],
    ["sleepDelayMs", device => (device.sleepDelayMs / 1000).toString() + "s"],
    ["pondCheckPeriodS", device => device.pondCheckPeriodS.toString() + "s"],
    ["platform", device => getDevicePlatformLabel(device.platform)],
    ["product", device => GetDeviceProductLabel(device.product)],
    ["upgradeChannel", device => getUpgradeChannelLabel(device.upgradeChannel)],
    ["automaticallyUpgrade", device => device.automaticallyUpgrade.toString()],
    ["latitude", device => device.latitude.toString()],
    ["longitude", device => device.longitude.toString()],
    ["theme", device => "Colour: " + device.theme?.color + "Size: " + device.theme?.height],
    ["extensionComponents", device => device.extensionComponents.toString()],
    ["mutations", device => device.mutations.toString()]
  ]
);

// Values will be stringified by default if its key is not found in the valueTranslator
export function TranslateValue(key: keyof pond.DeviceSettings, device: pond.DeviceSettings) {
  //console.log(device)
  //console.log(key)
  let translatorFunc = valueTranslator.get(key);
  let dKey = device[key];
  return translatorFunc ? translatorFunc(device) : capitalize(dKey ? dKey.toString() : "");
}

//checks the user's path to determine if they are on a shared url
export function isShareableLink(rawDeviceID: string): boolean {
  if (!rawDeviceID) {
    return false;
  }
  return isNaN(Number(rawDeviceID));
}
