window.onload = function () {
  retriveData();
};

let currentIndex = 0;
let interval = 0;
let isInitialCycle = true;
let isDefault = false;
let baseUrl = "https://back.disploy.com/api/NewScreen/GeneratePreview";
let storedData;
const GENERATE_PREVIEW_LAST_REQUEST_KEY = "generatePreview:lastRequestAt";
const GENERATE_PREVIEW_MIN_INTERVAL_MS = 3000;

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function waitForGeneratePreviewRateLimitSlot() {
  try {
    const lastRequestAt = Number(
      localStorage.getItem(GENERATE_PREVIEW_LAST_REQUEST_KEY) || "0",
    );
    const now = Date.now();
    const waitMs = Math.max(
      0,
      lastRequestAt + GENERATE_PREVIEW_MIN_INTERVAL_MS - now,
    );

    if (waitMs > 0) {
      await sleep(waitMs);
    }

    localStorage.setItem(GENERATE_PREVIEW_LAST_REQUEST_KEY, String(Date.now()));
  } catch {
    await sleep(GENERATE_PREVIEW_MIN_INTERVAL_MS);
  }
}

async function retriveData() {
  for (let attempt = 1; attempt <= 3; attempt++) {
    await waitForGeneratePreviewRateLimitSlot();

    try {
      const response = await axios.post(baseUrl, {
        macid: localStorage.getItem("machineId"),
      });
      storedData = response.data;
      break;
    } catch (error) {
      const isRateLimited = error?.response?.status === 429;
      if (isRateLimited && attempt < 3) {
        console.warn(
          `GeneratePreview 429 (attempt ${attempt}/3). Retrying in 3 seconds...`,
        );
        await sleep(GENERATE_PREVIEW_MIN_INTERVAL_MS);
        continue;
      }
      throw error;
    }
  }

  if (storedData) {
    const parsedData = storedData;

    currentIndex = changeCurrentIndex(parsedData.data);
    console.log("Current Index : ", currentIndex);
    if (currentIndex == -1) {
      currentIndex = findDefaultAssetIndex(parsedData.data);
      interval = getTimeLeftForNextSchedule(parsedData.data);
      console.log("Interval : ", interval);

      if (interval == -1) {
        isDefault = true;
      }
    } else {
      interval = calculateDurationInMilliseconds(
        parsedData.data[currentIndex].cStartDate,
        parsedData.data[currentIndex].cEndDate,
      );
    }

    const activeScheduleExists = parsedData.data.some((schedule) => {
      const currentTime = new Date().getTime();
      const startTime = new Date(schedule.cStartDate).getTime();
      const endTime = new Date(schedule.cEndDate).getTime();

      return currentTime >= startTime && currentTime <= endTime;
    });

    if (parsedData.data.length > 1 && activeScheduleExists) {
      updateDisplayContainer(parsedData.data);
    } else if (parsedData.myComposition[0].noofBox > 0) {
      renderComposition();
      const timeLeft = getTimeLeftForNextSchedule(parsedData.data);
      if (timeLeft !== -1) {
        setTimeout(() => {
          window.location.reload();
        }, timeLeft);
      }
    } else if (
      !activeScheduleExists &&
      parsedData.apps &&
      parsedData.apps.length > 0
    ) {
      // Show app when no active schedule exists
      // Use the first app from the apps array
      showApp(parsedData.apps[0].url);
      if (parsedData.data && parsedData.data.length > 0) {
        const timeLeft = getTimeLeftForNextSchedule(parsedData.data);
        if (timeLeft !== -1) {
          setTimeout(() => {
            window.location.reload();
          }, timeLeft);
        }
      }
    } else {
      updateDisplayContainer(parsedData.data);
    }
  } else {
    console.log("DISPLAY DATA:", storedData);
  }
}

function getNextScheduleTime(schedules) {
  const currentTime = new Date().getTime();

  const futureSchedules = schedules
    .filter((schedule) => new Date(schedule.cStartDate).getTime() > currentTime)
    .sort((a, b) => new Date(a.cStartDate) - new Date(b.cStartDate));

  return futureSchedules.length > 0
    ? new Date(futureSchedules[0].cStartDate).getTime()
    : -1;
}

function showApp(appUrl) {
  console.log("Showing app with URL:", appUrl);
  const container = document.querySelector(".display-container");
  // Render the app iframe using the existing renderApp function
  container.innerHTML = renderApp(appUrl);

  // Set container styles for full-screen display
  container.style.position = "fixed";
  container.style.left = "0";
  container.style.top = "0";
  container.style.width = "100vw";
  container.style.height = "100vh";
}

function getTimeLeftForNextSchedule(schedules) {
  const nextScheduleTime = getNextScheduleTime(schedules);
  const currentTime = new Date().getTime();

  if (nextScheduleTime <= 0) return -1;

  const timeLeft = nextScheduleTime - currentTime;
  return timeLeft > 0 ? timeLeft : -1;
}

async function updateDisplayContainer(data) {
  console.log({
    isDefault: isDefault,
    interval: interval,
    currentIndex: currentIndex,
    isInitialCycle: isInitialCycle,
  });
  let item = data[currentIndex];
  const container = document.querySelector(".display-container");
  container.innerHTML = "";
  container.innerHTML = renderMedia(item);

  if (isInitialCycle == false && isDefault == false) {
    interval = calculateDurationInMilliseconds(
      data[currentIndex].cStartDate,
      data[currentIndex].cEndDate,
    );
  }

  console.log("Interval : ", interval / 1000 / 60);

  container.style.position = "fixed";
  container.style.left = "0";
  container.style.top = "0";
  container.style.width = "100vw";
  container.style.height = "100vh";

  console.log({
    isDefault: isDefault,
    interval: interval,
    currentIndex: currentIndex,
    isInitialCycle: isInitialCycle,
  });

  if (data.length > 1 && !isDefault) {
    console.log("-------- INTERVAL START --------");
    setInterval(() => {
      currentIndex = changeCurrentIndex(data);
      if (currentIndex == -1) {
        currentIndex = findDefaultAssetIndex(data);
        interval = getTimeLeftForNextSchedule(data);

        if (interval == -1) {
          isDefault = true;
          interval = 864 * 100000;
        }
      }

      container.innerHTML = "";
      isInitialCycle = false;
      // updateDisplayContainer(data);
      window.location.reload();
    }, interval);
  } else {
    const parsedData = storedData;
    if (parsedData.myComposition[0].noofBox > 0) {
      renderComposition();
    } else if (isDefault && parsedData.apps && parsedData.apps.length > 0) {
      // Show app when in default mode (no active schedules)
      console.log("Showing app in default mode");
      showApp(parsedData.apps[0].url);
    }
  }
}

function findDefaultAssetIndex(data) {
  for (let i = 0; i < data.length; i++) {
    if (data[i].isdefaultAsset === "true") {
      return i;
    }
  }
  return -1;
}

function getTimeLeftForNextSchedule(schedules) {
  const now = new Date();
  const upcomingSchedules = schedules.filter(
    (schedule) => new Date(schedule.cStartDate) > now,
  );
  if (upcomingSchedules.length === 0) {
    return -1;
  }

  const onlyDefaultAsset = upcomingSchedules.every(
    (schedule) => schedule.isdefaultAsset === "true",
  );
  if (onlyDefaultAsset) {
    return -1;
  }

  const nearestSchedule = upcomingSchedules.reduce((nearest, current) => {
    const nearestTimeDiff = Math.abs(new Date(nearest.cStartDate) - now);
    const currentTimeDiff = Math.abs(new Date(current.cStartDate) - now);
    return currentTimeDiff < nearestTimeDiff ? current : nearest;
  });

  const timeLeftMilliseconds = new Date(nearestSchedule.cStartDate) - now;

  return timeLeftMilliseconds;
}

function changeCurrentIndex(data) {
  const currentTime = new Date();
  const currentTimeStamp = currentTime.getTime();

  for (let i = 0; i < data.length; i++) {
    const cStartDate = new Date(data[i].cStartDate).getTime();
    const cEndDate = new Date(data[i].cEndDate).getTime();

    if (currentTimeStamp >= cStartDate && currentTimeStamp <= cEndDate) {
      return i;
    }
  }

  return -1;
}

function calculateDurationInMilliseconds(startDate, endDate) {
  const startTime = new Date(startDate);
  const endTime = new Date(endDate);

  const currentTime = new Date();
  console.log(currentTime, startTime, endTime);

  if (currentTime >= startTime && currentTime <= endTime) {
    console.log(currentTime, startTime, endTime);
    startTime.setTime(currentTime.getTime());
  }

  const durationInMillis = endTime - startTime;

  return durationInMillis;
}

function renderComposition() {
  console.log("-------- COMPO RENDER --------");
  let compositionData;
  let currentIndices = [];
  let layoutContainer = document.getElementById("layout-container");

  if (!layoutContainer) {
    console.error("Error: layout-container element not found.");
    return;
  }

  if (!storedData) {
    console.error("No data found in localStorage.");
    return;
  }

  const parsedData = storedData;
  compositionData = parsedData?.myComposition?.[0]?.compositionPossition;

  console.log("📦 Composition data loaded in renderComposition:", {
    hasMyComposition: !!parsedData?.myComposition,
    compositionCount: parsedData?.myComposition?.length,
    hasCompositionPossition:
      !!parsedData?.myComposition?.[0]?.compositionPossition,
    compositionPossitionLength:
      parsedData?.myComposition?.[0]?.compositionPossition?.length,
    compositionData: compositionData,
  });

  if (
    !compositionData ||
    !Array.isArray(compositionData) ||
    compositionData.length === 0
  ) {
    console.error("Invalid or empty composition data in renderComposition.", {
      compositionData,
      fullData: parsedData,
    });
    return;
  }

  currentIndices = Array(compositionData.length).fill(0);

  initLayout();
  window.addEventListener("resize", initLayout);

  function initLayout() {
    layoutContainer.innerHTML = "";
    compositionData.forEach((box, index) => {
      const left = (box.left / 100) * window.innerWidth;
      const top = (box.top / 100) * window.innerHeight;
      const width = (box.width / 100) * window.innerWidth;
      const height = (box.height / 100) * window.innerHeight;

      const contentBox = document.createElement("div");
      contentBox.id = `content-box-${index}`;
      contentBox.classList.add("content-box");
      contentBox.style.position = "absolute";
      contentBox.style.left = `${left}px`;
      contentBox.style.top = `${top}px`;
      contentBox.style.width = `${width}px`;
      contentBox.style.height = `${height}px`;

      layoutContainer.appendChild(contentBox);
      renderSchedules(box.schedules, index);
    });
  }

  function buildContent(schedule, sequenceIndex) {
    const contentBox = document.querySelector(`#content-box-${sequenceIndex}`);
    if (!contentBox) {
      console.error(`Content box ${sequenceIndex} not found.`);
      return;
    }
    contentBox.innerHTML = renderMedia(schedule);
    observeMedia(contentBox);
  }

  function renderSchedules(schedules, sequenceIndex) {
    if (!schedules || schedules.length === 0) {
      console.warn(`No schedules for sequence index ${sequenceIndex}`);
      return;
    }

    const currentIndex = currentIndices[sequenceIndex];
    const schedule = schedules[currentIndex];
    buildContent(schedule, sequenceIndex);

    const duration = (schedule.durationInSecond || 5) * 1000;
    const startTime = performance.now();

    function scheduleNext() {
      const elapsed = performance.now() - startTime;
      if (elapsed >= duration) {
        currentIndices[sequenceIndex] = (currentIndex + 1) % schedules.length;
        renderSchedules(schedules, sequenceIndex);
      } else {
        requestAnimationFrame(scheduleNext);
      }
    }
    requestAnimationFrame(scheduleNext);
  }

  function observeMedia(element) {
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          const video = entry.target.querySelector("video");
          if (entry.isIntersecting) {
            video?.play();
          } else {
            video?.pause();
          }
        });
      },
      {
        threshold: 0.5,
      },
    );

    observer.observe(element);
  }
}

function extractVideoId(url) {
  const regExp = /^.*(?:youtu.be\/|v\/|embed\/|watch\?v=)([^#\&\?]*).*/;
  const match = url.match(regExp);
  return match && match[1].length === 11 ? match[1] : null;
}

function renderApp(appUrl) {
  console.log("Rendering app iframe with URL:", appUrl);

  if (!appUrl || typeof appUrl !== "string") {
    console.error("App URL must be a non-empty string");
    return '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: white;">App URL must be a non-empty string</div>';
  }

  try {
    const textarea = document.createElement("textarea");
    textarea.innerHTML = appUrl;
    const decodedUrl = textarea.value;

    console.log("Decoded URL:", decodedUrl);

    const url = new URL(decodedUrl);
    if (url.protocol !== "http:" && url.protocol !== "https:") {
      console.error("Invalid URL protocol:", url.protocol);
      return '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: white;">Only HTTP/HTTPS URLs are allowed</div>';
    }

    const iframe = document.createElement("iframe");
    iframe.setAttribute("src", url.href);
    iframe.setAttribute("allowfullscreen", "true");
    iframe.setAttribute("loading", "lazy");
    iframe.setAttribute(
      "allow",
      "autoplay; fullscreen; camera; microphone; geolocation",
    );
    iframe.style.cssText =
      "width: 100%; height: 100%; border: none; position: absolute; left: 0; top: 0;";

    return iframe.outerHTML;
  } catch (e) {
    console.error("Malformed app URL:", appUrl, e);
    return '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: white;">Malformed app URL</div>';
  }
}

function renderMedia(schedule) {
  console.log("Rendering media for schedule:", schedule);
  if (schedule.apps && schedule.apps.trim() !== "") {
    console.log("✅ Rendering app iframe:", schedule.apps);
    return renderApp(schedule.apps);
  }

  const mediaType = schedule.mediaType?.toLowerCase() || "";
  const screenResolution =
    schedule.screenResolutionName?.toLowerCase() === "fit"
      ? "fill"
      : schedule.screenResolutionName?.toLowerCase() || "cover";

  switch (mediaType) {
    case "text":
      return `<marquee 
                class="marquee"
                behavior="scroll" 
                direction="${schedule.direction === "LTR" ? "right" : "left"}" 
                scrollamount="10"
              >
                ${schedule.fileType}
              </marquee>
            `;

    case "youtube":
      const videoId = extractVideoId(schedule.fileType);
      return `<iframe
                src="https://www.youtube.com/embed/${videoId}?autoplay=1&controls=0&mute=${
                  schedule.isMute ? 1 : 0
                }&loop=1&playlist=${videoId}"
                allowfullscreen
                loading="lazy">
              </iframe>`;

    case "image":
    case "onlineimage":
      if (schedule.screenResolutionName?.toLowerCase() === "zoom") {
        return `<img
                  src="${schedule.fileType}"
                  style="width: 100%; height: 100%; object-fit: ${screenResolution};
                         transform: scale(1.2);
                         transform-origin: center;
                         overflow: hidden;">`;
      } else {
        return `<img
                  src="${schedule.fileType}"
                  style="width: 100%; height: 100%; object-fit: ${screenResolution};">`;
      }

    case "video":
      if (schedule.screenResolutionName?.toLowerCase() === "zoom") {
        return `<video 
                    id="video-${Math.random()}" 
                    class="video-js vjs-default-skin" 
                    autoplay 
                    preload="auto"
                    muted 
                    loop 
                    playsinline
                    poster=${schedule.thumbImage}
                    style="width: 100%; height: 100%; object-fit: ${screenResolution};
                           transform: scale(1.2);
                           transform-origin: center;
                           overflow: hidden;"
                    data-setup='{}'>
                    <source src="${schedule.fileType}" type="video/mp4">
                    Your browser does not support the video tag.
                  </video>`;
      } else {
        return `<video 
                    id="video-${Math.random()}" 
                    class="video-js vjs-default-skin" 
                    autoplay 
                    preload="auto"
                    muted 
                    loop 
                    playsinline
                    poster=${schedule.thumbImage}
                        style="width: 100%; height: 100%; object-fit: ${
                          screenResolution.toUpperCase() == "NONE"
                            ? "contain"
                            : screenResolution
                        };"
                    data-setup='{}'>
                    <source src="${schedule.fileType}" type="video/mp4">
                    Your browser does not support the video tag.
                  </video>`;
      }

    case "pdf":
    case "docx":
    case "ppt":
    case "excel":
      return createIframe(schedule);

    default:
      return `<div>Unsupported media type: ${mediaType}</div>`;
  }
}

function createIframe(schedule) {
  const iframe = document.createElement("iframe");

  iframe.src = `https://docs.google.com/viewer?embedded=true&url=${schedule.fileType}`;

  if (schedule.screenResolutionName?.toLowerCase() === "zoom") {
    iframe.style = `
      width: 100%; 
      height: 100%; 
      position: absolute; 
      left: 0; 
      top: 0; 
      object-fit: cover; 
      transform: scale(1.2); 
      transform-origin: center; 
      overflow: hidden; 
      border: none;`;
  } else {
    iframe.style = `
      width: 100%; 
      height: 100%; 
      position: absolute; 
      left: 0; 
      top: 0; 
      object-fit: cover; 
      border: none;`;
  }

  iframe.allowFullscreen = true;

  iframe.onerror = () => {
    console.error("Iframe failed to load. Reloading...");
    iframe.src = iframe.src;
  };

  if (schedule.isScroll) {
    console.log("Scrolling iframe...", document.body.scrollHeight);
    let scrollAmount =
      schedule.numberOfPages > 0 ? schedule.numberOfPages * 4 * 40 : 100;

    const scrollInterval = schedule.scrollPerSec * 1000;

    const scrollWebsite = () => {
      try {
        console.log("Scrolling website...", scrollAmount);
        document.body.scrollTo(0, scrollAmount);
      } catch (err) {
        console.error("Error scrolling website:", err);
      }
    };

    setInterval(scrollWebsite, scrollInterval);
  }

  return iframe.outerHTML;
}
