/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const { XPCOMUtils } = ChromeUtils.importESModule(
  "resource://gre/modules/XPCOMUtils.sys.mjs"
);
const { l10nHelper } = ChromeUtils.importESModule(
  "resource:///modules/imXPCOMUtils.sys.mjs"
);
const { OTR } = ChromeUtils.importESModule("resource:///modules/OTR.sys.mjs");

window.addEventListener("DOMContentLoaded", event => {
  otrAuth.onload();
});

var [mode, uiConv, contactInfo] = window.arguments;

function showSection(selected, hideMenu) {
  document.getElementById("how").hidden = !!hideMenu;
  ["questionAndAnswer", "sharedSecret", "manualVerification", "ask"].forEach(
    function (key) {
      document.getElementById(key).hidden = key !== selected;
    }
  );
  window.sizeToContent();
}

function startSMP(context, answer, question) {
  OTR.sendSecret(context, answer, question);
  OTR.authUpdate(context, 10);
}

function manualVerification(fingerprint, context) {
  let opts = document.getElementById("verifiedOption");
  let trust = opts.selectedItem.value === "yes";
  OTR.setTrust(fingerprint, trust, context);
}

async function populateFingers(context, theirs, trust) {
  let yours = OTR.privateKeyFingerprint(context.account, context.protocol);
  if (!yours) {
    throw new Error("Fingerprint should already be generated.");
  }

  let [yourFPLabel, theirFPLabel] = await document.l10n.formatValues([
    { id: "auth-your-fp-value", args: { own_name: context.account } },
    { id: "auth-their-fp-value", args: { their_name: context.username } },
  ]);

  document.getElementById("yourFPLabel").value = yourFPLabel;
  document.getElementById("theirFPLabel").value = theirFPLabel;

  document.getElementById("yourFPValue").value = yours;
  document.getElementById("theirFPValue").value = theirs;

  let opts = document.getElementById("verifiedOption");
  let verified = trust ? "yes" : "no";
  for (let item of opts.menupopup.children) {
    if (verified === item.value) {
      opts.selectedItem = item;
      break;
    }
  }
}

var otrAuth = {
  async onload() {
    // This window implements the interactive authentication of a buddy's
    // key. At open time, we're given several parameters, and the "mode"
    // parameter tells us from where we've been called.
    // mode == "pref" means that we have been opened from the preferences,
    // and it means we cannot rely on the other user being online, and
    // we there might be no uiConv active currently, so we fall back.

    let nameSource =
      mode === "pref" ? contactInfo.screenname : uiConv.normalizedName;
    let title = await document.l10n.formatValue("auth-title", {
      name: nameSource,
    });
    document.title = title;

    document.addEventListener("dialogaccept", () => {
      return this.accept();
    });

    document.addEventListener("dialogcancel", () => {
      return this.cancel();
    });

    let context, theirs;
    switch (mode) {
      case "start":
        context = OTR.getContext(uiConv.target);
        theirs = OTR.hashToHuman(context.fingerprint);
        populateFingers(context, theirs, context.trust);
        showSection("questionAndAnswer");
        break;
      case "pref":
        context = OTR.getContextFromRecipient(
          contactInfo.account,
          contactInfo.protocol,
          contactInfo.screenname
        );
        theirs = contactInfo.fingerprint;
        populateFingers(context, theirs, contactInfo.trust);
        showSection("manualVerification", true);
        this.oninput({ value: true });
        break;
      case "ask":
        let receivedQuestionLabel = document.getElementById(
          "receivedQuestionLabel"
        );
        let receivedQuestionDisplay =
          document.getElementById("receivedQuestion");
        let responseLabel = document.getElementById("responseLabel");
        if (contactInfo.question) {
          receivedQuestionLabel.hidden = false;
          receivedQuestionDisplay.hidden = false;
          receivedQuestionDisplay.value = contactInfo.question;
          responseLabel.value = await document.l10n.formatValue("auth-answer");
        } else {
          receivedQuestionLabel.hidden = true;
          receivedQuestionDisplay.hidden = true;
          responseLabel.value = await document.l10n.formatValue("auth-secret");
        }
        showSection("ask", true);
        break;
    }
  },

  accept() {
    // uiConv may not be present in pref mode
    let context = uiConv ? OTR.getContext(uiConv.target) : null;
    if (mode === "pref") {
      manualVerification(contactInfo.fpointer, context);
    } else if (mode === "start") {
      let how = document.getElementById("howOption");
      switch (how.selectedItem.value) {
        case "questionAndAnswer":
          let question = document.getElementById("question").value;
          let answer = document.getElementById("answer").value;
          startSMP(context, answer, question);
          break;
        case "sharedSecret":
          let secret = document.getElementById("secret").value;
          startSMP(context, secret);
          break;
        case "manualVerification":
          manualVerification(context.fingerprint, context);
          break;
        default:
          throw new Error("Unreachable!");
      }
    } else if (mode === "ask") {
      let response = document.getElementById("response").value;
      OTR.sendResponse(context, response);
      OTR.authUpdate(context, contactInfo.progress);
    } else {
      throw new Error("Unreachable!");
    }
    return true;
  },

  cancel() {
    if (mode === "ask") {
      let context = OTR.getContext(uiConv.target);
      OTR.abortSMP(context);
      // Close the ask-auth notification if it was previously triggered.
      OTR.notifyObservers(
        {
          context,
        },
        "otr:cancel-ask-auth"
      );
    }
  },

  oninput(e) {
    document.querySelector("dialog").getButton("accept").disabled = !e.value;
  },

  how() {
    let how = document.getElementById("howOption").selectedItem.value;
    switch (how) {
      case "questionAndAnswer":
        this.oninput(document.getElementById("answer"));
        break;
      case "sharedSecret":
        this.oninput(document.getElementById("secret"));
        break;
      case "manualVerification":
        this.oninput({ value: true });
        break;
    }
    showSection(how);
  },
};
