//penser à de la récursion pour display none

import {
  CalendarEvents,
  ReaderObject,
} from "./adapters/reader/lisio-reader-adapter";
import LisioBroadcastChannelNames from "./enums/lisio-broadcast-channel-names";
import LisioBroadcastChannelMessagesNames from "./enums/lisio-broadcast-channel-message-names";
import { LisioBroadcastChannelController } from "./controllers/broadcastChannel/lisio-broadcast-channel-controller";

const domParser = new DOMParser();
const topSVG = domParser.parseFromString(
  `
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M14.0987 30.2495C14.0987 31.216 14.9499 31.9995 15.9999 31.9995C17.0498 31.9995 17.901 31.216 17.901 30.2495H14.0987ZM17.3444 4.51209C16.602 3.82866 15.3983 3.82865 14.6558 4.51206L2.55685 15.6489C1.81439 16.3323 1.81438 17.4404 2.55682 18.1238C3.29927 18.8072 4.503 18.8072 5.24546 18.1238L16.0001 8.22438L26.7545 18.124C27.4969 18.8074 28.7007 18.8074 29.4431 18.124C30.1855 17.4406 30.1857 16.3325 29.4431 15.6491L17.3444 4.51209ZM17.901 30.2495L17.9013 5.74953L14.099 5.7495L14.0987 30.2495H17.901Z" fill="white"/>
  <path d="M2 1.99976H30" stroke="white" stroke-width="4" stroke-linecap="round"/>
</svg>
`,
  "image/svg+xml",
);
const upSVG = domParser.parseFromString(
  `
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M13.8271 30C13.8271 31.1046 14.7999 32 15.9999 32C17.1998 32 18.1726 31.1046 18.1726 30H13.8271ZM17.5365 0.585798C16.688 -0.195257 15.3123 -0.195267 14.4638 0.585774L0.636396 13.3136C-0.212122 14.0946 -0.212133 15.361 0.63637 16.142C1.48488 16.9231 2.86057 16.9231 3.7091 16.142L16.0001 4.82842L28.2909 16.1422C29.1393 16.9233 30.5151 16.9233 31.3636 16.1423C32.212 15.3612 32.2123 14.0949 31.3636 13.3138L17.5365 0.585798ZM18.1726 30L18.1729 2.00002L13.8274 1.99998L13.8271 30H18.1726Z" fill="white"/>
</svg>
`,
  "image/svg+xml",
);
const homeSVG = domParser.parseFromString(
  `
  <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M20.6673 29.9998V18.2103C20.6673 17.8195 20.5034 17.4446 20.2117 17.1683C19.92 16.8919 19.5243 16.7366 19.1118 16.7366H12.8895C12.477 16.7366 12.0813 16.8919 11.7896 17.1683C11.4979 17.4446 11.334 17.8195 11.334 18.2103V29.9998" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
    <path d="M2 13.7893C1.99989 13.3605 2.09852 12.9369 2.289 12.548C2.47949 12.1591 2.75724 11.8142 3.10289 11.5375L13.9918 2.69684C14.5533 2.24723 15.2648 2.00055 16 2.00055C16.7352 2.00055 17.4467 2.24723 18.0082 2.69684L28.8971 11.5375C29.2428 11.8142 29.5205 12.1591 29.711 12.548C29.9015 12.9369 30.0001 13.3605 30 13.7893V27.0524C30 27.8341 29.6722 28.5838 29.0888 29.1365C28.5053 29.6893 27.714 29.9998 26.8889 29.9998H5.11111C4.28599 29.9998 3.49467 29.6893 2.91122 29.1365C2.32778 28.5838 2 27.8341 2 27.0524V13.7893Z" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
  </svg>
`,
  "image/svg+xml",
);
const history: string[] = [];
// const currentDate = new Date(Date.now());
const loadingImg =
  document.querySelector<HTMLImageElement>("img#lisio-loading");
let wasDisabled = false;
const calendarsLangDatas2 = {
  eventColors: [
    "#FF5733",
    "#FF6F00",
    "#FF8C00",
    "#FFA500",
    "#FFC300",
    "#FFD700",
    "#E6A700",
    "#D4A017",
    "#C19A6B",
    "#A67B5B",
    "#8B4513",
    "#6B4226",
    "#964B00",
    "#734F30",
    "#5A3E26",
    "#4B2C20",
    "#D2691E",
    "#CD853F",
    "#BC8F8F",
    "#DB7093",
    "#FF1493",
    "#FF69B4",
    "#FFB6C1",
    "#DC143C",
    "#B22222",
    "#8B0000",
    "#A52A2A",
    "#800000",
    "#556B2F",
    "#808000",
    "#9ACD32",
  ],
  fr: {
    months: [
      "Janvier",
      "Février",
      "Mars",
      "Avril",
      "Mai",
      "Juin",
      "Juillet",
      "Août",
      "Septembre",
      "Octobre",
      "Novembre",
      "Décembre",
    ],
    days: [
      "Lundi",
      "Mardi",
      "Mercredi",
      "Jeudi",
      "Vendredi",
      "Samedi",
      "Dimanche",
    ],
    longestMonthLength: 9,
    longestDayLength: 8,
  },
  en: {
    months: [
      "January",
      "February",
      "March",
      "April",
      "May",
      "June",
      "July",
      "August",
      "Septembre",
      "October",
      "November",
      "December",
    ],
    days: [
      "Monday",
      "Tuesday",
      "Wednesday",
      "Thursday",
      "Friday",
      "Saturday",
      "Sundaiy",
    ],
    longestMonthLength: 9,
    longestDayLength: 9,
  },
};

let navIntoPDF = "";
let isNavClosing = false;

const main = document.createElement("main");
document.body.appendChild(main);
const head1 = document.querySelector("head");
const meta = document.createElement("meta");
meta.setAttribute("http-equiv", "Content-Security-Policy");
meta.setAttribute("content", "img-src * data: blob:");
head1?.append(meta);
const style1 = document.createElement("style");
style1.textContent += `
body{margin:0;padding-top:65px;}
main{display: flex; flex-direction: column; background-color:#fff; padding: 0px 5%;}
h1, h2, h3{align-sef: center;}
h4, h5, h6{font-weight: bold;}
img{margin: 8px 0; border: 2px solid #000; border-radius:8px; padding: 4px; max-width: 100%; background-color: #ddd;}
img:hover{background-color: #949494;}
.d-none{display:none;}
.dropdown{cursor: pointer; max-width: 100%;}
.dropdown *:not(.d-none, summary, p){display:flex; flex-direction:column}
table{border-collapse: collapse; maring: 24px 0;}
table thead tr {background-color: #555; color: #fff; text-align: center;}
table tbody tr:nth-child(odd) {background-color: #f2f2f2;}
table tbody tr:nth-child(even) {background-color: #fff;}
form {display: flex; flex-direction: column; row-gap: 16px; margin: 24px 0;}
label {display: flex; flex-direction: row; align-items: center;}
[data-clickable], input[type="checkbox"], input[type="radio"] {cursor: pointer; color: #2b37e0; text-decoration: underline;}
.lisio-slider{display: flex; column-gap: 16px; row-gap: 16px; flex-wrap: wrap; justify-content: space-evenly}
.lisio-caption-slider{display: flex; flex-direction: column; align-items: center}

font{
  pointer-events: none;
}

details {
  display: flex;
  flex-direction: column;
  margin: 1rem 0;
  border: 1px solid #ccc;
  border-radius: 8px;
  background-color: #fff;
  min-width: 60ch;
  width: fit-content;
}

details div{
  display: flex;
  flex-direction: column;
  padding-inline: 1rem;
}

summary {
  display:flex;
  font-weight: bold;
  cursor: pointer;
  padding-inline: 0.5rem;
  border-radius: 8px;
  align-items: center;
}

summary p {
  display: block;
  margin: 0;
}
    
summary p.content {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 30ch;
}

summary:hover, summary:focus {
  background-color: #f0f8ff;
}

details[open] {
  border-color: #015e66;
  background-color: #f8f9fa;
}

details[open] summary p.content{
  visibility: hidden;
}

summary::marker {
  content: '';
}

summary p.summary-icon {
  font-size: 32px;
  color: #015e66;
  margin-right: 0.5rem;
}

form{
  box-shadow: 1px 1px 7px 1px #8b8686;
  border-radius: 1.5rem;
  border: 0;
  padding: 1.5rem;
}

div#arrows-container{
  position: fixed;
  right : 0;
  bottom : 10vh;
}

div#arrows-container2{
  position: fixed;
  left : 0;
  top : 0;
}

td{
  vertical-align: middle;
  text-align: center;
}
`;
head1?.append(style1);

const broadcastChannel = new LisioBroadcastChannelController(
  LisioBroadcastChannelNames.READER,
);
let domain: string;
let sources: Map<string, string>;
let ready = false;
let isMobile = false;

const intersectionObserver = new IntersectionObserver(intersectionCallback, {
  root: null,
  rootMargin: "0px 0px -95% 0px",
  threshold: 0.9,
});

const divArrowContainer = document.createElement("div");
divArrowContainer.attachShadow({ mode: "open" });
const shadowArrow = divArrowContainer.shadowRoot;
const shadowStyle = document.createElement("style");
// @media screen and (min-width: 200px) and (max-width: 980px) {
//     div#arrows-container{
//       top: 0;
//       height: 75%;
//       row-gap : 32px;
//     }
// }
shadowStyle.textContent = `
  :root{
    --theme-primary: ${
      __BUILD_TARGET__ === "extension"
        ? "#15548a"
        : //@ts-expect-error lisioConfig are global in page
          lisioConfig.userSettings.colorPrimary
    };
  }

  div#right-controls{
    display : flex;
    flex-direction : column;
    row-gap : 8px;
  }

  button{
    background-color: var(--theme-primary);
    border: none;
    border-radius: 25%;
    padding: 10px;
    cursor: pointer;
  }

  button svg{
    width: 24px;
    height: 24px;
    aspect-ratio: 1;
  }
`;
shadowArrow?.append(shadowStyle);
divArrowContainer.id = "arrows-container";
const rightContainer = document.createElement("div");
rightContainer.id = "right-controls";
shadowArrow?.append(rightContainer);
for (const name of ["top", "up", "down"]) {
  createArrow(name, rightContainer);
}
document.body.append(divArrowContainer);

let shadowArrow2: ShadowRoot | undefined;
if (__BUILD_TARGET__ !== "extension") {
  const shadowStyle2 = document.createElement("style");
  shadowStyle2.textContent = `
    :root{
      --theme-primary: ${
        //@ts-expect-error lisioConfig are global in page
        lisioConfig.userSettings.colorPrimary
      };
    }
  
    div#top-controls{
      display : flex;
      position : absolute;
      top : 0;
      left: 0;
      column-gap : 8px;
      background-color: #fff;
      width: 100vw;
      padding: 8px;
      box-shadow: 0px 5px 10px -5px #000000;
    }
  
    button{
      background-color: var(--theme-primary);
      border: none;
      border-radius: 25%;
      padding: 10px;
      cursor: pointer;
    }
  
    button svg{
      width: 24px;
      height: 24px;
      aspect-ratio: 1;
    }
  `;
  const divArrowContainer2 = document.createElement("div");
  divArrowContainer2.attachShadow({ mode: "open" });
  shadowArrow2 = divArrowContainer2.shadowRoot as ShadowRoot;
  const topContainer = document.createElement("div");
  topContainer.id = "top-controls";
  shadowArrow2?.append(topContainer);
  shadowArrow2?.append(shadowStyle2);
  divArrowContainer2.id = "arrows-container2";
  for (const name of ["back", "home"]) {
    createArrow(name, topContainer);
  }
  document.body.append(divArrowContainer2);
}

function createArrow(name: string, container: HTMLElement) {
  const button = document.createElement("button");
  if (name === "back") {
    const svg = upSVG.documentElement.cloneNode(true) as SVGElement;
    svg.style.transform = "rotate(-90deg)";
    button.title = "Retourner à la page précédente";
    button.append(svg);
  } else if (name === "top") {
    const svg = topSVG.documentElement.cloneNode(true);
    button.title = "Remonter au début de la page";
    button.append(svg);
  } else if (name === "up") {
    const svg = upSVG.documentElement.cloneNode(true);
    button.title = "Faire défiler vers le haut";
    button.append(svg);
  } else if (name === "down") {
    const svg = upSVG.documentElement.cloneNode(true) as SVGElement;
    svg.style.transform = "rotate(180deg)";
    button.title = "Faire défiler vers le bas";
    button.append(svg);
  } else if (name === "home") {
    const svg = homeSVG.documentElement.cloneNode(true);
    button.title = "Aller à la page d'accueil";
    button.append(svg);
  }
  button.addEventListener("click", () => {
    let scroll;
    if (name === "back") {
      if (history[history.length] === origin) {
        history.pop();
        window?.opener?.history?.go(-1);
      } else {
        broadcastChannel.sendGoBackMessage();
      }
    } else if (name === "top") {
      scroll = 0;
    } else if (name === "up") {
      scroll = window.scrollY - window.innerHeight;
    } else if (name === "down") {
      scroll = window.scrollY + window.innerHeight;
    } else if (name === "home" && window?.opener?.location?.href) {
      window.opener.location.href = domain;
    }
    window.scroll({ left: 0, top: scroll, behavior: "smooth" });
  });
  container.append(button);
}

function createDropdown() {
  const details = document.createElement("details");
  details.classList.add("dropdown");
  const summary = document.createElement("summary");
  summary.textContent = "";
  details.append(summary);
  main.append(details);
  return details;
}

function deconstructTable(node: ReaderObject, cache: ReaderObject[]) {
  if (
    !["thead", "tr", "tbody", "table", "th", "td"].includes(node.name || "")
  ) {
    cache.push(node);
  } else if (node.childNodes != undefined) {
    for (const child of node.childNodes) {
      deconstructTable(child, cache);
    }
  }
}

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_INIT_HTML,
  async (datas) => {
    const value = JSON.parse(datas) as {
      back: string;
      isMobile: boolean;
      texts: ReaderObject[];
      styles: Record<string, string>;
      domain: string;
      base64s: Record<string, string>;
      calendarLang: "fr" | "en";
    };
    history.push(value.back);
    isMobile = value.isMobile;
    const stylesheet = Array.from(document.styleSheets).find(
      (styleSheet) => styleSheet.href == null,
    );
    if (stylesheet != undefined) {
      for (const [selector, style] of Object.values(value.styles) as [
        string,
        string,
      ]) {
        stylesheet?.insertRule(`.${selector}{ ${style} }`);
      }
    }
    if (loadingImg != undefined) {
      loadingImg.style = "display: none";
    }
    ready = false;
    sources = new Map(Object.entries(value.base64s));
    window.scroll(0, 0);

    if (domain == undefined) {
      domain = value.domain;
    }
    for (const child of Array.from(main.children)) {
      if (
        child.localName !== "script" &&
        child.id !== "lisio-label" &&
        child.id !== "lisio-widget" &&
        child.localName !== "style"
      ) {
        child.remove();
      }
    }

    if (
      (value.texts as ReaderObject[]).filter((text) => text.name === "table")
        .length /
        value.texts.length >=
      0.5
    ) {
      for (let i = 0; i < value.texts.length; i++) {
        if (value.texts[i].name === "table") {
          const toAddBody: ReaderObject[] = [];
          deconstructTable(value.texts[i], toAddBody);
          value.texts.splice(i, 1, ...toAddBody);
        }
      }
    }

    let sliderDiv = undefined;
    let captionSliderDiv = undefined;
    for (const [className, style] of Object.entries(value.styles)) {
      Array.from(document.styleSheets)
        .find((styleSheet) => styleSheet.href == undefined)
        ?.insertRule(`.${className}{${style}}`);
    }

    let dropdown;
    for (const [i, tag] of value.texts.entries()) {
      if (dropdown == undefined && tag.isHidden) {
        dropdown = createDropdown();
      } else if (!tag.isHidden && dropdown != undefined) {
        const textChild = Array.from(dropdown.children).find(
          (child) => child.textContent?.trim() != "",
        );
        if (textChild == undefined) {
          dropdown.remove();
        } else {
          const summary = dropdown.querySelector<HTMLElement>("summary");
          if (summary != undefined) {
            const sliced = textChild.textContent?.trim().slice(0, 35);
            summary.textContent = `${
              sliced === "" ? "Afficher textes" : sliced
            }...`;
          }
        }
        dropdown = undefined;
      }
      if (tag.name === "img") {
        try {
          const img = createImage(
            tag,
            i === 0 ? undefined : value.texts[i - 1],
            dropdown,
            !tag.isInSlider,
          );
          if (tag.isInSlider && img != undefined) {
            if (sliderDiv == undefined) {
              sliderDiv = createSliderDiv();
            }
            if (tag.hasCaption) {
              captionSliderDiv = createCaptionSliderDiv();
              captionSliderDiv.append(img);
            } else {
              sliderDiv.append(img);
              sliderDiv.dataset.position = tag.position.toString();
            }
          }
        } catch (error) {
          console.log(error, tag);
          return;
        }
      } else if (tag.name === "video") {
        try {
          createVideo(tag, i === 0 ? undefined : value.texts[i - 1], dropdown);
        } catch (error) {
          console.log(error, tag);
          return;
        }
      } else if (tag.name === "table") {
        createTable(
          tag,
          tag.isHidden && dropdown != undefined ? dropdown : main,
        );
      } else if (tag.name === "form") {
        createForm(
          tag,
          tag.isHidden && dropdown != undefined ? dropdown : main,
          value.calendarLang,
        );
      } else if (
        tag.name === "object" ||
        tag.name === "embed" ||
        tag.name === "iframe"
      ) {
        const element = document.createElement(tag.name);
        element.dataset.position = tag.position.toString();
        if (
          element instanceof HTMLEmbedElement ||
          element instanceof HTMLIFrameElement
        ) {
          if (element instanceof HTMLIFrameElement) {
            if (tag.src?.includes("youtube")) {
              element.srcdoc = `<style>*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}</style><a href="${tag.src}"><img src="${import.meta.env.VITE_LISIO_DOMAIN}/solution/assets/youtube-placeholder.webp" alt='Cliquez 2 fois sur la vidéo pour lancer la lecture'><span>▶</span></a>`;
            }
            element.setAttribute("loading", tag.loading || "true");
          }
          element.src = tag.src || "";
        } else {
          element.data = tag.src || "";
        }
        element.width = tag.width || "-1";
        element.height = tag.height || "-1";
        main.append(element);
      } else if (tag.name === "calendar") {
        createCalendar(
          tag,
          tag.isHidden && dropdown != undefined ? dropdown : main,
          value.calendarLang,
        );
      } else {
        const parsed = domParser.parseFromString(
          tag.content || "",
          "text/html",
        );
        const element = document.createElement(tag.name || "div");
        for (const child of parsed.body.childNodes) {
          if (child.textContent?.trim() != "") {
            element.append(child.cloneNode(true));
          }
        }
        element.className = tag.classes || "";
        element.dataset.position = tag.position.toString();
        if (tag.name === "a") {
          element.dataset.blank = tag.blank;
          element.dataset.href = tag.href;
        }
        if (tag.isHidden) {
          if (sliderDiv) {
            main.append(sliderDiv);
            sliderDiv = undefined;
          }
          dropdown?.append(element);
        } else if (tag.isInSlider && captionSliderDiv && sliderDiv) {
          captionSliderDiv.append(element);
          sliderDiv.append(captionSliderDiv);
          captionSliderDiv = undefined;
          sliderDiv.dataset.position = tag.position.toString();
        } else {
          if (sliderDiv) {
            main.append(sliderDiv);
            sliderDiv = undefined;
          }
          main.append(element);
        }
        if (tag.clickable != undefined) {
          element.dataset.clickable = tag.clickable.toString();
          element.addEventListener("click", handleOnClick);
        }
        for (const child of element.querySelectorAll<HTMLElement>(
          "[data-lisio-clickable]",
        )) {
          child.dataset.clickable = child.dataset.lisioClickable;
          child.removeAttribute("data-lisio-clickable");
        }
        for (const child of element.querySelectorAll<HTMLElement>(
          "[data-clickable]",
        )) {
          child.addEventListener("click", handleOnClick);
        }
        intersectionObserver.observe(element);
      }
    }

    if (dropdown != undefined) {
      const textChild = Array.from(dropdown.children).find(
        (child) => child.textContent?.trim() != "",
      );
      if (textChild == undefined) {
        dropdown.remove();
      } else {
        const summary = dropdown.querySelector<HTMLElement>("summary");
        if (summary != undefined) {
          const sliced = textChild.textContent?.trim().slice(0, 35);
          summary.textContent = `${
            sliced === "" ? "Afficher textes" : sliced
          }...`;
        }
      }
      dropdown = undefined;
    }

    if (__BUILD_TARGET__ != "extension") {
      window.addEventListener("visibilitychange", () => {
        if (!isNavClosing && document.visibilityState === "hidden") {
          broadcastChannel.sendNavResponseMessage(wasDisabled);
        }
      });
    }
    ready = true;
    if (__BUILD_TARGET__ === "extension") {
      window.postMessage("send_end_init_html");
    }
    document.querySelector(".lisio-disable")?.addEventListener("click", () => {
      wasDisabled = true;
    });
    setTimeout(() => {
      let positionToScroll = 0;
      const firstH1 = value.texts.find((text) => text.name === "h1");
      if (firstH1 != undefined) {
        positionToScroll = firstH1.position;
      } else {
        const firstH2 = value.texts.find((text) => text.name === "h2");
        if (firstH2 != undefined) {
          positionToScroll = firstH2.position;
        } else {
          const textMore100Chars = value.texts.find(
            (text) =>
              typeof text.content === "string" && text.content.length >= 100,
          );
          if (textMore100Chars != undefined) {
            positionToScroll = textMore100Chars.position;
          }
        }
      }
      if (__BUILD_TARGET__ !== "extension") {
        const scrollTo = document.querySelector(
          `[data-position="${positionToScroll}"]`,
        );
        if (scrollTo != undefined) {
          const rect = scrollTo.getClientRects()[0];
          window.scrollTo({
            top:
              rect.top -
              (shadowArrow2
                ?.querySelector<HTMLDivElement>("div")
                ?.getBoundingClientRect()?.height || 0),
            behavior: "smooth",
          });
        }
      }
    }, 1000);
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_ANYONE_THERE,
  async (datas) => {
    const data = JSON.parse(datas);
    if (__BUILD_TARGET__ === "extension" ? true : domain === data.value) {
      broadcastChannel.sendReadyMessage();
    }
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_NEW_IMAGE,
  async (datas) => {
    const data = JSON.parse(datas);
    if (ready) {
      if (data.value.base64 != undefined) {
        sources.set(data.value.src, data.value.base64);
      }
      const img = document.querySelector<HTMLImageElement>(
        `[data-position="${data.value.position}"]`,
      );
      if (img != undefined) {
        if (data.value.src.includes("http")) {
          img.addEventListener("error", loadOriginImage);
        }
        img.dataset.src = data.value.src;
        img.src = data.value.base64;
        img.width = data.value.width;
        img.height = data.value.height;
      }
    }
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_NEW_NODES,
  async (datas) => {
    const data = JSON.parse(datas);
    if (ready) {
      for (const node of data.value) {
        if (node.alreadyExists) {
          const existingNode = document.querySelector<HTMLElement>(
            `[data-position="${node.position}"]`,
          );
          if (existingNode != undefined) {
            existingNode.innerHTML = node.content;
          }
        } else {
          let refNode;
          for (const a of Array.from(
            document.querySelectorAll<HTMLElement>("[data-position]"),
          ).filter(
            (elt) =>
              elt.dataset.position != undefined &&
              elt.dataset.position >= node.position,
          )) {
            if (a.dataset.position == node.position) {
              refNode = a;
            }
            a.dataset.position = (
              Number.parseInt(a.dataset.position || "-2") + 1
            ).toString();
          }
          const element = document.createElement(node.name);
          element.innerHTML = node.content;
          element.className = node.classes;
          element.dataset.position = node.position;
          element.dataset.clickable = node.clickable;
          intersectionObserver.observe(element);
          if (node.clickable != undefined) {
            element.addEventListener("click", handleOnClick);
          }
          if (refNode != undefined) {
            main.insertBefore(element, refNode);
          }
        }
      }
    }
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_REMOVE_NODES,
  async (datas) => {
    const data = JSON.parse(datas);
    if (ready) {
      for (const node of data.value) {
        if (node.alreadyExists) {
          const existingNode = document.querySelector<HTMLElement>(
            `[data-position="${node.position}"]`,
          );
          if (existingNode != undefined) {
            existingNode.innerHTML = node.content;
          }
        } else {
          const element = document.querySelector(
            `[data-position="${node.position}"]`,
          );
          if (element != undefined) {
            intersectionObserver.unobserve(element);
            element.remove();
            for (const a of Array.from(
              document.querySelectorAll<HTMLElement>("[data-position]"),
            ).filter(
              (elt) =>
                Number.parseInt(elt.dataset.position || "-1") >= node.position,
            )) {
              a.dataset.position = (
                Number.parseInt(a.dataset.position || "-1") - 1
              ).toString();
            }
          }
        }
      }
    }
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_MODIFIED_TEXT,
  async (datas) => {
    const data = JSON.parse(datas);
    if (ready) {
      const text = document.querySelector(
        `[data-position="${data.value.position}"]`,
      );
      if (text != undefined) {
        const nodeIterator = document.createNodeIterator(
          text,
          NodeFilter.SHOW_TEXT,
          {
            acceptNode(node) {
              return node.textContent?.trim() === ""
                ? NodeFilter.FILTER_REJECT
                : NodeFilter.FILTER_ACCEPT;
            },
          },
        );
        let child;
        for (let iChild = 0; iChild < data.value.childIndex; iChild++) {
          child = nodeIterator.nextNode();
        }
        if (child != undefined) {
          if (child.nodeType === Node.TEXT_NODE) {
            child.textContent = data.value.text;
          }
        }
      }
    }
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_CLOSE,
  async () => {
    // window.close();
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_NAVIGATE,
  async () => {
    ready = true;
    if (navIntoPDF === "") {
      for (const child of Array.from(main.children)) {
        if (
          child.localName !== "script" &&
          child.id !== "lisio-label" &&
          child.id !== "lisio-widget" &&
          child.localName !== "style"
        ) {
          child?.remove();
        }
      }
      if (loadingImg != undefined) {
        loadingImg.style = "display: block";
      }
    } else {
      navIntoPDF = "";
    }
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_EXIT,
  async () => {
    const response = window.confirm(
      " Vous quittez notre site web, le mode lecture va se fermer. Merci de votre visite.",
    );
    broadcastChannel.sendNavResponseMessage(response);
    if (response) {
      isNavClosing = true;
      history.pop();
      window.close();
    }
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_REFRESH_CALENDAR,
  async (datas) => {
    const data = JSON.parse(datas);
    const calendar = document.querySelector<HTMLElement>(
      `article[data-calendar-index="${data.value.iCalendar}"]`,
    )?.shadowRoot;
    if (calendar != undefined) {
      let i = 1;
      const monthYearElement = calendar.querySelector<HTMLElement>(
        "[data-month][data-year]",
      );
      for (const [day, clickable] of data.value.clickables.entries()) {
        if (day <= i) {
          const date = calendar.querySelector<HTMLElement>(
            `[data-date="${day}-${monthYearElement?.dataset.month}-${monthYearElement?.dataset.year}"]:not([data-clickable])`,
          );
          if (date != undefined && date.dataset.clickable != undefined) {
            date.dataset.clickable = clickable;
            date.addEventListener("click", handleOnClick);
          }
        }
        i++;
      }
    }
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_LOAD_PDF,
  async (datas) => {
    const data = JSON.parse(datas);
    navIntoPDF = data.value;
    const iframe = document.createElement("iframe");
    iframe.src = data.value;
    iframe.style.width = "100%";
    iframe.style.height = "100vh";
    if (loadingImg != undefined) {
      loadingImg.style.display = "none";
    }
    for (const child of Array.from(main.children)) {
      if (
        child.localName !== "script" &&
        child.id !== "lisio-label" &&
        child.id !== "lisio-widget" &&
        child.localName !== "style"
      ) {
        child.remove();
      }
    }
    main.append(iframe);
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_OPEN_DROPDOWN,
  async (datas) => {
    const data = JSON.parse(datas);
    document
      .querySelector(`[data-position="${data.value}"]`)
      ?.closest("details")
      ?.setAttribute("open", "true");
  },
);

broadcastChannel.attachHandler(
  LisioBroadcastChannelMessagesNames.BCMR_OPEN_DROPDOWN,
  async (datas) => {
    const data = JSON.parse(datas);
    document
      .querySelector(`[data-position="${data.value}"]`)
      ?.closest("details")
      ?.removeAttribute("open");
  },
);

function createSliderDiv() {
  const div = document.createElement("div");
  div.className = "lisio-slider";
  return div;
}

function createCaptionSliderDiv() {
  const div = document.createElement("div");
  div.className = "lisio-caption-slider";
  return div;
}

function loadOriginImage(event: Event) {
  if (
    event.target instanceof HTMLImageElement &&
    event.target.dataset.src != undefined
  ) {
    event.target.src = event.target.dataset.src;
    event.target.removeEventListener("error", loadOriginImage);
  }
}

function createImage(
  image: ReaderObject,
  previous: ReaderObject | undefined,
  dropdown: HTMLElement | undefined,
  autoInsert = true,
) {
  const img = document.createElement("img") as HTMLImageElement;
  const source = sources.get(image.src || "");
  if (source != undefined) {
    img.src = source;
  } else {
    img.src = image.src || "";
  }
  img.dataset.position = image.position.toString();
  img.width = Number.parseInt(image.width || "-1");
  img.height = Number.parseInt(image.height || "-1");
  img.style.objectFit = image.objectFit || "normal";
  img.style.objectPosition = image.objectPosition || "normal";
  img.style.cursor = image.cursor || "auto";
  img.style.display = image.display || "block";
  img.dataset.src = image.src;
  img.alt = image.alt || "";
  img.loading = "lazy";
  if (image.clickable != undefined) {
    img.dataset.clickable = image.clickable.toString();
    img.addEventListener("click", handleOnClick);
  }
  if (autoInsert) {
    if (dropdown) {
      dropdown.append(img);
    } else {
      if (image.insert === "after" && previous != undefined) {
        document
          .querySelector(`[data-position="${previous.position}"]`)
          ?.after(img);
      } else {
        main.prepend(img);
      }
    }
  } else {
    return img;
  }
}

function createVideo(
  vid: ReaderObject,
  previous: ReaderObject | undefined,
  dropdown: HTMLElement | undefined,
  autoInsert = true,
) {
  const video = document.createElement("video");
  const source = document.createElement("source");
  video.append(source);
  if (vid.src != undefined) {
    source.src = vid.src;
  } else {
    source.src = "";
  }
  video.dataset.position = vid.position.toString();
  video.width = Number.parseInt(vid.width || "-1");
  video.height = Number.parseInt(vid.height || "-1");
  video.controls = true;
  intersectionObserver.observe(video);
  if (autoInsert) {
    if (dropdown) {
      dropdown.append(video);
    } else {
      dropdown = undefined;
      if (previous != undefined && vid.insert === "after") {
        document
          .querySelector<HTMLElement>(`[data-position="${previous.position}"]`)
          ?.after(video);
      } else {
        main.prepend(video);
      }
    }
  } else {
    return video;
  }
}

function handleOnClick(event: Event) {
  event.preventDefault();
  if (
    event.target instanceof HTMLElement &&
    event.target.localName === "a" &&
    event.target?.dataset.blank === "true"
  ) {
    if (
      !confirm(
        "Un nouvel onglet va s'ouvrir, voulez vous continuer ? La liseuse va se fermer.",
      )
    ) {
      return;
    }
  }
  if (
    isMobile &&
    event.target instanceof HTMLElement &&
    event.target?.dataset.href != undefined
  ) {
    window.opener.location.href = event.target.dataset.href;
  } else if (!isMobile && event.target instanceof HTMLElement) {
    broadcastChannel.sendOnClickMessage({
      target: event.target.dataset.clickable || "-1",
      isShadowRootCalendar:
        event.target.dataset.isShadowRootCalendar === "true",
    });
  }
}

function handleOnChange(event: Event) {
  event.preventDefault();
  if (
    event.target instanceof HTMLTextAreaElement ||
    event.target instanceof HTMLInputElement ||
    event.target instanceof HTMLSelectElement
  ) {
    broadcastChannel.sendOnChangeMessage({
      target: event.target.dataset.change || "-1",
      value: event.target.value,
    });
  }
}

function createTable(data: ReaderObject, parent: HTMLElement) {
  if (data.name === "#text") {
    const node = document.createTextNode(data.content || "");
    parent.append(node);
  } else {
    let element =
      data.name === "img"
        ? createImage(data, undefined, undefined, false)
        : document.createElement(data.name || "div");
    if (data.name === "svg") {
      const value = data.value as unknown as {
        hash: string;
        width: string;
        height: string;
      };
      element = document.createElement("img");
      const source = sources.get(value.hash);
      if (source != undefined && element instanceof HTMLImageElement) {
        element.src = source;
        element.setAttribute("width", value.width);
        element.setAttribute("height", value.height);
      }
    }
    if (element != undefined) {
      element.dataset.position = data.position.toString();
      if (data.classes != undefined) {
        element.className = data.classes;
      }
      if (data.childNodes) {
        for (const child of data.childNodes) {
          createTable(child, element);
        }
      }
      if (data.content != undefined) {
        element.innerHTML = data.content;
      }
      if (data.clickable != undefined) {
        element.dataset.clickable = data.clickable.toString();
        element.addEventListener("click", handleOnClick);
      }
      parent.append(element);
    }
  }
}

function createForm(
  data: ReaderObject,
  parent: HTMLElement,
  calendarLang: "en" | "fr",
  checkboxDiv?: HTMLElement,
) {
  if (data.name === "#text") {
    const node = document.createTextNode(data.content || "");
    parent.append(node);
  } else if (data.name === "calendar") {
    createCalendar(data, parent, calendarLang);
  } else {
    let f = parent.append.bind(parent);
    if (checkboxDiv) {
      f = checkboxDiv.append.bind(checkboxDiv);
      checkboxDiv = undefined;
    }
    const element = document.createElement(data.name || "div");
    element.dataset.position = data.position.toString();
    if (data.id != undefined) {
      element.id = data.id;
    }
    if (data.for) {
      element.setAttribute("for", data.for);
    }
    if (data.type && element instanceof HTMLInputElement) {
      if (data.type === "checkbox") {
        if (parent.localName !== "label") {
          checkboxDiv = document.createElement("div");
          parent.append(checkboxDiv);
          f = checkboxDiv.prepend.bind(checkboxDiv);
        } else {
          f = parent.prepend.bind(parent);
        }
      }
      element.type = data.type;
    }
    if (data.placeholder) {
      element.setAttribute("placeholder", data.placeholder);
    }
    if (
      data.value &&
      (element instanceof HTMLInputElement ||
        element instanceof HTMLSelectElement ||
        element instanceof HTMLTextAreaElement)
    ) {
      element.value = data.value;
    }
    if (data.clickable != undefined) {
      element.dataset.clickable = data.clickable.toString();
      element.addEventListener("click", handleOnClick);
    }
    if (data.change != undefined) {
      element.dataset.change = data.change.toString();
      element.addEventListener("change", handleOnChange);
    }
    if (data.rows != undefined) {
      element.setAttribute("rows", data.rows);
    }
    if (data.cols != undefined) {
      element.setAttribute("cols", data.cols);
    }
    try {
      f(element);
    } catch (error) {
      console.log(element, error, f, parent);
    }
    if (data.childNodes && data.name !== "calendar") {
      for (const child of data.childNodes) {
        createForm(child, element, calendarLang, checkboxDiv);
      }
    }
  }
}

function intersectionCallback(entries: IntersectionObserverEntry[]) {
  for (const entry of entries) {
    if (
      entry.isIntersecting &&
      entry.target instanceof HTMLElement &&
      entry.target.dataset.position != undefined
    ) {
      broadcastChannel.sendScrollToMessage(entry.target.dataset.position);
    }
  }
}

function createCalendar(
  {
    position,
    iCalendar,
    isShadowRootCalendar,
    days,
    daysNumbers,
    events,
    prevButtonClickable,
    nextButtonClickable,
  }: ReaderObject,
  parent: HTMLElement,
  calendarLang: "en" | "fr",
) {
  const article = document.createElement("article");
  article.attachShadow({ mode: "open" });
  article.dataset.position = position.toString();
  article.dataset.calendarIndex = (iCalendar || -1).toString();
  parent.append(article);
  if (daysNumbers == undefined) {
    daysNumbers = [];
  }
  if (events == undefined) {
    events = [];
  }

  const shadowRoot = article.shadowRoot;

  const calendarStyle = document.createElement("style");
  calendarStyle.textContent = `
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 20px;
    }

    a{color: #2b37e0; text-decoration: underline;}

    #calendar {
      display: flex:
      flex-direct: column;
      margin: 0 auto;
    }
    #calendar-body{
      display: grid;
      grid-template-rows: 1fr;
      grid-template-columns: repeat(7, 1fr);
      gap: 5px;
    }
    #calendar-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 10px;
      font-size: 24px;
      font-weight: bold;
    }
    #calendar-header button {
      background-color: #007BFF;
      color: white;
      border: none;
      padding: 5px 10px;
      cursor: pointer;
      border-radius: 5px;
    }
    #calendar-header button:focus {
      outline: 2px solid #0056b3;
    }
    [data-clickable]{
      cursor: pointer;
    }
    .day {
      text-align: center;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 5px;
      background-color: #f9f9f9;
    }
    .day:focus {
      outline: 2px solid #007BFF;
      background-color: #e9ecef;
    }
    #day-header {
      display: grid;
      grid-template-rows: 1fr;
      grid-template-columns: repeat(7, 1fr);
      text-align: center;
    }
    .day-text {
      font-weight: bold;
      text-transform: uppercase;
    }
    .today {
      background-color: #007BFF;
      color: white;
    }
    div.calendar-events{
        border-radius: 8px;
        padding: 8px;
    }
`;
  shadowRoot?.append(calendarStyle);

  const calendarMain = document.createElement("main");
  calendarMain.id = "calendar";
  calendarMain.role = "grid";
  shadowRoot?.append(calendarMain);

  const calendarHeader = document.createElement("header");
  calendarHeader.id = "calendar-header";
  calendarHeader.role = "row";
  calendarMain.append(calendarHeader);

  const prevButton = document.createElement("button");
  prevButton.id = "prevMonth";
  prevButton.ariaLabel = "Mois précédent";
  prevButton.textContent = "◀";
  prevButton.role = "gridcell";
  prevButton.dataset.isShadowRootCalendar = `${isShadowRootCalendar}`;
  if (prevButtonClickable != undefined) {
    prevButton.dataset.clickable = prevButtonClickable;
  }
  calendarHeader.append(prevButton);

  const monthYear = document.createElement("p");
  monthYear.id = "monthYear";
  monthYear.ariaLive = "polite";
  monthYear.role = "gridcell";
  calendarHeader.append(monthYear);

  const nextButton = document.createElement("button");
  nextButton.id = "nextMonth";
  nextButton.ariaLabel = "Mois suivant";
  nextButton.textContent = "▶";
  nextButton.role = "gridcell";
  nextButton.dataset.isShadowRootCalendar = `${isShadowRootCalendar}`;
  if (nextButtonClickable != undefined) {
    nextButton.dataset.clickable = nextButtonClickable;
  }
  calendarHeader.append(nextButton);

  const calendarSection = document.createElement("section");
  // calendarSection = "calendar";
  calendarSection.setAttribute("aria-labelledby", "monthYear");
  calendarSection.role = "rowgroup";
  calendarMain.append(calendarSection);

  const dayHeader = document.createElement("header");
  dayHeader.id = "day-header";
  dayHeader.role = "row";
  calendarSection.append(dayHeader);

  const beginM =
    days == undefined || days.length === 0
      ? true
      : new RegExp(
          `${calendarsLangDatas2[calendarLang].days[0].charAt(0)}`,
          "i",
        ).test(days[0].content || "");

  if (!beginM) {
    const sunday = calendarsLangDatas2[calendarLang].days.pop();
    if (sunday != undefined) {
      calendarsLangDatas2[calendarLang].days.unshift(sunday);
    }
  }
  for (const day of calendarsLangDatas2[calendarLang].days) {
    const dayText = document.createElement("p");
    dayText.classList.add("day-text");
    dayText.textContent = day.slice(0, 3);
    dayText.role = "columnheader";
    dayHeader.append(dayText);
  }

  const calendarBody = document.createElement("article");
  calendarBody.id = "calendar-body";
  calendarBody.role = "rowgroup";
  calendarSection.append(calendarBody);

  const currentDateCalendar = new Date(Date.now());
  currentDateCalendar.setDate(1);

  refreshCalendar(
    currentDateCalendar,
    monthYear,
    calendarBody,
    daysNumbers,
    calendarLang,
    events,
    beginM,
  );

  nextButton.addEventListener("click", (e) => {
    const nextMonth = currentDateCalendar.getMonth() + 1;
    if (nextMonth > 11) {
      currentDateCalendar.setFullYear(currentDateCalendar.getFullYear() + 1);
      currentDateCalendar.setMonth(0);
    } else {
      currentDateCalendar.setMonth(nextMonth);
    }
    refreshCalendar(
      currentDateCalendar,
      monthYear,
      calendarBody,
      daysNumbers,
      calendarLang,
      events,
      beginM,
    );
    handleOnClick(e);
  });

  prevButton.addEventListener("click", (e) => {
    const prevMonth = currentDateCalendar.getMonth() - 1;
    if (prevMonth < 0) {
      currentDateCalendar.setFullYear(currentDateCalendar.getFullYear() - 1);
      currentDateCalendar.setMonth(11);
    } else {
      currentDateCalendar.setMonth(prevMonth);
    }
    refreshCalendar(
      currentDateCalendar,
      monthYear,
      calendarBody,
      daysNumbers,
      calendarLang,
      events,
      beginM,
    );
    handleOnClick(e);
  });
}

function refreshCalendar(
  currentDateC: Date,
  monthYearElement: HTMLElement,
  calendarBody: HTMLElement,
  daysNumbers: ReaderObject[],
  calendarLang: "fr" | "en",
  events: CalendarEvents,
  beginM: boolean,
) {
  calendarBody.innerHTML = "";

  monthYearElement.textContent = `${
    calendarsLangDatas2[calendarLang].months[currentDateC.getMonth()]
  } ${currentDateC.getFullYear()}`;
  monthYearElement.dataset.month = currentDateC.getMonth().toString();
  monthYearElement.dataset.year = currentDateC.getFullYear().toString();

  const firstDay = new Date(
    currentDateC.getFullYear(),
    currentDateC.getMonth(),
    1,
  );
  const lastDay = new Date(
    currentDateC.getFullYear(),
    currentDateC.getMonth() + 1,
    0,
  );

  const firstDayIndex = (firstDay.getDay() + 6) % 7;
  const daysInMonth = lastDay.getDate();
  let iOffset = 0;
  const dateOffset = new Date(
    currentDateC.getFullYear(),
    currentDateC.getMonth(),
    1,
    12,
  );
  dateOffset.setDate(dateOffset.getDate() - firstDayIndex - 1);

  let iRow = 0;
  let iColumn = 0;

  for (iOffset; iOffset < firstDayIndex + (beginM ? 0 : 1); iOffset++) {
    const emptyDay = document.createElement("div");
    emptyDay.dataset.date = `${dateOffset.getDate()}-${dateOffset.getMonth()}-${dateOffset.getFullYear()}`;
    dateOffset.setDate(dateOffset.getDate() + 1);
    emptyDay.style.gridRow = "1";
    emptyDay.style.gridColumn = (iColumn + 1).toString();
    iColumn++;
    iRow++;
    calendarBody.appendChild(emptyDay);
  }

  const today = new Date();
  for (let day = 0; day < daysInMonth; day++) {
    const dayElement = document.createElement("p");
    dayElement.style.gridRow = (Math.floor(iRow / 7) * 2 + 1).toString();
    dayElement.style.gridColumn = ((iColumn % 7) + 1).toString();
    iColumn++;
    iRow++;
    dayElement.className = "day";
    dayElement.tabIndex = 0;
    dayElement.role = "gridcell";
    dayElement.textContent = (day + 1).toString();
    dayElement.dataset.date = `${
      day + 1
    }-${currentDateC.getMonth()}-${currentDateC.getFullYear()}`;
    const c = daysNumbers[iOffset + day];
    if (c != undefined && c.clickable != undefined) {
      dayElement.dataset.clickable = c.clickable.toString();
      dayElement.addEventListener("click", handleOnClick);
    }

    if (
      day + 1 === today.getDate() &&
      currentDateC.getMonth() === today.getMonth() &&
      currentDateC.getFullYear() === today.getFullYear()
    ) {
      dayElement.classList.add("today");
    }

    calendarBody.appendChild(dayElement);
  }

  for (const [year, eventsThisYear] of Object.entries(events)) {
    if (
      Number.parseInt(year) === currentDateC.getFullYear() ||
      Number.parseInt(year) === currentDateC.getFullYear() - 1 ||
      Number.parseInt(year) === currentDateC.getFullYear() + 1
    ) {
      for (const [month, eventsThisMonth] of Object.entries(eventsThisYear)) {
        if (
          Number.parseInt(month) === currentDateC.getMonth() ||
          Number.parseInt(month) === currentDateC.getMonth() - 1 ||
          Number.parseInt(month) === currentDateC.getMonth() + 1
        ) {
          for (const [day, eventsThisDay] of Object.entries(eventsThisMonth)) {
            const startingDate = calendarBody.querySelector(
              `[data-date="${day}-${month}-${year}"]`,
            );
            if (
              startingDate != undefined &&
              startingDate instanceof HTMLElement
            ) {
              for (const [duration, events] of Object.entries(eventsThisDay)) {
                const div = document.createElement("div");
                div.style.gridRow = (
                  Number.parseInt(startingDate.style.gridRow) + 1
                ).toString();
                const starting = Number.parseInt(startingDate.style.gridColumn);
                div.style.gridColumn = `${starting}/${
                  starting + Number.parseInt(duration)
                }`;
                div.classList.add("calendar-events");
                for (const event of events) {
                  const element = document.createElement(event.name || "div");
                  element.textContent = event.content || "";
                  element.className = event.classes || "";
                  element.dataset.position = event.position.toString();
                  if (event.clickable != undefined) {
                    element.dataset.clickable = event.clickable.toString();
                    element.addEventListener("click", handleOnClick);
                  }
                  div.style.border = `4px solid ${
                    calendarsLangDatas2.eventColors[event.numberEvent || 0]
                  }`;
                  div.appendChild(element);
                }
                startingDate.after(div);
              }
            }
          }
        }
      }
    }
  }
}

broadcastChannel.sendReadyMessage();
