/**
 * Screenshot Service for Samsung
 * Captures screenshots and uploads them to the server
 * Similar to android_new/lib/services/screenshot_service.dart
 */

// Constants
const SCREENSHOT_CAPTURE_DELAY_MS = 10000; // 10 seconds delay before screenshot capture

class ScreenshotService {
  constructor() {
    this.socket = null;
    this.isCapturing = false;
  }

  /**
   * Set the socket instance for emitting events
   * @param {Socket} socket - Socket.io instance
   */
  setSocket(socket) {
    this.socket = socket;
    console.log("---- Screenshot Service: Socket set ----");
  }

  /**
   * Capture screenshot as base64 string
   * @returns {Promise<string|null>} Base64 encoded image or null
   */
  async captureAsBase64() {
    if (this.isCapturing) {
      console.log("---- Screenshot capture already in progress ----");
      return null;
    }

    this.isCapturing = true;

    try {
      console.log("---- Starting screenshot capture ----");

      // Try to capture iframes first (if any exist)
      const iframes = document.querySelectorAll("iframe");
      
      // For compositions with multiple iframes or regular content, 
      // use canvas-based screenshot of the entire viewport
      if (iframes.length > 1 || iframes.length === 0) {
        console.log(`---- Capturing viewport (${iframes.length} iframes detected) ----`);
        const base64Image = await this.captureViewport();
        this.isCapturing = false;
        return base64Image;
      }

      // For single iframe, try capturing it directly first
      if (iframes.length === 1) {
        console.log("---- Single iframe detected, attempting direct capture ----");
        try {
          const iframeCapture = await this.captureIframe(iframes[0]);
          if (iframeCapture) {
            console.log("---- Iframe captured successfully ----");
            this.isCapturing = false;
            return iframeCapture;
          }
        } catch (e) {
          console.log(`---- Iframe capture failed: ${e.message}, falling back to viewport ----`);
        }
      }

      // Fallback to viewport capture
      console.log("---- Falling back to viewport capture ----");
      const base64Image = await this.captureViewport();
      this.isCapturing = false;
      return base64Image;
    } catch (error) {
      console.error("---- Error capturing screenshot:", error, "----");
      this.isCapturing = false;
      return null;
    }
  }

  /**
   * Capture the entire viewport as screenshot
   * @returns {Promise<string|null>}
   */
  async captureViewport() {
    return new Promise((resolve) => {
      try {
        // Use html2canvas to capture the DOM
        console.log("---- Attempting viewport capture with CORS support ----");
        
        // First attempt: Try with CORS enabled for best quality
        html2canvas(document.body, {
          allowTaint: false,
          useCORS: true, // Enable CORS to capture images
          logging: true, // Enable logging to debug
          width: window.innerWidth,
          height: window.innerHeight,
          backgroundColor: '#000000', // Black background
          scale: 1, // 1:1 scale
          windowWidth: window.innerWidth,
          windowHeight: window.innerHeight,
          scrollX: 0,
          scrollY: 0,
          ignoreElements: (element) => {
            // Skip cross-origin iframes only
            if (element.tagName === 'IFRAME') {
              try {
                element.contentDocument;
                return false; // Can access, include it
              } catch (e) {
                console.log('---- Skipping cross-origin iframe ----');
                return true; // Cannot access, skip it
              }
            }
            // Skip loaders
            if (element.classList && element.classList.contains('loader-container')) {
              return true;
            }
            return false;
          },
          onclone: (clonedDoc) => {
            // Handle video elements - capture current frame
            const videos = document.querySelectorAll('video');
            const clonedVideos = clonedDoc.querySelectorAll('video');
            
            videos.forEach((video, index) => {
              if (clonedVideos[index] && !video.paused && video.readyState >= 2) {
                try {
                  // Create a canvas to capture the video frame
                  const canvas = clonedDoc.createElement('canvas');
                  canvas.width = video.videoWidth || video.offsetWidth;
                  canvas.height = video.videoHeight || video.offsetHeight;
                  canvas.style.cssText = window.getComputedStyle(video).cssText;
                  canvas.style.position = 'absolute';
                  canvas.style.left = video.offsetLeft + 'px';
                  canvas.style.top = video.offsetTop + 'px';
                  canvas.style.width = video.offsetWidth + 'px';
                  canvas.style.height = video.offsetHeight + 'px';
                  
                  const ctx = canvas.getContext('2d');
                  ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
                  
                  // Replace video with canvas in cloned document
                  clonedVideos[index].parentNode.replaceChild(canvas, clonedVideos[index]);
                  console.log(`---- Captured video frame ${index + 1} ----`);
                } catch (e) {
                  console.warn(`---- Could not capture video frame ${index + 1}:`, e.message, '----');
                }
              }
            });
          }
        }).then((canvas) => {
          const base64Image = canvas.toDataURL("image/png").split(",")[1];
          console.log(`---- Viewport Screenshot Captured (CORS mode): Size: ${base64Image.length}, Dimensions: ${canvas.width}x${canvas.height} ----`);
          resolve(base64Image);
        }).catch((error) => {
          console.warn("---- CORS mode failed, trying without CORS ----", error);
          
          // Fallback: Try without CORS if first attempt fails
          html2canvas(document.body, {
            allowTaint: false,
            useCORS: false,
            logging: true,
            width: window.innerWidth,
            height: window.innerHeight,
            backgroundColor: '#000000',
            scale: 1,
            windowWidth: window.innerWidth,
            windowHeight: window.innerHeight,
            scrollX: 0,
            scrollY: 0,
            ignoreElements: (element) => {
              if (element.tagName === 'IFRAME') {
                try {
                  element.contentDocument;
                  return false;
                } catch (e) {
                  return true;
                }
              }
              if (element.classList && element.classList.contains('loader-container')) {
                return true;
              }
              return false;
            },
            onclone: (clonedDoc) => {
              const videos = document.querySelectorAll('video');
              const clonedVideos = clonedDoc.querySelectorAll('video');
              
              videos.forEach((video, index) => {
                if (clonedVideos[index] && !video.paused && video.readyState >= 2) {
                  try {
                    const canvas = clonedDoc.createElement('canvas');
                    canvas.width = video.videoWidth || video.offsetWidth;
                    canvas.height = video.videoHeight || video.offsetHeight;
                    canvas.style.cssText = window.getComputedStyle(video).cssText;
                    canvas.style.position = 'absolute';
                    canvas.style.left = video.offsetLeft + 'px';
                    canvas.style.top = video.offsetTop + 'px';
                    canvas.style.width = video.offsetWidth + 'px';
                    canvas.style.height = video.offsetHeight + 'px';
                    
                    const ctx = canvas.getContext('2d');
                    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
                    
                    clonedVideos[index].parentNode.replaceChild(canvas, clonedVideos[index]);
                    console.log(`---- Captured video frame ${index + 1} (fallback) ----`);
                  } catch (e) {
                    console.warn(`---- Could not capture video frame ${index + 1}:`, e.message, '----');
                  }
                }
              });
            }
          }).then((canvas) => {
            const base64Image = canvas.toDataURL("image/png").split(",")[1];
            console.log(`---- Viewport Screenshot Captured (no-CORS mode): Size: ${base64Image.length}, Dimensions: ${canvas.width}x${canvas.height} ----`);
            resolve(base64Image);
          }).catch((fallbackError) => {
            console.error("---- Both CORS and no-CORS modes failed:", fallbackError, "----");
            resolve(null);
          });
        });
      } catch (error) {
        console.error("---- Error in captureViewport:", error, "----");
        resolve(null);
      }
    });
  }

  /**
   * Attempt to capture iframe content (may fail due to CORS)
   * @param {HTMLIFrameElement} iframe
   * @returns {Promise<string|null>}
   */
  async captureIframe(iframe) {
    return new Promise((resolve, reject) => {
      try {
        // This will only work for same-origin iframes
        const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
        
        html2canvas(iframeDoc.body, {
          allowTaint: false,
          useCORS: false,
          logging: true,
          backgroundColor: '#000000',
          scale: 1,
        }).then((canvas) => {
          const base64Image = canvas.toDataURL("image/png").split(",")[1];
          console.log(`---- Iframe Screenshot Captured: Size: ${base64Image.length}, Dimensions: ${canvas.width}x${canvas.height} ----`);
          resolve(base64Image);
        }).catch((error) => {
          reject(new Error(`html2canvas iframe error: ${error.message}`));
        });
      } catch (error) {
        reject(new Error(`Cannot access iframe content (CORS): ${error.message}`));
      }
    });
  }

  /**
   * Upload screenshot to the server
   * @param {string} base64Image - Base64 encoded image
   * @param {string} deviceId - Device MAC ID
   */
  async uploadScreenshot(base64Image, deviceId) {
    try {
      const url = "https://back.disploy.com/api/NewScreen/CaptureCurrentView";

      console.log("---- Uploading screenshot to API... ----");
      const response = await axios.post(
        url,
        {
          macID: deviceId,
          file: base64Image,
        },
        {
          headers: {
            "Content-Type": "application/json",
          },
        }
      );

      if (response.status === 200 || response.status === 201) {
        console.log("---- Screenshot uploaded successfully Res:", response.data, "----");
        const responseBody = response.data;

        if (this.socket && this.socket.connected) {
          this.socket.emit("GetScreenPreview", {
            id: this.socket.id,
            connection: true,
            macId: deviceId,
            s3Url: responseBody.s3Url || "",
            isAdded: responseBody.isAdded || false,
          });
          console.log("---- Socket GetScreenPreview emitted successfully ----");
        } else {
          console.log("---- Socket not connected, skipping GetScreenPreview emit ----");
        }
      } else {
        console.log(`---- Screenshot upload failed with status: ${response.status} ----`);
      }
    } catch (error) {
      console.error("---- Error uploading screenshot:", error, "----");
    }
  }

  /**
   * Capture and upload screenshot
   * @param {string} deviceId - Device MAC ID
   * @param {string} screenName - Optional screen name
   */
  async captureAndUpload(deviceId, screenName = null) {
    try {
      // Wait before capturing to ensure content is loaded
      await new Promise((resolve) => setTimeout(resolve, SCREENSHOT_CAPTURE_DELAY_MS));

      console.log(`---- Capturing screenshot for device: ${deviceId} ----`);

      const base64Image = await this.captureAsBase64();

      if (!base64Image) {
        console.log("---- Failed to capture screenshot: base64Image is null ----");
        return;
      }

      console.log(`---- Screenshot captured, uploading... ----`);
      // Upload in background (don't await)
      this.uploadScreenshot(base64Image, deviceId);
    } catch (error) {
      console.error("---- Error in captureAndUpload:", error, "----");
    }
  }
}

// Create a singleton instance
const screenshotService = new ScreenshotService();
