const imageUrlServer = "include/dashboard/server.php";
const maxImages = 5;
let images = []; // Array to hold the images
// const nodeServerUrl = `http://localhost:3002`; // localserver
// const nodeServerUrl = `https://invisible-87fd8abb908d.herokuapp.com`; // heroku live server
// const nodeServerUrl = `http://135.148.121.143:3003`; // live server
let backendNodeUrl = null;
let csrf_token = null;
let all_streaming_cameras = [];

$(document).ready(async function () {
  let isChecked = $("#toggleView").is(":checked");
  if (!isChecked) {
    await getCsrf_token({ get_csrf_token: true });
    sendRequest({
      getSettingsData: "yes",
      property_id: sessionStorage.getItem("propertyId"),
    });
  }
});

function getCsrf_token(data) {
  return new Promise((resolve, reject) => {
    $.ajax({
      url: "/include/dashboard/settings_requests.php",
      type: "post",
      data,
      success: function (resp) {
        csrf_token = resp?.data;
        resolve(resp?.data);
      },
      error: function (xhr, status, error) {
        reject(xhr || error);
      },
    });
  });
}

async function getBackendStreamingUrl(data) {
  return new Promise((resolve, reject) => {
    $.ajax({
      url: "/include/property_builder/command_center/command_center_requests.php",
      type: "post",
      data,
      success: function (resp) {
        backendNodeUrl = `${resp?.data}/api`;
        resolve();
      },
      error: function (xhr, status, error) {
        reject(xhr || error);
      },
    });
  });
}

function sendServerRequestForImageView(data) {
  return $.ajax({
    url: "/include/dashboard/server.php",
    type: "post",
    data,
    success: function (response) {
      return response;
    },
    error: function (xhr, status, error) {
      console.log("Error occurred:", error);
      return Promise.reject(error);
    },
  });
}

async function fetchImages(item, count = 1, initialLoad = false, itemId) {
  let payload = { getImages: "yes", imagesCount: count };
  if (item?.liveImageURL) payload["imageUrl"] = item?.liveImageURL;
  if (item?.userName && item?.password) {
    payload["credentials"] = `${item.userName}:${item.password}`;
  }

  const loadingIndicator = document.getElementById(
    `loadingIndicator-${itemId}`
  );
  const loadingNextImage = document.getElementById(
    `loadingNextImage-${itemId}`
  );
  const loadingNextImageButton = document.getElementById(
    `loadingNextImageButton-${itemId}`
  );

  if (loadingNextImageButton.style.display == "block") {
    loadingNextImageButton.style.display = "none";
    loadingNextImage.style.display = "block";
  }

  if (!initialLoad) loadingIndicator.style.display = "block";
  sendServerRequestForImageView(payload)
    .then((response) => {
      if (loadingNextImage.style.display == "block") {
        loadingNextImage.style.display = "none";
        loadingNextImageButton.style.display = "block";
      }
      loadingIndicator.style.display = "none";
      const imageArray = response.images;
      updateImages(imageArray, initialLoad, itemId);
    })
    .catch((error) => {
      $(`#image_preview-${itemId}`).empty();
      $(`#image_preview-${itemId}`).append(
        `<p class="font-weight-bold">Failed to fetch images</p>`
      );

      loadingIndicator.style.display = "none";
      if (loadingNextImage.style.display == "block") {
        loadingNextImage.style.display = "none";
        loadingNextImageButton.style.display = "block";
      }
    });
}

function updateImages(imageArray, initialLoad, itemId) {
  imageArray.forEach((base64Image) => {
    const img = new Image();
    img.src = `data:image/jpeg;base64,${base64Image}`;
    img.classList.add("image-item");

    // Add new image to the beginning of the array
    // images.unshift(img);
    images.push(img);
  });

  updateUI(images, initialLoad, itemId);
}

function updateUI(images, initialLoad, itemId) {
  const imagePreview = document.querySelector(`#image_preview-${itemId}`);
  const allImagesContainer = document.querySelector(
    `#all_images_container-${itemId}`
  );

  // Clear existing images in the all_images_container
  allImagesContainer.innerHTML = "";

  // Set the remaining images in the image_box
  images.forEach((image) => {
    const imageBox = document.createElement("div");
    imageBox.classList.add("image_box");
    imageBox.appendChild(image.cloneNode());
    allImagesContainer.appendChild(imageBox);
    imageBox.querySelector("img").addEventListener("click", (event) => {
      showImageInPreview(event.target, itemId);
    });
  });
  // Set the first image in the image_preview only if it's not an initial load
  if (!initialLoad && images.length > 0) {
    imagePreview.innerHTML = ""; // Clear the previous image
    imagePreview.appendChild(images[0].cloneNode());
  }

  if (images.length >= maxImages) {
    if (imageFetchInterval !== null) {
      clearInterval(imageFetchInterval);
      imageFetchInterval = null;
    }
    allImagesContainer.scrollTo({
      left: allImagesContainer.scrollWidth - allImagesContainer.clientWidth,
      behavior: "smooth", // Smooth scrolling effect
    });

    document.getElementById(`loadingNextImageButton-${itemId}`).style.display =
      "block";
    document.getElementById(
      `loadingPreviousImageButton-${itemId}`
    ).style.display = "block";
  }
}

function previousButton(itemId) {
  const container = document.querySelector(`#all_images_container-${itemId}`);
  const scrollAmount = 100;
  container.scrollTo({
    left: Math.max(container.scrollLeft - scrollAmount, 0), // Ensure scroll position does not go negative
    behavior: "smooth", // Smooth scrolling effect
  });
}

function showImageInPreview(image, itemId) {
  const imagePreview = document.querySelector(`#image_preview-${itemId}`);
  imagePreview.innerHTML = "";
  const img = new Image();
  img.src = image.src;
  img.classList.add("image-item");
  imagePreview.appendChild(img);

  // Remove border from all images
  document.querySelectorAll(".image_box img").forEach((img) => {
    img.classList.remove("focused");
  });

  // Add border to the focused image
  image.classList.add("focused");
}

function toggleVideoMode(item, itemId) {
  const toggleButton = document.getElementById(`toggleView-${itemId}`);
  const pictureView = document.querySelector(`#picture-view${itemId}`);
  const videoView = document.querySelector(`.video-view${itemId}`);
  const all_images_container = document.querySelector(
    `#all_images_container-${itemId}`
  );
  all_images_container.innerHTML = "";
  document.getElementById(`loadingNextImageButton-${itemId}`).style.display =
    "none";
  document.getElementById(
    `loadingPreviousImageButton-${itemId}`
  ).style.display = "none";
  images = [];
  document.querySelector(`#image_preview-${itemId}`).innerHTML = "";
  // Clear the existing interval if it exists
  if (imageFetchInterval !== null) {
    clearInterval(imageFetchInterval);
    imageFetchInterval = null;
  }

  if (pictureView.style.display === "block") {
    pictureView.style.display = "none";
    videoView.style.display = "block";
    toggleButton.textContent = "Video view";
  } else {
    fetchImages(item, 2, false, itemId); // Fetch initial images
    imageFetchInterval = setInterval(
      () => fetchImages(item, 1, true, itemId),
      2000
    ); // Fetch images every 5 seconds
    pictureView.style.display = "block";
    videoView.style.display = "none";
    toggleButton.textContent = "Picture view";
  }
}

function sendRequest(data) {
  if (!data?.property_id) {
    showErrorGlobalToastMessage("Please select the property id");
    return;
  }
  $.ajax({
    url: "include/dashboard/settings_requests.php",
    type: "post",
    data,
    success: function (response) {
      if (response?.error) {
        console.log("Got error:", response);
        return;
      }
      response = response?.data;
      $("#streaming").empty();
      if (!response?.length > 0) {
        $("#streaming").append(
          `<p class="font-weight-bold">Add a camera to get live streaming! <br><span><a href="/dashboard.php?tab=property_builder&active=2">Add camera</a></span></p>`
        );
        return;
      }

      createStreamingDivs(response);
      getDashboardData();
    },
    error: function (xhr, status, error) {
      document.querySelector("#streaming").innerHTML = "";
      $("#streaming").append(
        `<p class="font-weight-bold">Got Error in getting camera configurations`
      );
    },
  });
}

function createStreamingDivs(response) {
  const container = document.getElementById("streaming"); // Ensure you have a container to hold the HTML
  container.innerHTML = ""; // Clear any existing content
  all_streaming_cameras = response;

  if (!response?.length > 0) {
    container.innerHTML = `<p class="font-weight-bold">Add a camera to get live streaming! <br> Go to settings in the menu to add camera <span><a href="/settings.php">Go to settings</a></span></p>`;
    return;
  }

  // Assuming 'response' is an array of objects with an 'id' field
  const htmlContent = response
    .map((item, index) => {
      let lastItem = false;
      if (index == response?.length - 1) lastItem = true;
      const htmlStreaming = `
      <div class="col-sm-12 col-md-6">
        <div class="card">
          <div class="card-body">

            <div class="${lastItem ? "" : "streaming"}" id="streaming-${item.id}">
              <div class="container text-right pb-3 d-flex justify-content-center">
                <span class="text-bold font-weight-bolder"> ${item?.cameraName} </span>
              </div>
              <div class="row">
                <div class="col-12">
                  <center>
                    <div class="video-view${item.id}">
                      <div id="imageContainer${item.id}">
                        <p class='text-center'> loading.....</p>
                      </div>
                      <div id="videoContainer-${item.id}"></div>
                    </div>
                  </center>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    `;
      getStreamingByImageUrl(item);
      return htmlStreaming;
    })
    .join("");

  // Wrap the output in a Bootstrap row
  container.innerHTML = `<div class="row">${htmlContent}</div>`;
  $(".custom-bootstrap-switch").bootstrapSwitch();
  
}

// Async function to handle streaming URLs
let requestPendingFlags = {}; // Object to track request status for each index

async function getStreamingByImageUrl(item) {
  if (!requestPendingFlags[item.id]) {
    requestPendingFlags[item.id] = false;
  }

  if (!item.streamingUrl && item.liveImageURL) {
    await getBackendStreamingUrl({ get_streaming_url_request: true });
    const data = await ajaxRequestWithHeaders(`${backendNodeUrl}/getImageStreamingingUrl`, "POST", {
      data: JSON.stringify({pass:item?.password, user:item?.userName}),
      contentType: "application/json",
    });
    connectImageSocket(data?.url,item);
  } else {
    getStreamingUrl(item);
  }
}

function connectImageSocket(wsUrl,item) {
  if (wsUrl) {
    const ws = new WebSocket(wsUrl);
    ws.onopen = () => {
      ws.send(JSON.stringify({
        event: "image_request",
        image_url: item.liveImageURL,
        pass:item?.password,
        user:item?.userName
      }));
    };
    ws.onmessage = (event) => {
      const message = JSON.parse(event.data);
      if (message.event === "image_data") {
        getImageStreaming(message.image, item.id, item);
        setTimeout(() => {
          ws.send(JSON.stringify({
            event: "image_request",
            image_url: item.liveImageURL,
            pass:item?.password,
            user:item?.userName
          }));
        }, 1000);
      }
    };
    ws.onerror = (event) => {
      console.log("WebSocket error:", event);
    };
    ws.onclose = async () => {
      console.log("WebSocket connection closed.");
    };
  } else {
    console.error("Failed to get SMS status:", result.error_message);
  }
}

function getImageStreaming(base64ImageData, itemId) {
  const imagePreview = document.querySelector(`#imageContainer${itemId}`);
  imagePreview.innerHTML = "";
  const imageBox = document.createElement("div");
  imageBox.classList.add("image_box");
  const img = document.createElement("img");
  img.src = `data:image/jpeg;base64,${base64ImageData}`;
  img.style.width = "100%";
  img.style.objectFit = "contain";
  // img.addEventListener("click", (event) => {
  //   showImageInPreview(event.target); // Attach event listener if needed
  // });

  // Append the image to the image box
  imageBox.appendChild(img);

  // Append the image box to the container
  imagePreview.appendChild(imageBox);
}

function sendServerRequest(data) {
  return $.ajax({
    url: "/include/dashboard/server.php",
    type: "post",
    data,
    success: function (response) {
      return response;
    },
    error: function (xhr, status, error) {
      console.log("Error occurred:", error);
      return Promise.reject(error);
    },
  });
}

// Async function to handle streaming URLs
async function getStreamingUrl(item) {  
  try {
    if(!backendNodeUrl) await getBackendStreamingUrl({ get_streaming_url_request: true });
    let payload = {
      ip: item.IP,
      user: item?.userName,
      pass: item?.password,
      port: item?.RTSP_PORT,
    };

    const data = encryptData(payload);
    const apiResponse = await ajaxRequestWithHeaders(`${backendNodeUrl}/streaming`, "POST", {
      data: JSON.stringify(data),
      headers: {
        Authorization: csrf_token,
      },
      contentType: "application/json", // important!
    });
    
    $(`#imageContainer${item.id}`).empty();
    const canvasId = `videoCanvas${item.id}`;
    $(`#videoContainer-${item.id}`).empty(); 
    $(`#videoContainer-${item.id}`).append(DOMPurify.sanitize(
      `<div id="${canvasId}div">
            <div class="">
              <canvas id="${canvasId}" width="550" height="380"></canvas>
              <div class="player-controls-wrapper"></div>
            </div> 
        </div>`
    ));
    $(`#videoContainer-${item.id}`).on("click", ".redirect-playback", function () {
      const idp = $(this).data("id");
      const urlp = `/playback.php?id=${idp}`;
      window.location.href = urlp;
    });
    connectWebSocket(apiResponse?.url, canvasId, item);
  } catch (error) {
    // console.log("What error i am getting : ", error);
    if(error?.responseJSON?.error) showErrorGlobalToastMessage(error?.responseJSON?.error );
    else showErrorGlobalToastMessage("Internal server error!");
    document.querySelector(`#videoContainer-${item.id}`).innerHTML = "";
    $(`#imageContainer${item.id}`).empty();
    const reconnectButton = createReconnectButton(
      item.id, 
      `#videoContainer-${item.id}`,
      "Internal server error!"
    );
    
    $(`#videoContainer-${item.id}`).append(reconnectButton.html);
    reconnectButton.bindEvent();
  }
}

function createReconnectButton(itemId, containerId, message = "Internal server error!") {
  const buttonHtml = `
    <p class="font-weight-bold text-center">
      ${message} <br>
      could not connect to the RTSP streaming server <br>
      <button class="btn btn-primary reconnect_button" 
              data-id="${itemId}" 
              data-container-id="${containerId}">
        Reconnect <i class="fa-solid fa-rotate-left"></i>
      </button>
    </p>
  `;
  
  return {
    html: DOMPurify.sanitize(buttonHtml),
    bindEvent: function() {
      $(`${containerId} .reconnect_button`).on('click', function(e) {
        e.preventDefault();
        console.log("Reconnect button clicked");
        const id = $(this).data("id");
        const container_id = $(this).data("container-id");
        console.log("Reconnecting with ID:", id, "Container:", container_id);
        reconnectRTSP(id, container_id);
      });
    }
  };
}

function reconnectRTSP(itemId, clearId) {
  const selected_camera = all_streaming_cameras.find((ele) => ele.id == itemId);
  if (selected_camera) getStreamingUrl(selected_camera);
  $(clearId).empty();
}

let players = {};
let playerStates = {};

function connectWebSocket(wsUrl, canvasId, item = null) {
  const safeCanvasId = String(canvasId);
  // if (!players[safeCanvasId]) {
  //   console.warn("Player not found:", safeCanvasId);
  //   return;
  // }
  let canvas = document.getElementById(safeCanvasId);
  canvas.width = 540;
  canvas.height = 318;
  window.addEventListener("resize", () => {
    if (canvas.width <= 540) {
      canvas.width = window.innerWidth * 0.8;
      canvas.width > 540 ? (canvas.width = 540) : "";
    }
    canvas.height = (canvas.width * 318) / 540;
  });
  const socket = new WebSocket(wsUrl);
  socket.onopen = function () {
    players[safeCanvasId] = new JSMpeg.Player(wsUrl, {
      canvas: document.getElementById(safeCanvasId),
      audio: true,
    });
    if (isSafeKey(safeCanvasId)) {
      playerStates[safeCanvasId] = {
        muted: true,
        playing: true,
      };
    }
    addPlayerControls(safeCanvasId, wsUrl);
  };

  socket.onmessage = function (event) {
    try {
      const message = event?.data;
      if (message.includes("Unauthorized")) {
        document.querySelector("#videoContainer").innerHTML = "";
        $("#videoContainer").append(
          `<p class="font-weight-bold text-center">User name or password is wrong! <br> Please provide a valid configurations in settings <span><a href="/settings.php">Go to settings</a></span></p>`
        );
      }
    } catch (e) {}
  };

  socket.onerror = function (error) {
    const player = players[safeCanvasId];
    if (player) {
      player.destroy();
      delete players[safeCanvasId]; // Remove the player from the dictionary
    }
  };

  socket.onclose = function () {
    const player = players[safeCanvasId];
    if (player) {
      player.destroy();
      delete players[safeCanvasId]; // Remove the player from the dictionary
    }
    document.querySelector(`#${safeCanvasId}div`).innerHTML = "";
    
    const reconnectButton = createReconnectButton(
      item?.id,
      `#${safeCanvasId}div`,
      "Connection has closed by server <br>Or Check your configurations"
    );
    
    $(`#${safeCanvasId}div`).append(reconnectButton.html);
    reconnectButton.bindEvent();
  };
}

function addPlayerControls(canvasId, wsUrl) {
  const safeCanvasId = String(canvasId);
  if (!safeCanvasId || !isSafeKey(safeCanvasId)) return;

  if (!playerStates.hasOwnProperty(safeCanvasId)) {
    playerStates[safeCanvasId] = { muted: true, playing: true };
  }
  console.log(safeCanvasId);
  const idOnly = safeCanvasId.replace("videoCanvas", "");
  players[safeCanvasId].volume = 0;
  const controlsHTML = `
    <div class="player-controls">
      <button id="playPause-${safeCanvasId}"><i class="fa-solid fa-pause"></i></button> <!--⏸️-->
      <button id="muteUnmute-${safeCanvasId}"><i class="fa-solid fa-volume-xmark"></i></button>
      <input type="range" id="volume-${safeCanvasId}" min="0" max="1" step="0.1" value="1" />
      <button id="fullscreen-${safeCanvasId}"><i class="fa-solid fa-maximize"></i></button>
      <button class="fa-solid fa-video mr-2 text-white cursor_pointer redirect-playback" style="line-height: unset;" data-id="${idOnly}"></button>
    </div>
  `;

  $(`#${safeCanvasId}div .player-controls-wrapper`).append(DOMPurify.sanitize(controlsHTML));

  $(`#volume-${safeCanvasId}`).val(0);

  $(`#playPause-${safeCanvasId}`).on("click", function () {
    const player = players[safeCanvasId];
    if (playerStates[safeCanvasId].playing) {
      player.pause();
      $(`#playPause-${safeCanvasId}`).html(`<i class="fa-solid fa-play"></i>`);
    } else {
      player.play();
      $(`#playPause-${safeCanvasId}`).html(`<i class="fa-solid fa-pause"></i>`);
    }
    if(!safeCanvasId) return;
    playerStates[safeCanvasId].playing = !playerStates[safeCanvasId].playing;
  });

  $(`#muteUnmute-${safeCanvasId}`).on("click", function () {
    const player = players[safeCanvasId];
    player.volume = player.volume > 0 ? 0 : 1;
    if (player.volume === 0) {
      $(this).html(`<i class="fa-solid fa-volume-xmark"></i>`);
      $(`#volume-${safeCanvasId}`).val(0);
    } else {
      $(this).html(`<i class="fa-solid fa-volume-high"></i>`);
      $(`#volume-${safeCanvasId}`).val(1);
    }
  });

  $(`#volume-${safeCanvasId}`).on("input", function () {
    const player = players[safeCanvasId];
    player.volume = parseFloat(this.value);

    if (player.volume === 0) {
      $(`#muteUnmute-${safeCanvasId}`).html(
        `<i class="fa-solid fa-volume-xmark"></i>`
      );
      $(`#volume-${safeCanvasId}`).val(0);
    } else {
      $(`#muteUnmute-${safeCanvasId}`).html(
        `<i class="fa-solid fa-volume-high"></i>`
      );
      $(`#volume-${safeCanvasId}`).val(player.volume);
    }
  });

  $(`#fullscreen-${safeCanvasId}`).on("click", function () {
    const canvas = document.getElementById(safeCanvasId);
    if (!document.fullscreenElement) {
      if (canvas.requestFullscreen) {
        canvas.requestFullscreen();
      } else if (canvas.webkitRequestFullscreen) {
        // Safari
        canvas.webkitRequestFullscreen();
      } else if (canvas.msRequestFullscreen) {
        // IE/Edge
        canvas.msRequestFullscreen();
      }
    } else {
      if (document.exitFullscreen) {
        document.exitFullscreen();
      } else if (document.webkitExitFullscreen) {
        // Safari
        document.webkitExitFullscreen();
      } else if (document.msExitFullscreen) {
        // IE/Edge
        document.msExitFullscreen();
      }
      $(this).text("🔳");
    }
  });
}

function cleanupPlayer(canvasId) {
  const safeCanvasId = String(canvasId);
  document.querySelector(`#${safeCanvasId}div`).innerHTML = "";
}

function ajaxRequestWithHeaders(url, type, payload) {
  return new Promise((resolve, reject) => {
    $.ajax({
      url,
      type,
      data: { data: payload.data },
      headers: payload.headers || {},
      success: resolve,
      error: reject,
    });
  });
}

function isSafeKey(key) {
  return typeof key === "string" &&
         /^[a-zA-Z0-9_-]+$/.test(key) &&
         ![
           "__proto__",
           "prototype",
           "constructor",
           "toString",
           "valueOf",
           "hasOwnProperty",
           "isPrototypeOf",
           "__defineGetter__",
           "__defineSetter__",
           "__lookupGetter__",
           "__lookupSetter__"
         ].includes(key);
}
