import { animate, stagger } from "motion";
import browser from "webextension-polyfill";
import LogoLight from "@/resources/icons/betterseqta-light-icon.png";
import assessmentsicon from "@/seqta/icons/assessmentsIcon";
import coursesicon from "@/seqta/icons/coursesIcon";
import { GetThresholdOfColor } from "@/seqta/ui/colors/getThresholdColour";
import { convertTo12HourFormat } from "../convertTo12HourFormat";
import { delay } from "../delay";
import { settingsState } from "../listeners/SettingsState";
import stringToHTML from "../stringToHTML";
import { renderShortcuts } from "@/seqta/utils/Render/renderShortcuts";
import { CreateElement } from "@/seqta/utils/CreateEnable/CreateElement";
import { FilterUpcomingAssessments } from "@/seqta/utils/FilterUpcomingAssessments";
import { getMockNotices } from "@/seqta/ui/dev/hideSensitiveContent";
import { setupFixedTooltips } from "@/seqta/utils/fixedTooltip";

let LessonInterval: any;
let currentSelectedDate = new Date();
let loadingTimeout: any;

export async function loadHomePage() {
  console.info("[BetterSEQTA+] Started Loading Home Page");

  currentSelectedDate = new Date();

  await delay(10);

  document.title = "Home ― SEQTA Learn";
  const element = document.querySelector("[data-key=home]");
  element?.classList.add("active");

  const main = document.getElementById("main");
  if (!main) {
    console.error("[BetterSEQTA+] Main element not found.");
    return;
  }

  const homeRoot = stringToHTML(`<div id="home-root" class="home-root"></div>`);

  main.innerHTML = "";
  main.appendChild(homeRoot?.firstChild!);

  const homeContainer = document.getElementById("home-root");
  if (!homeContainer) return;

  const skeletonStructure = stringToHTML(/* html */`
      <div class="home-container" id="home-container">
        <div class="border shortcut-container">
          <div class="border shortcuts" id="shortcuts"></div>
        </div>
        <div class="border timetable-container">
          <div class="home-subtitle">
            <h2 id="home-lesson-subtitle">Today's Lessons</h2>
            <div class="timetable-arrows">
              <svg width="24" height="24" viewBox="0 0 24 24" style="transform: scale(-1,1)" id="home-timetable-back">
                <g style="fill: currentcolor;"><path d="M8.578 16.359l4.594-4.594-4.594-4.594 1.406-1.406 6 6-6 6z"></path></g>
              </svg>
              <svg width="24" height="24" viewBox="0 0 24 24" id="home-timetable-forward">
                <g style="fill: currentcolor;"><path d="M8.578 16.359l4.594-4.594-4.594-4.594 1.406-1.406 6 6-6 6z"></path></g>
              </svg>
            </div>
          </div>
          <div class="day-container loading" id="day-container">
          </div>
        </div>
        <div class="border upcoming-container">
          <div class="upcoming-title">
            <h2 class="home-subtitle">Upcoming Assessments</h2>
            <div class="upcoming-filters" id="upcoming-filters"></div>
          </div>
          <div class="upcoming-items loading" id="upcoming-items">
          </div>
        </div>
        <div class="border notices-container">
          <div style="display: flex; justify-content: space-between">
            <h2 class="home-subtitle">Notices</h2>
            <input type="date" />
          </div>
          <div class="notice-container upcoming-items loading" id="notice-container">
          </div>
        </div>
      </div>`);

  homeContainer.appendChild(skeletonStructure.firstChild!);

  if (settingsState.animations) {
    animate(
      ".home-container > div",
      { opacity: [0, 1], y: [10, 0], scale: [0.99, 1] },
      {
        delay: stagger(0.15, { startDelay: 0.1 }),
        type: "spring",
        stiffness: 341,
        damping: 20,
        mass: 1,
      },
    );
  }

  const cleanup = setupTimetableListeners();

  renderShortcuts();

  const date = new Date();
  const TodayFormatted = formatDate(date);

  const [timetablePromise, assessmentsPromise, classesPromise, prefsPromise] = [
    fetch(`${location.origin}/seqta/student/load/timetable?`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        from: TodayFormatted,
        until: TodayFormatted,
        student: 69,
      }),
    }).then((res) => res.json()),

    GetUpcomingAssessments(),

    GetActiveClasses(),

    fetch(`${location.origin}/seqta/student/load/prefs?`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ asArray: true, request: "userPrefs" }),
    }).then((res) => res.json()),
  ];

  const [timetableData, assessments, classes, prefs] = await Promise.all([
    timetablePromise,
    assessmentsPromise,
    classesPromise,
    prefsPromise,
  ]);

  const dayContainer = document.getElementById("day-container");
  if (dayContainer && timetableData.payload.items.length > 0) {
    const lessonArray = timetableData.payload.items.sort((a: any, b: any) =>
      a.from.localeCompare(b.from),
    );
    const colours = await GetLessonColours();

    dayContainer.innerHTML = "";
    for (let i = 0; i < lessonArray.length; i++) {
      const lesson = lessonArray[i];
      const subjectname = `timetable.subject.colour.${lesson.code}`;
      const subject = colours.find(
        (element: any) => element.name === subjectname,
      );

      lesson.colour = subject
        ? `--item-colour: ${subject.value};`
        : "--item-colour: #8e8e8e;";
      lesson.from = lesson.from.substring(0, 5);
      lesson.until = lesson.until.substring(0, 5);

      if (settingsState.timeFormat === "12") {
        lesson.from = convertTo12HourFormat(lesson.from);
        lesson.until = convertTo12HourFormat(lesson.until);
      }

      lesson.attendanceTitle = CheckUnmarkedAttendance(lesson.attendance);

      const div = makeLessonDiv(lesson, i + 1);
      if (GetThresholdOfColor(subject?.value) > 300) {
        const firstChild = div.firstChild as HTMLElement;
        if (firstChild) {
          firstChild.classList.add("day-inverted");
        }
      }
      dayContainer.appendChild(div.firstChild!);
    }

    if (currentSelectedDate.getDate() === date.getDate()) {
      for (let i = 0; i < lessonArray.length; i++) {
        CheckCurrentLesson(lessonArray[i], i + 1);
      }
      CheckCurrentLessonAll(lessonArray);
    }
  } else if (dayContainer) {
    dayContainer.innerHTML = `
        <div class="day-empty">
          <img src="${browser.runtime.getURL(LogoLight)}" />
          <p>No lessons available.</p>
        </div>`;
  }
  dayContainer?.classList.remove("loading");

  const activeClass = classes.find((c: any) => c.hasOwnProperty("active"));
  const activeSubjects = activeClass?.subjects || [];
  const activeSubjectCodes = activeSubjects.map((s: any) => s.code);
  const currentAssessments = assessments
    .filter((a: any) => activeSubjectCodes.includes(a.code))
    .sort(comparedate);

  const upcomingItems = document.getElementById("upcoming-items");
  if (upcomingItems) {
    await CreateUpcomingSection(currentAssessments, activeSubjects);
    upcomingItems.classList.remove("loading");
  }

  const labelArray = prefs.payload
    .filter((item: any) => item.name === "notices.filters")
    .map((item: any) => item.value);

  if (labelArray.length > 0) {
    const noticeContainer = document.getElementById("notice-container");
    if (noticeContainer) {
      const dateControl = document.querySelector(
        'input[type="date"]',
      ) as HTMLInputElement;
      if (dateControl) {
        dateControl.value = TodayFormatted;
        setupNotices(labelArray[0].split(" "), TodayFormatted);
      }
      noticeContainer.classList.remove("loading");
    }
  }

  return cleanup;
}

async function GetUpcomingAssessments() {
  let func = fetch(
    `${location.origin}/seqta/student/assessment/list/upcoming?`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json; charset=utf-8",
      },
      body: JSON.stringify({ student: 69 }),
    },
  );

  return func
    .then((result) => result.json())
    .then((response) => response.payload);
}

function setupTimetableListeners() {
  const listeners: Array<() => void> = [];
  const timetableBack = document.getElementById("home-timetable-back");
  const timetableForward = document.getElementById("home-timetable-forward");

  function changeTimetable(value: number) {
    if (loadingTimeout) {
      clearTimeout(loadingTimeout);
    }

    loadingTimeout = setTimeout(() => {
      const dayContainer = document.getElementById("day-container");
      if (dayContainer) {
        dayContainer.classList.add("loading");
        dayContainer.innerHTML = "";
      }
    }, 200);

    currentSelectedDate.setDate(currentSelectedDate.getDate() + value);
    const formattedDate = formatDate(currentSelectedDate);
    callHomeTimetable(formattedDate, true);
    SetTimetableSubtitle();
  }

  const backHandler = () => changeTimetable(-1);
  const forwardHandler = () => changeTimetable(1);

  timetableBack?.addEventListener("click", backHandler);
  timetableForward?.addEventListener("click", forwardHandler);

  listeners.push(
    () => timetableBack?.removeEventListener("click", backHandler),
    () => timetableForward?.removeEventListener("click", forwardHandler),
  );

  return () => listeners.forEach((cleanup) => cleanup());
}

function formatDate(date: Date): string {
  const year = date.getFullYear();
  const month = (date.getMonth() + 1).toString().padStart(2, "0");
  const day = date.getDate().toString().padStart(2, "0");
  return `${year}-${month}-${day}`;
}

async function GetActiveClasses() {
  try {
    const response = await fetch(
      `${location.origin}/seqta/student/load/subjects?`,
      {
        method: "POST",
        headers: { "Content-Type": "application/json; charset=utf-8" },
        body: JSON.stringify({}),
      },
    );

    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }

    const data = await response.json();
    return data.payload;
  } catch (error) {
    console.error("Oops! There was a problem fetching active classes:", error);
  }
}

function setupNotices(labelArray: string[], date: string) {
  const dateControl = document.querySelector(
    'input[type="date"]',
  ) as HTMLInputElement;

  const fetchNotices = async (date: string) => {
    let data;

    if (settingsState.mockNotices) {
      data = getMockNotices();
    } else {
      const response = await fetch(
        `${location.origin}/seqta/student/load/notices?`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json; charset=utf-8" },
          body: JSON.stringify({ date }),
        },
      );
      data = await response.json();
    }

    processNotices(data, labelArray);
  };

  const debouncedInputChange = debounce((e: Event) => {
    const target = e.target as HTMLInputElement;
    fetchNotices(target.value);
  }, 250);

  dateControl?.addEventListener("input", debouncedInputChange);
  fetchNotices(date);

  return () => dateControl?.removeEventListener("input", debouncedInputChange);
}

function debounce<T extends (...args: any[]) => any>(
  func: T,
  wait: number,
): (...args: Parameters<T>) => void {
  let timeout: any;
  return (...args: Parameters<T>) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => func(...args), wait);
  };
}

function comparedate(obj1: any, obj2: any) {
  if (obj1.date < obj2.date) {
    return -1;
  }
  if (obj1.date > obj2.date) {
    return 1;
  }
  return 0;
}


function processNotices(response: any, labelArray: string[]) {
  const NoticeContainer = document.getElementById("notice-container");
  if (!NoticeContainer) return;

  NoticeContainer.innerHTML = "";

  const notices = response.payload;
  if (!notices.length) {
    const dummyNotice = document.createElement("div");
    dummyNotice.textContent = "No notices for today.";
    dummyNotice.classList.add("dummynotice");
    NoticeContainer.append(dummyNotice);
    return;
  }

  const fragment = document.createDocumentFragment();

  notices.forEach((notice: any) => {
    const shouldInclude =
      settingsState.mockNotices ||
      labelArray.includes(JSON.stringify(notice.label));

    if (shouldInclude) {
      const colour = processNoticeColor(notice.colour);
      const noticeElement = createNoticeElement(notice, colour);
      fragment.appendChild(noticeElement);
    }
  });

  NoticeContainer.appendChild(fragment);
}

function processNoticeColor(colour: string): string | undefined {
  if (typeof colour === "string") {
    const rgb = GetThresholdOfColor(colour);
    if (rgb < 100 && settingsState.DarkMode) {
      return undefined;
    }
  }
  return colour;
}

function createNoticeElement(notice: any, colour: string | undefined): Node {
  const textPreview = notice.contents
    .replace(/<[^>]*>/g, "")
    .replace(/\[\[[\w]+[:][\w]+[\]\]]+/g, "")
    .replace(/\s+/g, " ")
    .trim()
    .substring(0, 150)
    + (notice.contents.length > 150 ? "..." : "");
  
  const noticeId = `notice-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

  const htmlContent = `
    <div class="notice-unified-content notice-card-state" data-notice-id="${noticeId}" style="--colour: ${colour || "#8e8e8e"}; position: relative; background: var(--background-primary); cursor: pointer; transition: all 0.3s ease; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); border: 1px solid rgba(255, 255, 255, 0.1);">
      <div class="notice-header">
        <div class="notice-badge-row">
          <span class="notice-badge" style="background: linear-gradient(135deg, ${colour || "#8e8e8e"}, ${colour || "#8e8e8e"}dd); color: white;">
            ${notice.label_title || "General"}
          </span>
          <span class="notice-staff">${notice.staff}</span>
        </div>
        <button class="notice-close-btn" style="opacity: 0; pointer-events: none;">&times;</button>
      </div>
      <h2 class="notice-content-title">${notice.title}</h2>
      <div class="notice-content-body">${textPreview}</div>
    </div>`;

  const element = stringToHTML(htmlContent).firstChild as HTMLElement;
  if (element) {
    element.addEventListener("click", () =>
      openNoticeModal(notice, colour, element),
    );
  }
  return element!;
}

function openNoticeModal(
  notice: any,
  colour: string | undefined,
  sourceElement: HTMLElement,
) {
  const cleanContent = notice.contents
    .replace(/\[\[[\w]+[:][\w]+[\]\]]+/g, "")
    .replace(/ +/, " ");

  const existingModal = document.getElementById("notice-modal");
  if (existingModal) {
    existingModal.remove();
  }

  const sourceRect = sourceElement.getBoundingClientRect();
  let scrollY = Math.round(window.scrollY);
  let scrollX = Math.round(window.scrollX);

  let sourceLeft = sourceRect.left;
  let sourceTop = sourceRect.top;
  let sourceWidth = sourceRect.width;
  let sourceHeight = sourceRect.height;

  const modalHtml = `
    <div id="notice-modal" class="notice-modal-overlay" style="opacity: 0;">
      <div class="notice-modal-transition" style="
        position: fixed;
        left: ${sourceLeft + scrollX}px;
        top: ${sourceTop + scrollY}px;
        width: ${sourceWidth}px;
        height: ${sourceHeight}px;
        transform-origin: center;
        z-index: 10001;
      ">
        <div class="notice-modal-content notice-transitioning">
          <div class="notice-unified-content notice-card-state">
            <div class="notice-header">
              <div class="notice-badge-row">
                <span class="notice-badge" style="background: linear-gradient(135deg, ${colour || "#8e8e8e"}, ${colour || "#8e8e8e"}dd); color: white;">
                  ${notice.label_title || "General"}
                </span>
                <span class="notice-staff">${notice.staff}</span>
              </div>
              <button class="notice-close-btn">&times;</button>
            </div>
            <h2 class="notice-content-title">${notice.title}</h2>
            <div class="notice-content-body">${cleanContent}</div>
          </div>
        </div>
      </div>
    </div>`;

  const modal = stringToHTML(modalHtml).firstChild as HTMLElement;
  const transitionContainer = modal.querySelector(
    ".notice-modal-transition",
  ) as HTMLElement;
  const unifiedContent = modal.querySelector(
    ".notice-unified-content",
  ) as HTMLElement;
  const closeBtn = modal.querySelector(".notice-close-btn") as HTMLElement;

  document.body.appendChild(modal);

  sourceElement.setAttribute("data-transitioning", "true");
  sourceElement.style.opacity = "0";
  sourceElement.style.transform = "scale(0.95)";

  const viewportWidth = window.innerWidth;
  const viewportHeight = window.innerHeight;
  let targetWidth = Math.round(
    Math.min(Math.max(sourceWidth, 800), viewportWidth - 40),
  );

  const tempMeasureDiv = document.createElement("div");
  tempMeasureDiv.style.position = "absolute";
  tempMeasureDiv.style.left = "-9999px";
  tempMeasureDiv.style.width = targetWidth + "px";
  tempMeasureDiv.style.visibility = "hidden";
  tempMeasureDiv.innerHTML = `
    <div class="notice-unified-content notice-modal-state" style="position: relative; width: 100%; padding: 16px; border: 1px solid rgba(255, 255, 255, 0.1);">
      <div class="notice-header">
        <div class="notice-badge-row">
          <span class="notice-badge">${notice.label_title || "General"}</span>
          <span class="notice-staff">${notice.staff}</span>
        </div>
        <button class="notice-close-btn">&times;</button>
      </div>
      <h2 class="notice-content-title">${notice.title}</h2>
      <div class="notice-content-body">${cleanContent}</div>
    </div>
  `;
  document.body.appendChild(tempMeasureDiv);
  const measuredHeight =
    tempMeasureDiv.firstElementChild!.getBoundingClientRect().height;
  document.body.removeChild(tempMeasureDiv);

  let targetHeight = Math.round(
    Math.min(Math.max(measuredHeight, 200), viewportHeight * 0.85),
  );

  let targetLeft = Math.round((viewportWidth - targetWidth) / 2);
  let targetTop = Math.round((viewportHeight - targetHeight) / 2) + scrollY;

  const closeModal = () => {
    window.removeEventListener("resize", handleResize);
    document.removeEventListener("keydown", handleEscape);

    if (!settingsState.animations) {
      modal.remove();
      sourceElement.style.opacity = "1";
      sourceElement.style.transform = "";
      sourceElement.removeAttribute("data-transitioning");
      return;
    }

    animate(
      modal,
      {
        backgroundColor: ["rgba(0, 0, 0, 0.5)", "rgba(0, 0, 0, 0)"],
        backdropFilter: ["blur(4px)", "blur(0px)"],
      },
      { duration: 0.2 },
    );

    animate(
      transitionContainer,
      { opacity: [1, 0] },
      { duration: 0.2, delay: 0.3 },
    );

    sourceElement.style.opacity = "1";
    sourceElement.style.transform = "";

    modal.style.pointerEvents = "none";

    animate(
      transitionContainer,
      {
        left: [targetLeft + scrollX, sourceLeft + scrollX],
        top: [targetTop, sourceTop + scrollY],
        width: [targetWidth, sourceWidth],
        height: [targetHeight, sourceHeight],
        scale: [1, 1],
      },
      {
        duration: 0.35,
        type: "spring",
        stiffness: 400,
        damping: 35,
      },
    ).finished.then(async () => {
      modal.remove();
      sourceElement.removeAttribute("data-transitioning");
    });
  };

  closeBtn?.addEventListener("click", closeModal);
  modal?.addEventListener("click", (e) => {
    if (e.target === modal) {
      closeModal();
    }
  });

  const handleEscape = (e: KeyboardEvent) => {
    if (e.key === "Escape") {
      closeModal();
      document.removeEventListener("keydown", handleEscape);
      window.removeEventListener("resize", handleResize);
    }
  };
  document.addEventListener("keydown", handleEscape);

  const handleResize = () => {
    const newSourceRect = sourceElement.getBoundingClientRect();
    const newScrollY = Math.round(window.scrollY);
    const newScrollX = Math.round(window.scrollX);

    // Get the current scale applied to the source element and compensate for it
    const computedStyle = getComputedStyle(sourceElement);
    const transform = computedStyle.transform;
    let scaleX = 1,
      scaleY = 1;

    if (transform && transform !== "none") {
      const matrix = transform.match(/matrix.*\((.+)\)/);
      if (matrix) {
        const values = matrix[1].split(", ");
        scaleX = parseFloat(values[0]);
        scaleY = parseFloat(values[3]);
      }
    }

    // Apply inverse scale to get true original dimensions and positions
    const newSourceWidth = newSourceRect.width / scaleX;
    const newSourceHeight = newSourceRect.height / scaleY;

    // Calculate position shift due to center-based scaling
    const deltaX = (newSourceWidth - newSourceRect.width) / 2;
    const deltaY = (newSourceHeight - newSourceRect.height) / 2;

    const newSourceLeft = newSourceRect.left - deltaX;
    const newSourceTop = newSourceRect.top - deltaY;

    const newViewportWidth = window.innerWidth;
    const newViewportHeight = window.innerHeight;
    const newTargetWidth = Math.round(
      Math.min(Math.max(newSourceWidth, 800), newViewportWidth - 40),
    );

    // Just measure the existing modal content
    const currentHeight = unifiedContent.getBoundingClientRect().height;
    const newTargetHeight = Math.round(
      Math.min(Math.max(currentHeight, 200), newViewportHeight * 0.85),
    );

    const newTargetLeft = Math.round((newViewportWidth - newTargetWidth) / 2);
    const newTargetTop =
      Math.round((newViewportHeight - newTargetHeight) / 2) + newScrollY;

    transitionContainer.style.left =
      Math.round(newTargetLeft + newScrollX) + "px";
    transitionContainer.style.top = Math.round(newTargetTop) + "px";
    transitionContainer.style.width = Math.round(newTargetWidth) + "px";
    transitionContainer.style.height = Math.round(newTargetHeight) + "px";

    sourceLeft = newSourceLeft;
    sourceTop = newSourceTop;
    sourceWidth = newSourceWidth;
    sourceHeight = newSourceHeight;
    targetLeft = newTargetLeft;
    targetTop = newTargetTop;
    targetWidth = newTargetWidth;
    targetHeight = newTargetHeight;
    scrollY = newScrollY;
    scrollX = newScrollX;
  };

  window.addEventListener("resize", handleResize);

  if (settingsState.animations) {
    animate(modal, { opacity: [0, 1] }, { duration: 0.2 });

    animate(
      transitionContainer,
      {
        left: [sourceLeft + scrollX, targetLeft + scrollX],
        top: [sourceTop + scrollY, targetTop],
        width: [sourceWidth, targetWidth],
        height: [sourceHeight, targetHeight],
        scale: [1, 1],
      },
      {
        duration: 0.5,
        type: "spring",
        stiffness: 280,
        damping: 24,
      },
    );

    unifiedContent.classList.remove("notice-card-state");
    unifiedContent.classList.add("notice-modal-state");
  } else {
    modal.style.opacity = "1";
    transitionContainer.style.left = Math.round(targetLeft + scrollX) + "px";
    transitionContainer.style.top = Math.round(targetTop) + "px";
    transitionContainer.style.width = Math.round(targetWidth) + "px";
    transitionContainer.style.height = Math.round(targetHeight) + "px";
    unifiedContent.classList.remove("notice-card-state");
    unifiedContent.classList.add("notice-modal-state");
  }
}

function callHomeTimetable(date: string, change?: any) {
  var xhr = new XMLHttpRequest();
  xhr.open("POST", `${location.origin}/seqta/student/load/timetable?`, true);

  xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");

  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      if (loadingTimeout) {
        clearTimeout(loadingTimeout);
        loadingTimeout = null;
      }

      const DayContainer = document.getElementById("day-container")!;

      try {
        var serverResponse = JSON.parse(xhr.response);
        let lessonArray: Array<any> = [];

        if (serverResponse.payload.items.length > 0) {
          if (DayContainer.innerText || change) {
            for (let i = 0; i < serverResponse.payload.items.length; i++) {
              lessonArray.push(serverResponse.payload.items[i]);
            }
            lessonArray.sort(function (a, b) {
              return a.from.localeCompare(b.from);
            });

            GetLessonColours().then((colours) => {
              let subjects = colours;
              for (let i = 0; i < lessonArray.length; i++) {
                let subjectname = `timetable.subject.colour.${lessonArray[i].code}`;

                let subject = subjects.find(
                  (element: any) => element.name === subjectname,
                );
                if (!subject) {
                  lessonArray[i].colour = "--item-colour: #8e8e8e;";
                } else {
                  lessonArray[i].colour = `--item-colour: ${subject.value};`;
                  let result = GetThresholdOfColor(subject.value);

                  if (result > 300) {
                    lessonArray[i].invert = true;
                  }
                }

                lessonArray[i].from = lessonArray[i].from.substring(0, 5);
                lessonArray[i].until = lessonArray[i].until.substring(0, 5);

                if (settingsState.timeFormat === "12") {
                  lessonArray[i].from = convertTo12HourFormat(
                    lessonArray[i].from,
                  );
                  lessonArray[i].until = convertTo12HourFormat(
                    lessonArray[i].until,
                  );
                }

                lessonArray[i].attendanceTitle = CheckUnmarkedAttendance(
                  lessonArray[i].attendance,
                );
              }

              DayContainer.innerText = "";
              for (let i = 0; i < lessonArray.length; i++) {
                var div = makeLessonDiv(lessonArray[i], i + 1);

                if (lessonArray[i].invert) {
                  const div1 = div.firstChild! as HTMLElement;
                  div1.classList.add("day-inverted");
                }

                DayContainer.append(div.firstChild as HTMLElement);
              }

              DayContainer.classList.remove("loading");

              const today = new Date();
              if (currentSelectedDate.getDate() == today.getDate()) {
                for (let i = 0; i < lessonArray.length; i++) {
                  CheckCurrentLesson(lessonArray[i], i + 1);
                }

                CheckCurrentLessonAll(lessonArray);
              }
            });
          }
        } else {
          DayContainer.innerHTML = "";
          var dummyDay = document.createElement("div");
          dummyDay.classList.add("day-empty");
          let img = document.createElement("img");
          img.src = browser.runtime.getURL(LogoLight);
          let text = document.createElement("p");
          text.innerText = "No lessons available.";
          dummyDay.append(img);
          dummyDay.append(text);
          DayContainer.append(dummyDay);

          DayContainer.classList.remove("loading");
        }
      } catch (error) {
        console.error("Error loading timetable data:", error);

        DayContainer.classList.remove("loading");

        DayContainer.innerHTML = "";
        const errorDiv = document.createElement("div");
        errorDiv.classList.add("day-empty");
        errorDiv.innerHTML = `
          <img src="${browser.runtime.getURL(LogoLight)}" />
          <p>Error loading lessons. Please try again.</p>
        `;
        DayContainer.append(errorDiv);
      }
    }
  };
  xhr.send(
    JSON.stringify({
      from: date,
      until: date,

      student: 69,
    }),
  );
}

function CheckCurrentLessonAll(lessons: any) {
  LessonInterval = setInterval(
    function () {
      for (let i = 0; i < lessons.length; i++) {
        CheckCurrentLesson(lessons[i], i + 1);
      }
    }.bind(lessons),
    60000,
  );
}

async function CheckCurrentLesson(lesson: any, num: number) {
  const {
    from: startTime,
    until: endTime,
    code,
    description,
    room,
    staff,
  } = lesson;
  const currentDate = new Date();

  const [startHour, startMinute] = startTime.split(":").map(Number);
  const [endHour, endMinute] = endTime.split(":").map(Number);

  const startDate = new Date(currentDate);
  startDate.setHours(startHour, startMinute, 0);

  const endDate = new Date(currentDate);
  endDate.setHours(endHour, endMinute, 0);

  const isValidTime = startDate < currentDate && endDate > currentDate;

  const elementId = `${code}${num}`;
  const element = document.getElementById(elementId);

  if (!element) {
    clearInterval(LessonInterval);
    return;
  }

  const isCurrentDate =
    currentSelectedDate.toLocaleDateString("en-au") ===
    currentDate.toLocaleDateString("en-au");

  if (isCurrentDate) {
    if (isValidTime) {
      element.classList.add("activelesson");
    } else {
      element.classList.remove("activelesson");
    }
  }

  const minutesUntilStart = Math.floor(
    (startDate.getTime() - currentDate.getTime()) / 60000,
  );

  if (
    minutesUntilStart !== 5 ||
    settingsState.lessonalert ||
    !window.Notification
  )
    return;

  if (Notification.permission !== "granted")
    await Notification.requestPermission();

  try {
    new Notification("Next Lesson in 5 Minutes:", {
      body: `Subject: ${description}${room ? `\nRoom: ${room}` : ""}${staff ? `\nTeacher: ${staff}` : ""}`,
    });
  } catch (error) {
    console.error(error);
  }
}

function makeLessonDiv(lesson: any, num: number) {
  if (!lesson) throw new Error("No lesson provided.");

  const {
    code,
    colour,
    description,
    staff,
    room,
    from,
    until,
    attendanceTitle,
    programmeID,
    metaID,
    assessments,
  } = lesson;

  let lessonString = `
      <div class="day" id="${code + num}" style="${colour}">
        <h2>${description || "Unknown"}</h2>
        <h3>${staff || "Unknown"}</h3>
        <h3>${room || "Unknown"}</h3>
        <h4>${from || "Unknown"} - ${until || "Unknown"}</h4>
        <h5>${attendanceTitle || "Unknown"}</h5>
    `;

  if (programmeID !== 0) {
    lessonString += `
        <div class="day-button clickable" style="right: 5px;" onclick="location.href='${buildAssessmentURL(programmeID, metaID)}'">${assessmentsicon}</div>
        <div class="day-button clickable" style="right: 35px;" onclick="location.href='../#?page=/courses/${programmeID}:${metaID}'">${coursesicon}</div>
      `;
  }

  if (assessments && assessments.length > 0) {
    const assessmentString = assessments
      .map(
        (element: any) =>
          `<p onclick="location.href = '${buildAssessmentURL(programmeID, metaID, element.id)}';">${element.title}</p>`,
      )
      .join("");

    lessonString += `
        <div class="fixed-tooltip assessmenttooltip">
          <svg style="width:28px;height:28px;border-radius:0;" viewBox="0 0 24 24">
            <path fill="#ed3939" d="M16 2H4C2.9 2 2 2.9 2 4V20C2 21.11 2.9 22 4 22H16C17.11 22 18 21.11 18 20V4C18 2.9 17.11 2 16 2M16 20H4V4H6V12L8.5 9.75L11 12V4H16V20M20 15H22V17H20V15M22 7V13H20V7H22Z" />
          </svg>
          <div class="tooltiptext">${assessmentString}</div>
        </div>
      `;
  }

  lessonString += "</div>";
  const element = stringToHTML(lessonString);
  setupFixedTooltips(element);
  return element;
}

function buildAssessmentURL(programmeID: any, metaID: any, itemID = "") {
  const base = "../#?page=/assessments/";
  return itemID
    ? `${base}${programmeID}:${metaID}&item=${itemID}`
    : `${base}${programmeID}:${metaID}`;
}

function CheckUnmarkedAttendance(lessonattendance: any) {
  if (lessonattendance) {
    var lesson = lessonattendance.label;
  } else {
    lesson = " ";
  }
  return lesson;
}

async function CreateUpcomingSection(assessments: any, activeSubjects: any) {
  let upcomingitemcontainer = document.querySelector("#upcoming-items");
  let overdueDates = [];
  let upcomingDates = {};

  var Today = new Date();

  for (let i = 0; i < assessments.length; i++) {
    const assessment = assessments[i];
    let assessmentdue = new Date(assessment.due);

    CheckSpecialDay(Today, assessmentdue);
    if (assessmentdue < Today) {
      if (!CheckSpecialDay(Today, assessmentdue)) {
        overdueDates.push(assessment);
        assessments.splice(i, 1);
        i--;
      }
    }
  }

  var TomorrowDate = new Date();
  TomorrowDate.setDate(TomorrowDate.getDate() + 1);

  const colours = await GetLessonColours();

  let subjects = colours;
  for (let i = 0; i < assessments.length; i++) {
    let subjectname = `timetable.subject.colour.${assessments[i].code}`;

    let subject = subjects.find((element: any) => element.name === subjectname);

    if (!subject) {
      assessments[i].colour = "--item-colour: #8e8e8e;";
    } else {
      assessments[i].colour = `--item-colour: ${subject.value};`;
      GetThresholdOfColor(subject.value);
    }
  }

  for (let i = 0; i < activeSubjects.length; i++) {
    const element = activeSubjects[i];
    let subjectname = `timetable.subject.colour.${element.code}`;
    let colour = colours.find((element: any) => element.name === subjectname);
    if (!colour) {
      element.colour = "--item-colour: #8e8e8e;";
    } else {
      element.colour = `--item-colour: ${colour.value};`;
      let result = GetThresholdOfColor(colour.value);
      if (result > 300) {
        element.invert = true;
      }
    }
  }

  CreateFilters(activeSubjects);

  let type;
  let class_;

  for (let i = 0; i < assessments.length; i++) {
    const element: any = assessments[i];
    if (!upcomingDates[element.due as keyof typeof upcomingDates]) {
      let dateObj: any = new Object();
      dateObj.div = CreateElement(
        (type = "div"),
        (class_ = "upcoming-date-container"),
      );
      dateObj.assessments = [];
      (upcomingDates[element.due as keyof typeof upcomingDates] as any) =
        dateObj;
    }
    let assessmentDateDiv =
      upcomingDates[element.due as keyof typeof upcomingDates];

    if (assessmentDateDiv) {
      (assessmentDateDiv as any).assessments.push(element);
    }
  }

  for (var date in upcomingDates) {
    let assessmentdue = new Date(
      (
        upcomingDates[date as keyof typeof upcomingDates] as any
      ).assessments[0].due,
    );
    let specialcase = CheckSpecialDay(Today, assessmentdue);
    let assessmentDate;

    if (specialcase) {
      let datecase: string = specialcase!;
      assessmentDate = createAssessmentDateDiv(
        date,
        upcomingDates[date as keyof typeof upcomingDates],

        datecase,
      );
    } else {
      assessmentDate = createAssessmentDateDiv(
        date,
        upcomingDates[date as keyof typeof upcomingDates],
      );
    }

    if (specialcase === "Yesterday") {
      upcomingitemcontainer!.insertBefore(
        assessmentDate,
        upcomingitemcontainer!.firstChild,
      );
    } else {
      upcomingitemcontainer!.append(assessmentDate);
    }
  }
  FilterUpcomingAssessments(settingsState.subjectfilters);
  
  if (assessments.length === 0) {
    upcomingitemcontainer!.innerHTML = `
      <div class="day-empty">
        <img src="${browser.runtime.getURL(LogoLight)}" />
        <p>No assessments available.</p>
      </div>`;
  }
}

function createAssessmentDateDiv(date: string, value: any, datecase?: any) {
  var options = {
    weekday: "long" as "long",
    month: "long" as "long",
    day: "numeric" as "numeric",
  };
  const FormattedDate = new Date(date);

  const assessments = value.assessments;
  const container = value.div;

  let DateTitleDiv = document.createElement("div");
  DateTitleDiv.classList.add("upcoming-date-title");

  if (datecase) {
    let datetitle = document.createElement("h5");
    datetitle.classList.add("upcoming-special-day");
    datetitle.innerText = datecase;
    DateTitleDiv.append(datetitle);
    container.setAttribute("data-day", datecase);
  }

  let DateTitle = document.createElement("h5");
  DateTitle.innerText = FormattedDate.toLocaleDateString("en-AU", options);
  DateTitleDiv.append(DateTitle);

  container.append(DateTitleDiv);

  let assessmentContainer = document.createElement("div");
  assessmentContainer.classList.add("upcoming-date-assessments");

  for (let i = 0; i < assessments.length; i++) {
    const element = assessments[i];
    let item = document.createElement("div");
    item.classList.add("upcoming-assessment");
    item.setAttribute("data-subject", element.code);
    item.id = `assessment${element.id}`;

    item.style.cssText = element.colour;

    let titlediv = document.createElement("div");
    titlediv.classList.add("upcoming-subject-title");

    let titlesvg =
      stringToHTML(`<svg viewBox="0 0 24 24" style="width:35px;height:35px;fill:white;">
    <path d="M6 20H13V22H6C4.89 22 4 21.11 4 20V4C4 2.9 4.89 2 6 2H18C19.11 2 20 2.9 20 4V12.54L18.5 11.72L18 12V4H13V12L10.5 9.75L8 12V4H6V20M24 17L18.5 14L13 17L18.5 20L24 17M15 19.09V21.09L18.5 23L22 21.09V19.09L18.5 21L15 19.09Z"></path>
    </svg>`).firstChild;
    titlediv.append(titlesvg!);

    let detailsdiv = document.createElement("div");
    detailsdiv.classList.add("upcoming-details");
    let detailstitle = document.createElement("h5");
    detailstitle.innerText = `${element.subject} assessment`;
    let subject = document.createElement("p");
    subject.innerText = element.title;
    subject.classList.add("upcoming-assessment-title");
    subject.onclick = function () {
      document.querySelector("#menu ul")!.classList.add("noscroll");
      location.href = `../#?page=/assessments/${element.programmeID}:${element.metaclassID}&item=${element.id}`;
    };
    detailsdiv.append(detailstitle);
    detailsdiv.append(subject);

    item.append(titlediv);
    item.append(detailsdiv);
    assessmentContainer.append(item);

    fetch(`${location.origin}/seqta/student/assessment/submissions/get`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json; charset=utf-8",
      },
      body: JSON.stringify({
        assessment: element.id,
        metaclass: element.metaclassID,
        student: 69,
      }),
    })
      .then((result) => result.json())
      .then((response) => {
        if (response.payload.length > 0) {
          const assessment = document.querySelector(`#assessment${element.id}`);

          let submittedtext = document.createElement("div");
          submittedtext.classList.add("upcoming-submittedtext");
          submittedtext.innerText = "Submitted";
          assessment!.append(submittedtext);
        }
      });
  }

  container.append(assessmentContainer);

  return container;
}

function CheckSpecialDay(date1: Date, date2: Date) {
  if (
    date1.getFullYear() === date2.getFullYear() &&
    date1.getMonth() === date2.getMonth() &&
    date1.getDate() - 1 === date2.getDate()
  ) {
    return "Yesterday";
  }
  if (
    date1.getFullYear() === date2.getFullYear() &&
    date1.getMonth() === date2.getMonth() &&
    date1.getDate() === date2.getDate()
  ) {
    return "Today";
  }
  if (
    date1.getFullYear() === date2.getFullYear() &&
    date1.getMonth() === date2.getMonth() &&
    date1.getDate() + 1 === date2.getDate()
  ) {
    return "Tomorrow";
  }
}

async function GetLessonColours() {
  let func = fetch(`${location.origin}/seqta/student/load/prefs?`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json; charset=utf-8",
    },
    body: JSON.stringify({ request: "userPrefs", asArray: true, user: 69 }),
  });
  return func
    .then((result) => result.json())
    .then((response) => response.payload);
}

function CreateFilters(subjects: any) {
  let filteroptions = settingsState.subjectfilters;

  let filterdiv = document.querySelector("#upcoming-filters");
  for (let i = 0; i < subjects.length; i++) {
    const element = subjects[i];

    if (!Object.prototype.hasOwnProperty.call(filteroptions, element.code)) {
      filteroptions[element.code] = true;
      settingsState.subjectfilters = filteroptions;
    }
    let elementdiv = CreateSubjectFilter(
      element.code,
      element.colour,
      filteroptions[element.code],
    );

    filterdiv!.append(elementdiv);
  }
}

function CreateSubjectFilter(
  subjectcode: any,
  itemcolour: string,
  checked: any,
) {
  let label = CreateElement("label", "upcoming-checkbox-container");
  label.innerText = subjectcode;
  let input1 = CreateElement("input");
  const input = input1 as HTMLInputElement;
  input.type = "checkbox";
  input.checked = checked;
  input.id = `filter-${subjectcode}`;
  label.style.cssText = itemcolour;
  let span = CreateElement("span", "upcoming-checkmark");
  label.append(input);
  label.append(span);

  input.addEventListener("change", function (change) {
    let filters = settingsState.subjectfilters;
    let id = (change.target as HTMLInputElement)!.id.split("-")[1];
    filters[id] = (change.target as HTMLInputElement)!.checked;

    settingsState.subjectfilters = filters;
  });

  return label;
}

function SetTimetableSubtitle() {
  const homelessonsubtitle = document.getElementById("home-lesson-subtitle");
  if (!homelessonsubtitle) return;

  const date = new Date();
  const isSameMonth =
    date.getFullYear() === currentSelectedDate.getFullYear() &&
    date.getMonth() === currentSelectedDate.getMonth();

  if (isSameMonth) {
    const dayDiff = date.getDate() - currentSelectedDate.getDate();
    switch (dayDiff) {
      case 0:
        homelessonsubtitle.innerText = "Today's Lessons";
        break;
      case 1:
        homelessonsubtitle.innerText = "Yesterday's Lessons";
        break;
      case -1:
        homelessonsubtitle.innerText = "Tomorrow's Lessons";
        break;
      default:
        homelessonsubtitle.innerText = formatDateString(currentSelectedDate);
    }
  } else {
    homelessonsubtitle.innerText = formatDateString(currentSelectedDate);
  }
}

function formatDateString(date: Date): string {
  return `${date.toLocaleString("en-us", { weekday: "short" })} ${date.toLocaleDateString("en-au")}`;
}
