"use strict";

function pluginit(KorAPugin) {
  var container = document.querySelector(".container");
  if (!container) return;

  var serviceURL = container.dataset.serviceUrl;
  var cookieName = container.dataset.cookieName || "km-config";
  var requestMappingDivs = container.querySelectorAll('.mapping[data-mode="request"]');
  var responseMappingDivMap = {};
  var requestCfgPreview = container.querySelector(".request-cfg-preview");
  var responseCfgPreview = container.querySelector(".response-cfg-preview");

  var responseMappingDivs = container.querySelectorAll('.mapping[data-mode="response"]');
  for (var i = 0; i < responseMappingDivs.length; i++) {
    responseMappingDivMap[responseMappingDivs[i].dataset.id] = responseMappingDivs[i];
  }

  // Cookie helpers

  function readCookie() {
    var prefix = cookieName + "=";
    var parts = document.cookie.split("; ");
    for (var i = 0; i < parts.length; i++) {
      if (parts[i].indexOf(prefix) === 0) {
        try {
          return JSON.parse(decodeURIComponent(parts[i].substring(prefix.length)));
        } catch (e) {
          return null;
        }
      }
    }
    return null;
  }

  function writeCookie(state) {
    var value = encodeURIComponent(JSON.stringify(state));
    document.cookie = cookieName + "=" + value + "; path=/; SameSite=Lax; max-age=31536000";
  }

  function deleteCookie() {
    document.cookie = cookieName + "=; path=/; SameSite=Lax; max-age=0";
  }

  // Form state

  function reverseDir(dir) {
    return dir === "atob" ? "btoa" : "atob";
  }

  function rowFieldClasses(mode) {
    return {
      foundryA: "." + mode + "-foundryA",
      layerA: "." + mode + "-layerA",
      foundryB: "." + mode + "-foundryB",
      layerB: "." + mode + "-layerB",
      fieldA: "." + mode + "-fieldA",
      fieldB: "." + mode + "-fieldB",
      dirArrow: "." + mode + "-dir-arrow"
    };
  }

  function inputValue(parent, selector) {
    var el = parent.querySelector(selector);
    return el ? el.value : "";
  }

  function getModeState(div, mode) {
    var classes = rowFieldClasses(mode);
    var arrow = div.querySelector(classes.dirArrow);
    return {
      enabled: div.querySelector("." + mode + "-cb").checked,
      dir: arrow ? arrow.dataset.dir : "atob",
      foundryA: inputValue(div, classes.foundryA),
      layerA: inputValue(div, classes.layerA),
      foundryB: inputValue(div, classes.foundryB),
      layerB: inputValue(div, classes.layerB),
      fieldA: inputValue(div, classes.fieldA),
      fieldB: inputValue(div, classes.fieldB)
    };
  }

  function getFormState() {
    var state = { mappings: [] };

    for (var i = 0; i < requestMappingDivs.length; i++) {
      var requestDiv = requestMappingDivs[i];
      var responseDiv = responseMappingDivMap[requestDiv.dataset.id];
      var entry = {
        id: requestDiv.dataset.id
      };

      entry.request = getModeState(requestDiv, "request");
      entry.response = responseDiv ? getModeState(responseDiv, "response") : { enabled: false };

      state.mappings.push(entry);
    }

    return state;
  }

  // Restore form from cookie

  function setInputValue(parent, selector, value) {
    if (value === undefined) return;
    var el = parent.querySelector(selector);
    if (el) el.value = value;
  }

  function setArrowDirection(div, selector, dir) {
    var arrow = div.querySelector(selector);
    if (!arrow || !dir) return;
    arrow.dataset.dir = dir;
    arrow.textContent = dir === "atob" ? "\u2192" : "\u2190";
  }

  function restoreModeState(div, mode, modeState) {
    if (!modeState) return;
    var classes = rowFieldClasses(mode);
    var checkbox = div.querySelector("." + mode + "-cb");
    if (checkbox) checkbox.checked = !!modeState.enabled;
    setArrowDirection(div, classes.dirArrow, modeState.dir);
    setInputValue(div, classes.foundryA, modeState.foundryA);
    setInputValue(div, classes.layerA, modeState.layerA);
    setInputValue(div, classes.foundryB, modeState.foundryB);
    setInputValue(div, classes.layerB, modeState.layerB);
    setInputValue(div, classes.fieldA, modeState.fieldA);
    setInputValue(div, classes.fieldB, modeState.fieldB);
  }

  function restoreFormState(saved) {
    if (!saved || !saved.mappings) return;

    var byId = {};
    for (var i = 0; i < saved.mappings.length; i++) {
      byId[saved.mappings[i].id] = saved.mappings[i];
    }

    for (var i = 0; i < requestMappingDivs.length; i++) {
      var requestDiv = requestMappingDivs[i];
      var responseDiv = responseMappingDivMap[requestDiv.dataset.id];
      var entry = byId[requestDiv.dataset.id];
      if (!entry) continue;

      if (requestDiv.dataset.type !== "corpus") {
        // Backward compatibility with old cookie schema.
        if (entry.request && typeof entry.request === "object") {
          restoreModeState(requestDiv, "request", entry.request);
          if (responseDiv) {
            restoreModeState(responseDiv, "response", entry.response);
          }
        } else {
          var requestLegacy = {
            enabled: !!entry.request,
            dir: entry.dir || "atob",
            foundryA: entry.foundryA,
            layerA: entry.layerA,
            foundryB: entry.foundryB,
            layerB: entry.layerB
          };
          var responseLegacy = {
            enabled: !!entry.response,
            dir: reverseDir(entry.dir || "atob"),
            foundryA: entry.foundryA,
            layerA: entry.layerA,
            foundryB: entry.foundryB,
            layerB: entry.layerB
          };
          restoreModeState(requestDiv, "request", requestLegacy);
          if (responseDiv) {
            restoreModeState(responseDiv, "response", responseLegacy);
          }
        }
      } else {
        // Backward compatibility with old cookie schema.
        if (entry.request && typeof entry.request === "object") {
          restoreModeState(requestDiv, "request", entry.request);
          if (responseDiv) {
            restoreModeState(responseDiv, "response", entry.response);
          }
        } else {
          var requestCb = requestDiv.querySelector(".request-cb");
          var responseCb = responseDiv ? responseDiv.querySelector(".response-cb") : null;
          if (requestCb) {
            requestCb.checked = !!entry.request;
          }
          if (responseCb) {
            responseCb.checked = !!entry.response;
          }
        }
      }
    }
  }

  // cfg parameter building

  // Returns "" when the input matches its default (compact URL).
  function cfgFieldValue(div, inputSelector, defaultDataAttr) {
    var el = div.querySelector(inputSelector);
    if (!el) return "";
    var val = el.value;
    var def = div.dataset[defaultDataAttr] || "";
    return val === def ? "" : val;
  }

  function buildCfgParam(mode) {
    var parts = [];
    var classes = rowFieldClasses(mode);
    var mappingDivs = mode === "request" ? requestMappingDivs : responseMappingDivs;

    for (var i = 0; i < mappingDivs.length; i++) {
      var div = mappingDivs[i];
      var cbClass = mode === "request" ? ".request-cb" : ".response-cb";
      var cb = div.querySelector(cbClass);
      if (!cb || !cb.checked) continue;

      var id = div.dataset.id;
      var dir = "atob";
      var arrow = div.querySelector(classes.dirArrow);
      dir = arrow ? arrow.dataset.dir : "atob";

      if (div.dataset.type !== "corpus") {
        var fA = cfgFieldValue(div, classes.foundryA, "defaultFoundryA");
        var lA = cfgFieldValue(div, classes.layerA, "defaultLayerA");
        var fB = cfgFieldValue(div, classes.foundryB, "defaultFoundryB");
        var lB = cfgFieldValue(div, classes.layerB, "defaultLayerB");

        if (fA || lA || fB || lB) {
          parts.push(id + ":" + dir + ":" + fA + ":" + lA + ":" + fB + ":" + lB);
        } else {
          parts.push(id + ":" + dir);
        }
      } else {
        var fieldA = cfgFieldValue(div, classes.fieldA, "defaultFieldA");
        var fieldB = cfgFieldValue(div, classes.fieldB, "defaultFieldB");
        if (fieldA || fieldB) {
          parts.push(id + ":" + dir + ":" + fieldA + ":" + fieldB);
        } else {
          parts.push(id + ":" + dir);
        }
      }
    }

    return parts.join(";");
  }

  // Active state tracking

  var isPluginActive = false;
  var activeCheckbox = container.querySelector("#check-active");

  function setActiveState(value) {
    isPluginActive = !!value;
    if (activeCheckbox) {
      activeCheckbox.checked = isPluginActive;
    }
    syncPipes();
  }

  // Kalamar pipe registration

  function encodePathCfg(cfg) {
    return encodeURIComponent(cfg).replace(/%3A/gi, ':').replace(/%3B/gi, ';');
  }

  function buildPipeURL(pipeType, cfg) {
    if (!cfg) return "";
    return serviceURL.replace(/\/+$/, "") + "/" + pipeType + "/" + encodePathCfg(cfg);
  }

  var lastQueryPipe = null;
  var lastResponsePipe = null;

  function removePipes() {
    if (typeof KorAPugin === "undefined") return;
    if (lastQueryPipe) {
      KorAPlugin.sendMsg({ action: "pipe", job: "del", service: lastQueryPipe });
      lastQueryPipe = null;
    }
    if (lastResponsePipe) {
      KorAPlugin.sendMsg({ action: "pipe", job: "del-after", service: lastResponsePipe });
      lastResponsePipe = null;
    }
  }

  function registerPipes() {
    var queryCfg = buildCfgParam("request");
    var responseCfg = buildCfgParam("response");

    if (requestCfgPreview) {
      requestCfgPreview.value = queryCfg;
    }
    if (responseCfgPreview) {
      responseCfgPreview.value = responseCfg;
    }

    if (!isPluginActive) {
      removePipes();
      return;
    }

    var newQueryPipe = buildPipeURL("query", queryCfg);
    var newResponsePipe = buildPipeURL("response", responseCfg);

    if (newQueryPipe === lastQueryPipe && newResponsePipe === lastResponsePipe) return;

    if (typeof KorAPlugin !== "undefined") {
      if (newQueryPipe !== lastQueryPipe) {
        if (lastQueryPipe) {
          KorAPlugin.sendMsg({ action: "pipe", job: "del", service: lastQueryPipe });
        }
        if (newQueryPipe) {
          KorAPlugin.sendMsg({ action: "pipe", job: "add", service: newQueryPipe });
        }
      }
      if (newResponsePipe !== lastResponsePipe) {
        if (lastResponsePipe) {
          KorAPlugin.sendMsg({ action: "pipe", job: "del-after", service: lastResponsePipe });
        }
        if (newResponsePipe) {
          KorAPlugin.sendMsg({ action: "pipe", job: "add-after", service: newResponsePipe });
        }
      }
    }

    lastQueryPipe = newQueryPipe;
    lastResponsePipe = newResponsePipe;
  }

  function syncPipes() {
    if (isPluginActive) {
      registerPipes();
    } else {
      removePipes();
    }
  }

  // Change handler

  function onChange() {
    writeCookie(getFormState());
    registerPipes();
  }

  // Initialisation

  var saved = readCookie();
  if (saved) {
    restoreFormState(saved);
  }

  var checkboxes = container.querySelectorAll('input[type="checkbox"]:not(#check-active)');
  for (var i = 0; i < checkboxes.length; i++) {
    checkboxes[i].addEventListener("change", onChange);
  }

  var textInputs = container.querySelectorAll('input[type="text"]');
  for (var i = 0; i < textInputs.length; i++) {
    textInputs[i].addEventListener("input", onChange);
  }

  var arrows = container.querySelectorAll(".request-dir-arrow, .response-dir-arrow");
  for (var i = 0; i < arrows.length; i++) {
    (function (arrow) {
      arrow.addEventListener("click", function () {
        var next = reverseDir(arrow.dataset.dir);
        arrow.dataset.dir = next;
        arrow.textContent = next === "atob" ? "\u2192" : "\u2190";
        onChange();
      });
    })(arrows[i]);
  }

  // Reset button

  function resetForm() {
    for (var i = 0; i < checkboxes.length; i++) {
      checkboxes[i].checked = false;
    }

    for (var i = 0; i < textInputs.length; i++) {
      textInputs[i].value = "";
    }

    var requestArrows = container.querySelectorAll(".request-dir-arrow");
    for (var i = 0; i < requestArrows.length; i++) {
      requestArrows[i].dataset.dir = "atob";
      requestArrows[i].textContent = "\u2192";
    }
    var responseArrows = container.querySelectorAll(".response-dir-arrow");
    for (var i = 0; i < responseArrows.length; i++) {
      responseArrows[i].dataset.dir = "btoa";
      responseArrows[i].textContent = "\u2190";
    }

    deleteCookie();
    registerPipes();
  }


  var resetBtn = container.querySelector("#reset-btn");
  if (resetBtn) {
    resetBtn.addEventListener("click", resetForm);
  }

  // When the active checkbox in the iframe is toggled,
  // send the new state to the host button.
  if (activeCheckbox) {
    activeCheckbox.addEventListener("change", function () {
      isPluginActive = activeCheckbox.checked;
      if (typeof KorAPlugin !== "undefined") {
        KorAPlugin.sendMsg({
          action: "set",
          key: "Active",
          value: isPluginActive
        });
      }
      syncPipes();
    });
  }

  // Don't register pipes until we know the active state
    KorAPugin.requestMsg({
      'action': 'get',
      'key': 'Active'
    }, function (msg) {
      setActiveState(msg.value);
    });

    KorAPugin.onMessage = function(msg) {
      if (msg.action === 'state' && msg.key === 'active') {
        setActiveState(msg.value);
        return;
      }
    };
};
