import Choices from "choices.js";
import { Sidebar } from "./js/sidebar";
import "./scss/app.scss";
export interface choiceMap {
  [details: string]: Choices;
}

declare var loggedin_user_id: string;
let choiceObjects: choiceMap = {};
let boat_in_ottensheim = true;
let boat_reserved_today = true;

document.addEventListener("DOMContentLoaded", function () {
  changeTheme();
  initcolorTheme();
  initSearch();
  initSidebar();
  initToggle();
  replaceStrings();
  initChoices();
  initBoatActions();
  selectBoatChange();
  addRelationMagic(<HTMLElement>document.querySelector("body"));
  reloadPage();
  setCurrentdate(<HTMLInputElement>document.querySelector("#departure"));
});

function changeTheme() {
  let toggleBtn = <HTMLElement>document.querySelector("#theme-toggle-js");

  if (toggleBtn) {
    toggleBtn.addEventListener("click", function () {
      if (toggleBtn.dataset.theme === "light") {
        setTheme("dark", true);
      } else {
        setTheme("light", true);
      }
    });
  }
}

/***
 * init javascript
 * 1) detect native color scheme or use set theme in local storage
 * 2) detect view (desktop or responsive) if on mobile device with touch screen
 * 3) set base font size to 112.5% -> 18px
 */
function initcolorTheme() {
  colorThemeWatcher();
  let theme = localStorage.getItem("theme");
  if (theme == null || theme === "auto") {
    if (
      window.matchMedia &&
      window.matchMedia("(prefers-color-scheme: dark)").matches
    ) {
      setTheme("dark", false);
    } else {
      setTheme("light", false);
    }
  } else {
    setTheme(theme);
  }
}

/***
 * Listener operating system native color configuration
 */
function colorThemeWatcher() {
  try {
    window
      .matchMedia("(prefers-color-scheme: dark)")
      .addEventListener("change", (e) => {
        setTheme(e.matches ? "dark" : "light");
      });
  } catch {
    console.warn("color theme watcher not supported");
  }
}

/**
 * Define color scheme, colors without losing the base font size configuration
 * and add data-theme to html tag
 * @param theme
 */
function setTheme(theme: string, setLocalStorage = true) {
  let toggleBtn = document.querySelector("#theme-toggle-js");

  if (setLocalStorage) {
    localStorage.setItem("theme", theme);
  }
  if (toggleBtn) toggleBtn.setAttribute("data-theme", theme);

  if (
    document.documentElement.classList.contains("dark") &&
    theme === "light"
  ) {
    document.documentElement.classList.remove("dark");
  } else if (theme === "dark") {
    document.documentElement.classList.add("dark");
  }
}

function setCurrentdate(input: HTMLInputElement) {
  if (input) {
    const now = new Date();
    const formattedDateTime = `${now.getFullYear()}-${String(
      now.getMonth() + 1
    ).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}T${String(
      now.getHours()
    ).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;

    input.value = formattedDateTime;
  }
}

interface ChoiceBoatEvent extends Event {
  detail: {
    value: string;
    label: string;
    customProperties: {
      amount_seats: number;
      owner: number;
      default_destination: string;
      boat_in_ottensheim: boolean;
      boat_reserved_today: boolean;
      default_handoperated: boolean;
      convert_handoperated_possible: boolean;
    };
  };
}

function selectBoatChange() {
  const boatSelect = <HTMLSelectElement>document.querySelector("#boat_id");

  if (boatSelect) {
    const boatChoice = new Choices(boatSelect, {
      loadingText: "Wird geladen...",
      noResultsText: "Keine Ergebnisse gefunden",
      noChoicesText: "Keine Ergebnisse gefunden",
      itemSelectText: "Zum Auswählen klicken",
    } as any);

    boatSelect.addEventListener(
      "addItem",
      function (e) {
        const event = e as ChoiceBoatEvent;
        boat_reserved_today = event.detail.customProperties.boat_reserved_today;
        if (boat_reserved_today) {
          alert(
            event.detail.label.trim() +
              " wurde heute reserviert. Bitte kontrolliere, dass du die Reservierung nicht störst."
          );
        }
        boat_in_ottensheim = event.detail.customProperties.boat_in_ottensheim;

        const amount_seats = event.detail.customProperties.amount_seats;
        setMaxAmountRowers("newrower", amount_seats);

        let only_steering = <HTMLSelectElement>(
          document.querySelector("#shipmaster_only_steering")
        );
        if (event.detail.customProperties.default_handoperated) {
          only_steering.setAttribute("checked", "true");
        } else {
          only_steering.removeAttribute("checked");
        }

        if (event.detail.customProperties.convert_handoperated_possible) {
          only_steering.removeAttribute("readonly");
        } else {
          only_steering.setAttribute("readonly", "readonly");
        }

        const destination = <HTMLSelectElement>(
          document.querySelector("#destination")
        );
        destination.value = event.detail.customProperties.default_destination;

        if (event.detail.customProperties.owner) {
          choiceObjects["newrower"].setChoiceByValue(
            event.detail.customProperties.owner.toString()
          );

          if (event.detail.value === "36") {
            /** custom code for Etsch */
            choiceObjects["newrower"].setChoiceByValue("81");
          }
        } else if (typeof loggedin_user_id !== "undefined") {
          const currentSelection = choiceObjects["newrower"].getValue();
          let selectedItemsCount: number;
          if (Array.isArray(currentSelection)) {
            selectedItemsCount = currentSelection.length;
          } else {
            selectedItemsCount = currentSelection !== undefined ? 1 : 0;
          }
          if (selectedItemsCount == 0) {
            choiceObjects["newrower"].setChoiceByValue(loggedin_user_id);
          }
        }

        const inputElement = document.getElementById(
          "departure"
        ) as HTMLInputElement;
        const now = new Date();
        const formattedDateTime = `${now.getFullYear()}-${String(
          now.getMonth() + 1
        ).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}T${String(
          now.getHours()
        ).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;

        inputElement.value = formattedDateTime;

        const destinput = <HTMLInputElement>(
          document.querySelector("#destination")
        );
        destinput.dispatchEvent(new Event("input"));
      },
      false
    );

    choiceObjects[boatSelect.id] = boatChoice;
    choiceObjects["boat_id"] = boatChoice;
  }
}

function reloadPage() {
  if (!window.location.href.includes("ergo")) {
    let pageTitle = document.title;
    let attentionMessage = "Riemen- und Dollenbruch";

    document.addEventListener("visibilitychange", function () {
      let isPageActive = !document.hidden;

      if (!isPageActive) {
        document.title = attentionMessage;
      } else {
        document.title = pageTitle;
        location.reload();
      }
    });
  }
}

function setMaxAmountRowers(name: string, rowers: number) {
  if (choiceObjects[name]) {
    //choiceObjects[name].removeActiveItems(-1);
    let curSelection = choiceObjects[name].getValue(true);
    let amount_to_delete = (<any>curSelection).length - rowers;

    if (amount_to_delete > 0) {
      let to_delete = (<any>curSelection).slice(-amount_to_delete);
      for (let del of to_delete) {
        choiceObjects[name].removeActiveItemsByValue(del);
      }
    }

    let input = <HTMLElement>document.querySelector("#" + name);
    if (input) {
      choiceObjects[name].config.maxItemCount = rowers;
      if (rowers === 0) {
        choiceObjects[name].disable();
        input.parentElement?.parentElement?.parentElement?.classList.add(
          "hidden"
        );
        input.parentElement?.parentElement?.parentElement?.classList.add(
          "md:block"
        );
        input.parentElement?.parentElement?.parentElement?.classList.add(
          "opacity-50"
        );
      } else {
        choiceObjects[name].enable();
        input.parentElement?.parentElement?.parentElement?.classList.remove(
          "hidden"
        );
        input.parentElement?.parentElement?.parentElement?.classList.remove(
          "md:block"
        );
        input.parentElement?.parentElement?.parentElement?.classList.remove(
          "opacity-50"
        );
      }
    }

    let shipmaster = <HTMLElement>(
      document.querySelector("#shipmaster-" + name + "js")
    );
    let steering_person = <HTMLElement>(
      document.querySelector("#steering_person-" + name + "js")
    );
    if (rowers == 1) {
      if (shipmaster.parentNode) {
        (<HTMLElement>shipmaster.parentNode).classList.add("hidden");
      }
      shipmaster.removeAttribute("required");

      if (steering_person.parentNode) {
        (<HTMLElement>steering_person.parentNode).classList.add("hidden");
      }
      steering_person.removeAttribute("required");
    } else {
      if (shipmaster.parentNode) {
        (<HTMLElement>shipmaster.parentNode).classList.remove("hidden");
      }
      shipmaster.setAttribute("required", "required");

      if (steering_person.parentNode) {
        (<HTMLElement>steering_person.parentNode).classList.remove("hidden");
      }
      steering_person.setAttribute("required", "required");
    }
  }
}

function initBoatActions() {
  const boatSelects = document.querySelectorAll(
    '.boats-js[data-onclick="true"]'
  );
  if (boatSelects) {
    Array.prototype.forEach.call(boatSelects, (select: HTMLInputElement) => {
      select.addEventListener("click", function () {
        if (select.dataset.seats) {
          if (select.dataset.id) {
            choiceObjects["boat_id"].setChoiceByValue(select.dataset.id);
          }

          window.scrollTo(0, 0);
        }
      });
    });
  }
}

function initChoices() {
  const selects = document.querySelectorAll('select[data-init="true"]');
  if (selects) {
    Array.prototype.forEach.call(selects, (select: HTMLInputElement) => {
      initNewChoice(select);
    });
  }
}

interface ChoiceEvent extends Event {
  detail: {
    value: string;
    label: string;
    customProperties: {
      is_cox: boolean;
      steers: boolean;
      cox_on_boat: boolean;
      is_racing: boolean;
    };
  };
}

function initNewChoice(select: HTMLInputElement) {
  let seats = 0;
  if (select.dataset && select.dataset.seats) {
    seats = +select.dataset.seats;
  }

  let shipmaster = <HTMLElement>(
    document.querySelector("#shipmaster-" + select.id + "js")
  );
  let steering_person = <HTMLElement>(
    document.querySelector("#steering_person-" + select.id + "js")
  );
  if (seats == 1) {
    if (shipmaster.parentNode) {
      (<HTMLElement>shipmaster.parentNode).classList.add("hidden");
    }
    shipmaster.removeAttribute("required");

    if (steering_person.parentNode) {
      (<HTMLElement>steering_person.parentNode).classList.add("hidden");
    }
    steering_person.removeAttribute("required");
  } else {
    if (shipmaster.parentNode) {
      (<HTMLElement>shipmaster.parentNode).classList.remove("hidden");
    }
    shipmaster.setAttribute("required", "required");

    if (steering_person.parentNode) {
      (<HTMLElement>steering_person.parentNode).classList.remove("hidden");
    }
    steering_person.setAttribute("required", "required");
  }
  const choice = new Choices(select, {
    searchFields: ["label", "value", "customProperties.searchableText"],
    removeItemButton: true,
    loadingText: "Wird geladen...",
    noResultsText: "Keine Ergebnisse gefunden",
    noChoicesText: "Keine Ergebnisse gefunden",
    itemSelectText: "Zum Auswählen klicken",
    placeholderValue: "Ruderer auswählen",
    maxItemCount: seats,
    maxItemText: (maxItemCount) => {
      return `Nur ${maxItemCount} Ruderer können hinzugefügt werden`;
    },
    callbackOnInit: function () {
      this._currentState.items.forEach(function (obj) {
        if (boat_in_ottensheim && obj.customProperties) {
          if (obj.customProperties.is_racing) {
            const coxSelect = <HTMLSelectElement>(
              document.querySelector("#shipmaster-" + select.id + "js")
            );
            var new_option = new Option(obj.label, obj.value);
            if (obj.customProperties.cox_on_boat) {
              new_option.selected = true;
            }
            coxSelect.add(new_option);
          }
        }
        if (obj.customProperties && obj.customProperties.is_cox) {
          const coxSelect = <HTMLSelectElement>(
            document.querySelector("#shipmaster-" + select.id + "js")
          );
          var new_option = new Option(obj.label, obj.value);
          if (obj.customProperties.cox_on_boat) {
            new_option.selected = true;
          }
          coxSelect.add(new_option);
        }
        const steeringSelect = <HTMLSelectElement>(
          document.querySelector("#steering_person-" + select.id + "js")
        );
        if (steeringSelect) {
          var new_option = new Option(obj.label, obj.value);
          if (obj.customProperties && obj.customProperties.steers) {
            new_option.selected = true;
          }
          steeringSelect.add(new_option);
        }
      });
    },
  });
  choiceObjects[select.id] = choice;

  select.addEventListener(
    "addItem",
    function (e) {
      const event = e as ChoiceEvent;
      const user_id = event.detail.value;
      const name = event.detail.label;

      if (boat_in_ottensheim && event.detail.customProperties.is_racing) {
        if (event.detail.customProperties.is_racing) {
          const coxSelect = <HTMLSelectElement>(
            document.querySelector("#shipmaster-" + select.id + "js")
          );
          if (coxSelect) {
            coxSelect.add(new Option(name, user_id));
          }
        }
      }
      if (event.detail.customProperties.is_cox) {
        const coxSelect = <HTMLSelectElement>(
          document.querySelector("#shipmaster-" + select.id + "js")
        );
        if (coxSelect) {
          coxSelect.add(new Option(name, user_id));
        }
      }

      const steeringSelect = <HTMLSelectElement>(
        document.querySelector("#steering_person-" + select.id + "js")
      );
      if (steeringSelect) {
        steeringSelect.add(new Option(name, user_id));
      }
    },
    false
  );

  select.addEventListener(
    "removeItem",
    function (e) {
      const event = e as ChoiceEvent;

      const user_id = event.detail.value;

      const coxSelect = <HTMLSelectElement>(
        document.querySelector("#shipmaster-" + select.id + "js")
      );
      if (coxSelect) {
        for (var i = 0; i < coxSelect.length; i++) {
          if (coxSelect.options[i].value == user_id) coxSelect.remove(i);
        }
      }

      const steeringSelect = <HTMLSelectElement>(
        document.querySelector("#steering_person-" + select.id + "js")
      );
      if (steeringSelect) {
        for (var i = 0; i < steeringSelect.length; i++) {
          if (steeringSelect.options[i].value == user_id)
            steeringSelect.remove(i);
        }
      }
    },
    false
  );

  choiceObjects[select.id] = choice;
}

function initToggle() {
  // get filter btns & set object sessionStorage
  const btns = <NodeListOf<HTMLButtonElement>>(
    document.querySelectorAll(".filter-trips-js")
  );
  let filterObject = new Map();

  if (btns) {
    Array.prototype.forEach.call(btns, (btn: HTMLButtonElement) => {
      filterObject.set(btn.dataset.action, btn.ariaPressed);

      btn.addEventListener("click", () => {
        let filter = sessionStorage.getItem("tripsFilter");
        if (filter) {
          let filterMap = new Map(JSON.parse(filter));
          for (let entry of filterMap.entries()) {
            if (entry[0] === btn.dataset.action && entry[1] !== "true") {
              filterMap.set(entry[0], "true");
            } else {
              filterMap.set(entry[0], "false");
            }
          }
          sessionStorage.setItem(
            "tripsFilter",
            JSON.stringify(Array.from(filterMap.entries()))
          );
        }
        resetFilteredElements();
        if (btn.getAttribute("aria-pressed") === "false") {
          Array.prototype.forEach.call(btns, (b: HTMLButtonElement) => {
            b.setAttribute("aria-pressed", "false");
          });
          triggerFilterAction(btn.dataset.action);
        } else {
          btn.setAttribute("aria-pressed", "false");
        }
      });
    });
  }

  let filter = sessionStorage.getItem("tripsFilter");
  if (filter) {
    let filterMap = new Map(JSON.parse(filter));
    for (let entry of filterMap.entries()) {
      if (entry[1] === "true") {
        triggerFilterAction(entry[0]);
      }
    }
  } else {
    sessionStorage.setItem(
      "tripsFilter",
      JSON.stringify(Array.from(filterObject.entries()))
    );
  }
}

function resetFilteredElements() {
  const hiddenElements = document.querySelectorAll(".reset-js.hidden");
  if (hiddenElements) {
    Array.prototype.forEach.call(
      hiddenElements,
      (hiddenElement: HTMLButtonElement) => {
        hiddenElement.classList.remove("hidden");
      }
    );
  }
}

function triggerFilterAction(activeFilter: any) {
  const activeBtn = document.querySelector(
    'button[data-action="' + activeFilter + '"]'
  );
  if (activeBtn) {
    activeBtn.setAttribute("aria-pressed", "true");

    filterAction(activeFilter);
  }
}

function filterAction(activeFilter: string) {
  switch (activeFilter) {
    case "filter-days": {
      filterDays();
      break;
    }
    case "filter-coxs": {
      filterCoxs();
      break;
    }
  }
}

function filterDays() {
  const daysNoTrips = document.querySelectorAll('div[data-trips="0"]');
  Array.prototype.forEach.call(daysNoTrips, (day: HTMLElement) => {
    day.classList.toggle("hidden");
  });
}

function filterCoxs() {
  const noCoxNeeded = document.querySelectorAll('div[data-coxneeded="false"]');
  Array.prototype.forEach.call(noCoxNeeded, (notNeeded: HTMLElement) => {
    notNeeded.classList.toggle("hidden");
  });
}

function initSearch() {
  const input = <HTMLInputElement>document.querySelector("#filter-js");

  if (input) {
    filterElements(input.value);

    input.addEventListener("input", () => {
      filterElements(input.value);
    });
  }
}

function filterElements(input: string) {
  const elements = document.querySelectorAll('div[data-filterable="true"]');
  let resultWrapper = <HTMLElement>document.querySelector("#filter-result-js"),
    amountShownElements = 0;

  Array.prototype.forEach.call(elements, (element: HTMLElement) => {
    // set both strings (input & dataset filter) to lowercase to not be case sensitive
    let filterString = element.dataset.filter?.toLocaleLowerCase();

    // bulk hide all elements
    element.style.display = "none";

    // show if input matches
    if (filterString?.includes(input.toLocaleLowerCase())) {
      element.style.display = "flex";
      amountShownElements++;
    }
  });

  if (resultWrapper) {
    resultWrapper.innerHTML =
      amountShownElements === 0
        ? "Kein Ergebnis gefunden"
        : "<strong>" +
          amountShownElements +
          "</strong>" +
          (amountShownElements > 1 ? " Ergebnisse" : " Ergebnis") +
          " gefunden";
  }
}

function initSidebar() {
  const sidebarTrigger = <NodeListOf<HTMLElement>>(
    document.querySelectorAll("[data-trigger]")
  );

  if (sidebarTrigger) {
    Array.prototype.forEach.call(
      sidebarTrigger,
      (triggerElement: HTMLElement) => {
        if (triggerElement.dataset.trigger) {
          const sidebar = new Sidebar(triggerElement.dataset.trigger);

          triggerElement.addEventListener("click", (e) => {
            e.preventDefault();
            if (triggerElement.dataset.trigger === "sidebar") {
              initTripSidebar(triggerElement);
            }

            sidebar.toggle();
          });
        }
      }
    );
  }
}

function initTripSidebar(triggerElement: HTMLElement) {
  const sidebarElement = <HTMLElement>document.querySelector("#sidebar");
  if (
    sidebarElement &&
    triggerElement.dataset.body &&
    triggerElement.dataset.header
  ) {
    let body = <HTMLElement>document.querySelector(triggerElement.dataset.body);
    let bodyElement = <HTMLElement>body.cloneNode(true);
    let bodyContainerElement = <HTMLElement>(
      sidebarElement.querySelector(".body-js")
    );

    /* Quickfix duplicate ids checkboxes */
    const checkboxes = <NodeListOf<HTMLElement>>(
      bodyElement.querySelectorAll('input[type="checkbox"]')
    );

    Array.prototype.forEach.call(checkboxes, (checkbox: HTMLElement) => {
      if (checkbox) {
        checkbox.parentElement?.setAttribute("for", checkbox.id + "js");
        checkbox.id += "js";
      }
    });

    const prefixedContent = <NodeListOf<HTMLElement>>(
      bodyElement.querySelectorAll(".change-id-js")
    );
    Array.prototype.forEach.call(prefixedContent, (content: HTMLElement) => {
      if (content) {
        content.id += "js";

        if (content.dataset.relation) {
          content.dataset.relation += "js";
        }
      }
    });

    if (bodyContainerElement) {
      bodyContainerElement.innerHTML = "";
      bodyContainerElement.append(bodyElement);

      addRelationMagic(bodyElement);
    }
    if (triggerElement.dataset.day) {
      let hiddenElement = <HTMLInputElement>(
        bodyElement.querySelector(".day-js")
      );
      if (hiddenElement) {
        hiddenElement.value = triggerElement.dataset.day;
      }
    }

    let headerElement = sidebarElement.querySelector(".header-js");
    if (headerElement) {
      headerElement.innerHTML = triggerElement.dataset.header;
    }
    const selects = bodyElement.querySelectorAll("select[multiple]");
    if (selects) {
      Array.prototype.forEach.call(selects, (select: HTMLInputElement) => {
        initNewChoice(select);
      });
    }
  }
  const defaultDateTimes = <NodeListOf<HTMLInputElement>>(
    document.querySelectorAll(".current-date-time")
  );
  defaultDateTimes.forEach((defaultDateTime) => {
    setCurrentdate(defaultDateTime);
  });
}

function addRelationMagic(bodyElement: HTMLElement) {
  const fields = bodyElement.querySelectorAll(".set-distance-js");

  if (fields) {
    Array.prototype.forEach.call(fields, (field: HTMLInputElement) => {
      if (field.dataset.relation) {
        const relatedField = <HTMLInputElement>(
          bodyElement.querySelector("#" + field.dataset.relation)
        );
        if (relatedField) {
          field.addEventListener("input", (e) => {
            e.preventDefault();
            const dataList = <HTMLDataListElement>(
              document.querySelector("#destinations")
            );
            if (dataList) {
              var option = Array.prototype.find.call(
                dataList.options,
                function (option) {
                  return option.value === field.value;
                }
              );

              if (option && option.value !== "") {
                // Get distance
                const distance = option.getAttribute("distance");
                if (distance && relatedField.value === "")
                  relatedField.value = distance;
              }
            }
          });
        }
      }
    });
  }
}

function replaceStrings() {
  const weekdays = document.querySelectorAll(".weekday-js");
  Array.prototype.forEach.call(weekdays, (weekday: HTMLElement) => {
    weekday.innerHTML = weekday.innerHTML.replace("Freitag", "Markttag");
  });
}