window.__ARMED__ = false;
window.__SAFETY__ = true;
window.__CONNECTED__ = false;

const COLLAR_BT_NAME = "PetSafe Smart Dog Trainer";
const COLLAR_COMMAND_SERVICE = "0bd51666-e7cb-469b-8e4d-2742f1ba77cc";
const COLLAR_COMMAND_CHARACTERISTIC = "e7add780-b042-4876-aae1-112855353cc1";
const COLLAR_AUTH_CHARACTERISTIC = "0e7ad781-b043-4877-aae2-112855353cc2";
const COLLAR_TONE_COMMAND = [0x55, 0x36, 0x31, 0x31, 0x31, 0x30];
const COLLAR_VIBRATE_COMMAND = [0x55, 0x36, 0x31, 0x33, 0x33, 0x30];
// Last byte is command strength (0-15) + 0x48. We set it to 0 here.
const COLLAR_STATIC_COMMAND = [0x55, 0x36, 0x31, 0x32, 0x33, 0x30];
// Last four bytes are the ASCII values of the PIN digits
const COLLAR_AUTH_COMMAND = [0x55, 0x37, 0x37, 0x30, 0x30, 0x30, 0x30];

class PetsafeSmartDogTrainingCollar {
  constructor() {
    this.device = null;
    this.service = null;
    this.tx = null;
  }

  async connect() {
    console.log("Starting connect");

    if (!navigator.bluetooth) {
      addLogMessage("No WebBluetooth support; bailing.");
      throw new Error("No WebBluetooth; bailing.");
    }

    this.device = await navigator.bluetooth.requestDevice({
      filters: [
        {
          name: COLLAR_BT_NAME,
        },
      ],
      optionalServices: [COLLAR_COMMAND_SERVICE],
    });
    let server = await this.device.gatt.connect();
    this.service = await server.getPrimaryService(COLLAR_COMMAND_SERVICE);
    this.tx = await this.service.getCharacteristic(
      COLLAR_COMMAND_CHARACTERISTIC
    );
    this.auth = await this.service.getCharacteristic(
      COLLAR_AUTH_CHARACTERISTIC
    );
    console.log("Connected");
  }

  async disconnect() {
    await this.device.gatt.disconnect();
  }
  async authorize(d1, d2, d3, d4) {
    console.log("Authenticating with ", d1, d2, d3, d4);
    let r = new Uint8Array(COLLAR_AUTH_COMMAND);
    r[3] += d1;
    r[4] += d2;
    r[5] += d3;
    r[6] += d4;
    console.log(r);
    this.auth.writeValue(r);
  }
  async runTone() {
    console.log("Running tone");
    addLogMessage("[TONE]");
    this.tx.writeValue(new Uint8Array(COLLAR_TONE_COMMAND));
  }

  async runVibrate() {
    console.log("Running vibration");
    addLogMessage("[VIBRATE]");
    this.tx.writeValue(new Uint8Array(COLLAR_VIBRATE_COMMAND));
  }

  async runStatic(power) {
    if (window.__SAFETY__) {
      addLogMessage("SAFETY ON; runStatic REJECTED");
      return;
    }

    console.log("Running static");
    addLogMessage("[SHOCK] Power = " + power);
    if (power < 0 || power > 15) {
      throw Error("power not in range 0-15");
    }
    let r = new Uint8Array(COLLAR_STATIC_COMMAND);
    r[5] += power;
    console.log(r);
    this.tx.writeValue(r);
  }
}

const collar = new PetsafeSmartDogTrainingCollar();

const addLogMessage = (message) => {
  const logEl = document.querySelector("#log");
  logEl.innerHTML = `${new Date().toISOString()} :: ${message}\n${
    logEl.innerHTML
  }`;
};

const setIntensityReadout = (value) => {
  document.querySelector("#intensity-readout").innerHTML = value;
};

window.getIntensity = () => document.querySelector("#intensity").value;

const setStatus = (color, text) => {
  document.querySelector("#dot").style.backgroundColor = color;
  document.querySelector("#dotText").innerHTML = text;
};

const setSafety = (color, text) => {
  document.querySelector("#safetyDot").style.backgroundColor = color;
  document.querySelector("#safetyDotText").innerHTML = text;
};

const connectCollar = async (pin) => {
  addLogMessage("Connecting to collar...");
  await collar.connect();
  addLogMessage("Collar connected; running vibration test.");
  await collar.runVibrate();
};

const fire = (level) => {
  if (window.__SAFETY__ || !window.__ARMED__) {
    addLogMessage("SAFETY ON or NOT ARMED -- FIRE REJECTED.");
    return;
  }

  collar.runStatic(level);
};

window.shockInit = () => {
  document.querySelector("#arm").addEventListener("change", (event) => {
    window.__ARMED__ = event.target.checked;

    if (event.target.checked) {
      addLogMessage("ARMED");
      setStatus("yellow", "ARMED");
    } else {
      addLogMessage("Disarmed.");
      setStatus("red", "Not Armed");
    }
  });

  document.querySelector("#safety").addEventListener("change", (event) => {
    window.__SAFETY__ = event.target.checked;

    if (event.target.checked) {
      addLogMessage("Safety is on; shock commands will NOT be sent.");
      setSafety("red", "Safety ON (commands will not be sent)");
    } else {
      addLogMessage("Safety is off. Good luck, dolly.");
      setSafety("green", "Safety OFF");
    }
  });

  document.querySelector("#pair").addEventListener("click", () => {
    // const pin = document.querySelector("#pin").value;
    connectCollar();
  });

  document.querySelector("#intensity").addEventListener("input", (event) => {
    setIntensityReadout(event.target.value);
  });

  setIntensityReadout(getIntensity());

  document.querySelector("#safety").checked = true;
  document.querySelector("#arm").checked = false;
  addLogMessage("Safety is on; shock commands will NOT be sent.");
  addLogMessage("Ready");
};
