window.addEventListener("online", () => console.log("Became online"));
window.addEventListener("offline", () => console.log("Became offline"));

var socket = io("wss://disploysocket.disploy.com", {
  transports: ["polling"],
  secure: true,
  reconnection: true,
  reconnectionDelay: 1000,
  reconnectionDelayMax: 5000,
  reconnectionAttempts: Infinity,
});

let isSocketShuttingDown = false;

async function ensureMachineId() {
  const existingId = localStorage.getItem("machineId");
  if (existingId) return existingId;

  return new Promise((resolve, reject) => {
    try {
      if (typeof webapis !== "undefined" && webapis.appcommon) {
        const value = webapis.appcommon.getUuid();
        localStorage.setItem("machineId", value);
        localStorage.setItem("deviceUID", value);
        resolve(value);
      } else {
        reject(new Error("webapis is not defined or unsupported"));
      }
    } catch (error) {
      reject(error);
    }
  });
}

function disconnectSocketImmediately() {
  if (isSocketShuttingDown || typeof socket === "undefined" || !socket) {
    return;
  }

  isSocketShuttingDown = true;

  try {
    if (socket.io && socket.io.opts) {
      socket.io.opts.reconnection = false;
    }

    socket.removeAllListeners();
    socket.disconnect();
  } catch (error) {
    console.warn("Failed to disconnect socket cleanly:", error);
  }
}

window.addEventListener("pagehide", disconnectSocketImmediately);
window.addEventListener("beforeunload", disconnectSocketImmediately);
window.addEventListener("unload", disconnectSocketImmediately);

socket.on("connect", async function () {
  let machineId = localStorage.getItem("machineId");
  if (!machineId) {
    try {
      machineId = await ensureMachineId();
    } catch (error) {
      console.error("Failed to resolve machineId:", error);
    }
  }

  socket.emit("SendTvStatus", {
    id: socket.id,
    connection: true,
    macId: machineId || "",
  });

  console.log("---- Socket Connected ----");

  if (typeof screenshotService !== "undefined") {
    screenshotService.setSocket(socket);
  }
});

socket.on("disconnect", function () {
  console.log("---- Socket Disconnected ----");
});

socket.on("ScreenConnected", function (data) {
  console.log(`--- SOCKET DATA ${JSON.stringify(data)} ---`);
  try {
    if (data != null && data.macId == localStorage.getItem("machineId")) {
      if (
        window.location.pathname.includes("index.html") ||
        window.location.pathname === "/"
      ) {
        window.location.reload();
      } else {
        window.location.href = "index.html";
      }
    } else {
      console.log("---- Data --> NULL ----");
    }
  } catch (e) {
    console.log(`Error in ScreenConnected event: ${e}`);
  }
});

socket.on("SendTvPreview", async function (data) {
  console.log(
    `--- [Screenshot] : SOCKET Screenshot DATA ${JSON.stringify(data)} ---`,
  );

  try {
    const macId = localStorage.getItem("machineId");

    if (data != null && data.macId !== macId) {
      console.log("Mac ID does not match. Ignoring screenshot request.");
      return;
    }

    if (typeof screenshotService !== "undefined") {
      const base64Image = await screenshotService.captureAsBase64();

      if (base64Image) {
        console.log("---- Screenshot captured successfully, uploading ----");
        await screenshotService.uploadScreenshot(base64Image, macId);
      } else {
        console.log("---- Failed to capture screenshot ----");
      }
    } else {
      console.error("---- Screenshot service not available ----");
    }
  } catch (e) {
    console.error(`Error in SendTvPreview event: ${e}`);
  }
});

// ============================================================================
// Schedule Management System
// Similar to android_new implementation
// ============================================================================

// Windows → IANA timezone mapping (extend when needed)
const TIMEZONE_MAP = {
  "India Standard Time": "Asia/Kolkata",
  "Pacific Standard Time": "America/Los_Angeles",
  "Eastern Standard Time": "America/New_York",
  "Central European Standard Time": "Europe/Berlin",
  "Greenwich Standard Time": "Etc/Greenwich",
};

// Global schedule data
let scheduleData = {
  myScreenOperatingHours: [],
  adsScreenOperatingHours: [],
  adsScreenExtraWorkingHours: [],
  myWeatherSchedule: [],
};

// Schedule check interval (1 minute like android_new)
let scheduleCheckInterval = null;

/**
 * Parse time string to get hours and minutes
 * Supports both "HH:MM:SS" and "HH:MM" formats
 */
function parseTime(timeStr) {
  const parts = timeStr.split(".")[0].split(":");
  return {
    hour: parseInt(parts[0]),
    minute: parseInt(parts[1]),
    second: parts[2] ? parseInt(parts[2]) : 0,
  };
}

/**
 * Get current time in specified timezone
 */
function getNowInTimezone(tz) {
  const iana = TIMEZONE_MAP[tz] || "UTC";
  return new Date(
    new Date().toLocaleString("en-US", {
      timeZone: iana,
    }),
  );
}

/**
 * Parse time string and create Date object for today
 */
function parseTimeToToday(timeStr, tz) {
  const time = parseTime(timeStr);
  const now = getNowInTimezone(tz);
  now.setHours(time.hour, time.minute, time.second, 0);
  return now;
}

/**
 * Check if current time is within operating hours
 */
function isInOperatingHours(operatingHours, tz = "UTC") {
  if (!operatingHours || !operatingHours.length) return false;

  const now = getNowInTimezone(tz);

  for (const slot of operatingHours) {
    const start = parseTimeToToday(slot.cStartDate, tz);
    const end = parseTimeToToday(slot.cEndDate, tz);

    // Overnight support (ex 22:00 → 06:00)
    if (end < start) {
      if (now >= start || now <= end) return true;
    } else {
      if (now >= start && now <= end) return true;
    }
  }

  return false;
}

/**
 * Check if current date/time matches extra working hours
 */
function isInExtraWorkingHours(extraHours, tz = "UTC") {
  if (!extraHours || !extraHours.length) return null;

  const now = getNowInTimezone(tz);
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());

  for (const extra of extraHours) {
    try {
      // Parse the date from extra hour entry
      const extraDate = new Date(extra.Date);
      const extraDateOnly = new Date(
        extraDate.getFullYear(),
        extraDate.getMonth(),
        extraDate.getDate(),
      );

      // Check if this extra hour is for today
      if (extraDateOnly.getTime() === today.getTime()) {
        const start = parseTimeToToday(extra.cStartDate, tz);
        const end = parseTimeToToday(extra.cEndDate, tz);

        // Check if we're in the time window
        const inWindow = now >= start && now <= end;

        // Return status based on IsClose flag
        if (inWindow) {
          return {
            isClose: extra.IsClose,
            inWindow: true,
          };
        }
      }
    } catch (e) {
      console.error("Error checking extra working hours:", e);
    }
  }

  return null;
}

/**
 * Determine ads screen status based on all schedule levels
 * Similar to android_new OperatingHoursManager.checkAdsScreenStatus
 */
function checkAdsScreenStatus(currentTime) {
  const tz = scheduleData.myScreenOperatingHours[0]?.timeZoneName || "UTC";

  console.log("🔍 Checking Ads Screen Status...");

  // Step 1: Check if adsScreenOperatingHours exists
  if (
    !scheduleData.adsScreenOperatingHours ||
    !scheduleData.adsScreenOperatingHours.length
  ) {
    console.log("❌ Step 1: No adsScreenOperatingHours → NOT APPLICABLE");
    return "notApplicable";
  }

  // Step 2: Check if within default hours
  const inDefaultHours = isInOperatingHours(
    scheduleData.adsScreenOperatingHours,
    tz,
  );
  if (!inDefaultHours) {
    console.log("❌ Step 2: Outside adsScreenOperatingHours → CLOSED");
    return "closed";
  }

  console.log("✅ Step 2: Inside adsScreenOperatingHours");

  // Step 3: Check extra working hours
  if (
    !scheduleData.adsScreenExtraWorkingHours ||
    !scheduleData.adsScreenExtraWorkingHours.length
  ) {
    console.log("✅ Step 3: No extra hours but within default hours → OPEN");
    return "open";
  }

  console.log("✅ Step 3: adsScreenExtraWorkingHours exists");

  // Step 4: Check if extra hours apply today
  const extraStatus = isInExtraWorkingHours(
    scheduleData.adsScreenExtraWorkingHours,
    tz,
  );

  if (!extraStatus) {
    console.log("❌ Step 4: No entries for today → CLOSED");
    return "closed";
  }

  // Step 5: Apply extra hour rules
  if (extraStatus.inWindow) {
    if (extraStatus.isClose) {
      console.log("❌ Step 5: Inside close window → CLOSED");
      return "closed";
    } else {
      console.log("✅ Step 5: Inside open window → OPEN");
      return "open";
    }
  }

  // Default to open if within default hours
  console.log("✅ Default: Within default hours → OPEN");
  return "open";
}

/**
 * Check if current page is the index page
 */
function isIndexPage() {
  return (
    window.location.pathname.includes("index.html") ||
    window.location.pathname === "/"
  );
}

/**
 * Main schedule check function
 * Checks all schedule levels and navigates accordingly
 */
function checkSchedules() {
  const tz = scheduleData.myScreenOperatingHours[0]?.timeZoneName || "UTC";
  const now = getNowInTimezone(tz);
  const isBlackout = window.location.pathname.includes("blackout-screen.html");

  console.log("🕒 [CRON] Schedule Check at:", now.toISOString());
  console.log("📍 Current page:", window.location.pathname);

  // Check main screen operating hours
  const inMainHours = isInOperatingHours(
    scheduleData.myScreenOperatingHours,
    tz,
  );
  console.log("📅 Main operating hours:", inMainHours);

  // If outside main hours, go to blackout
  if (!inMainHours) {
    if (!isBlackout) {
      console.log("🛑 Outside main hours → Navigating to blackout");
      window.location.href = "blackout-screen.html";
    }
    return;
  }

  // Check ads screen status
  const adsStatus = checkAdsScreenStatus(now);
  console.log("🎯 Ads Screen Status:", adsStatus);

  // Handle ads screen logic
  if (adsStatus === "closed") {
    if (!isBlackout) {
      console.log("🛑 Ads closed → Navigating to blackout");
      window.location.href = "blackout-screen.html";
    }
    return;
  }

  // If we're here, we should be showing content
  if (isBlackout) {
    console.log("✅ Should show content → Navigating to index");
    window.location.href = "index.html";
    return;
  }

  // Check if we need to reload (at exact boundaries)
  checkScheduleBoundaries(now, tz);
}

/**
 * Check if we're at a schedule boundary and need to reload
 */
function checkScheduleBoundaries(now, tz) {
  const checkBoundary = (hours, label) => {
    if (!hours || !hours.length) return false;

    for (const slot of hours) {
      const start = parseTimeToToday(slot.cStartDate, tz);
      const end = parseTimeToToday(slot.cEndDate, tz);

      // Check if we're within 1 minute of start or end
      const timeDiffStart = Math.abs(now - start);
      const timeDiffEnd = Math.abs(now - end);

      if (timeDiffStart < 60000) {
        // Within 1 minute of start
        console.log(`✅ [${label}] StartTime boundary reached`);
        return true;
      }

      if (timeDiffEnd < 60000) {
        // Within 1 minute of end
        console.log(`🛑 [${label}] EndTime boundary reached`);
        return true;
      }
    }
    return false;
  };

  // Check all schedule levels
  const mainBoundary = checkBoundary(
    scheduleData.myScreenOperatingHours,
    "MAIN",
  );
  const adsBoundary = checkBoundary(
    scheduleData.adsScreenOperatingHours,
    "ADS",
  );

  // Check extra hours boundaries
  let extraBoundary = false;
  if (scheduleData.adsScreenExtraWorkingHours) {
    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());

    for (const extra of scheduleData.adsScreenExtraWorkingHours) {
      try {
        const extraDate = new Date(extra.Date);
        const extraDateOnly = new Date(
          extraDate.getFullYear(),
          extraDate.getMonth(),
          extraDate.getDate(),
        );

        if (extraDateOnly.getTime() === today.getTime()) {
          const start = parseTimeToToday(extra.cStartDate, tz);
          const end = parseTimeToToday(extra.cEndDate, tz);

          const timeDiffStart = Math.abs(now - start);
          const timeDiffEnd = Math.abs(now - end);

          if (timeDiffStart < 60000 || timeDiffEnd < 60000) {
            console.log(`🔄 [EXTRA] Boundary reached`);
            extraBoundary = true;
            break;
          }
        }
      } catch (e) {
        console.error("Error checking extra boundary:", e);
      }
    }
  }

  // If at any boundary, reload to re-evaluate
  if (mainBoundary || adsBoundary || extraBoundary) {
    console.log("🔄 At schedule boundary → Reloading");
    window.location.href = "index.html";
  }
}

/**
 * Initialize schedule management system
 */
async function initScheduleManagement() {
  const baseUrl = "https://back.disploy.com/api/NewScreen/GeneratePreview";
  const cacheKey = "generatePreview:response";

  const getGeneratePreviewCache = (maxAgeMs = 20000) => {
    try {
      const raw = localStorage.getItem(cacheKey);
      if (!raw) return null;
      const parsed = JSON.parse(raw);
      if (!parsed || typeof parsed.ts !== "number") return null;
      if (Date.now() - parsed.ts > maxAgeMs) return null;
      return parsed.data || null;
    } catch {
      return null;
    }
  };

  const setGeneratePreviewCache = (data) => {
    try {
      localStorage.setItem(cacheKey, JSON.stringify({ ts: Date.now(), data }));
    } catch {}
  };

  console.log("🚀 Initializing Schedule Management System...");

  try {
    let data = getGeneratePreviewCache(20000);

    if (!data) {
      try {
        const response = await fetch(baseUrl, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            macid: localStorage.getItem("machineId"),
          }),
        });

        if (response.status === 429) {
          data = getGeneratePreviewCache(Infinity);
        } else {
          data = await response.json();
          setGeneratePreviewCache(data);
        }
      } catch (error) {
        data = getGeneratePreviewCache(Infinity);
        if (!data) {
          throw error;
        }
      }
    }

    if (!data) {
      console.warn("Schedule manager: no GeneratePreview data available");
      return;
    }

    // Store schedule data
    scheduleData.myScreenOperatingHours = data.myScreenOperatingHours || [];
    scheduleData.adsScreenOperatingHours = data.adsScreenOperatingHours || [];
    scheduleData.adsScreenExtraWorkingHours =
      data.adsScreenExtraWorkingHours || [];
    scheduleData.myWeatherSchedule = data.myWeatherSchedule || [];

    console.log("📊 Schedule Data Loaded:");
    console.log("  - Main hours:", scheduleData.myScreenOperatingHours.length);
    console.log("  - Ads hours:", scheduleData.adsScreenOperatingHours.length);
    console.log(
      "  - Extra hours:",
      scheduleData.adsScreenExtraWorkingHours.length,
    );
    console.log(
      "  - Weather schedules:",
      scheduleData.myWeatherSchedule.length,
    );

    // If no main operating hours, skip schedule management
    if (!scheduleData.myScreenOperatingHours.length) {
      console.log("ℹ️ No operating hours found — skipping schedule management");
      return;
    }

    // Start schedule checking (every minute like android_new)
    startScheduleChecking();
  } catch (err) {
    console.error("❌ Failed loading schedule data:", err);
  }
}

/**
 * Start periodic schedule checking
 */
function startScheduleChecking() {
  // Clear any existing interval
  if (scheduleCheckInterval) {
    clearInterval(scheduleCheckInterval);
  }

  // Do initial check
  checkSchedules();

  // Schedule checks every minute (60000ms)
  scheduleCheckInterval = setInterval(() => {
    checkSchedules();
  }, 60000);

  console.log("✅ Schedule checking started (every 1 minute)");
}

// Initialize schedule management on load
initScheduleManagement();
