// renderer.js
const { ipcRenderer } = require("electron");

let mediaStream = null;
let screenshotInterval = null;
let audioContext = null;
let audioProcessor = null;
let micAudioProcessor = null;
let audioBuffer = [];
const SAMPLE_RATE = 24000;
const AUDIO_CHUNK_DURATION = 0.1; // seconds
const BUFFER_SIZE = 4096; // Increased buffer size for smoother audio

let hiddenVideo = null;
let offscreenCanvas = null;
let offscreenContext = null;
let currentImageQuality = "medium"; // Store current image quality for manual screenshots

const isLinux = process.platform === "linux";
const isMacOS = process.platform === "darwin";

// ============ STORAGE API ============
// Wrapper for IPC-based storage access
const storage = {
  // Config
  async getConfig() {
    const result = await ipcRenderer.invoke("storage:get-config");
    return result.success ? result.data : {};
  },
  async setConfig(config) {
    return ipcRenderer.invoke("storage:set-config", config);
  },
  async updateConfig(key, value) {
    return ipcRenderer.invoke("storage:update-config", key, value);
  },

  // Credentials
  async getCredentials() {
    const result = await ipcRenderer.invoke("storage:get-credentials");
    return result.success ? result.data : {};
  },
  async setCredentials(credentials) {
    return ipcRenderer.invoke("storage:set-credentials", credentials);
  },
  async getApiKey() {
    const result = await ipcRenderer.invoke("storage:get-api-key");
    return result.success ? result.data : "";
  },
  async setApiKey(apiKey) {
    return ipcRenderer.invoke("storage:set-api-key", apiKey);
  },
  async getGroqApiKey() {
    const result = await ipcRenderer.invoke("storage:get-groq-api-key");
    return result.success ? result.data : "";
  },
  async setGroqApiKey(groqApiKey) {
    return ipcRenderer.invoke("storage:set-groq-api-key", groqApiKey);
  },
  async getOpenAICompatibleConfig() {
    const result = await ipcRenderer.invoke("get-openai-compatible-config");
    return result.success
      ? result.config
      : { apiKey: "", baseUrl: "", model: "" };
  },
  async setOpenAICompatibleConfig(apiKey, baseUrl, model) {
    return ipcRenderer.invoke(
      "set-openai-compatible-config",
      apiKey,
      baseUrl,
      model,
    );
  },

  // Preferences
  async getPreferences() {
    const result = await ipcRenderer.invoke("storage:get-preferences");
    return result.success ? result.data : {};
  },
  async setPreferences(preferences) {
    return ipcRenderer.invoke("storage:set-preferences", preferences);
  },
  async updatePreference(key, value) {
    return ipcRenderer.invoke("storage:update-preference", key, value);
  },

  // Keybinds
  async getKeybinds() {
    const result = await ipcRenderer.invoke("storage:get-keybinds");
    return result.success ? result.data : null;
  },
  async setKeybinds(keybinds) {
    return ipcRenderer.invoke("storage:set-keybinds", keybinds);
  },

  // Sessions (History)
  async getAllSessions() {
    const result = await ipcRenderer.invoke("storage:get-all-sessions");
    return result.success ? result.data : [];
  },
  async getSession(sessionId) {
    const result = await ipcRenderer.invoke("storage:get-session", sessionId);
    return result.success ? result.data : null;
  },
  async saveSession(sessionId, data) {
    return ipcRenderer.invoke("storage:save-session", sessionId, data);
  },
  async deleteSession(sessionId) {
    return ipcRenderer.invoke("storage:delete-session", sessionId);
  },
  async deleteAllSessions() {
    return ipcRenderer.invoke("storage:delete-all-sessions");
  },

  // Clear all
  async clearAll() {
    return ipcRenderer.invoke("storage:clear-all");
  },

  // Limits
  async getTodayLimits() {
    const result = await ipcRenderer.invoke("storage:get-today-limits");
    return result.success
      ? result.data
      : { flash: { count: 0 }, flashLite: { count: 0 } };
  },
};

// Cache for preferences to avoid async calls in hot paths
let preferencesCache = null;

async function loadPreferencesCache() {
  preferencesCache = await storage.getPreferences();
  return preferencesCache;
}

// Initialize preferences cache
loadPreferencesCache();

function convertFloat32ToInt16(float32Array) {
  const int16Array = new Int16Array(float32Array.length);
  for (let i = 0; i < float32Array.length; i++) {
    // Improved scaling to prevent clipping
    const s = Math.max(-1, Math.min(1, float32Array[i]));
    int16Array[i] = s < 0 ? s * 0x8000 : s * 0x7fff;
  }
  return int16Array;
}

function arrayBufferToBase64(buffer) {
  let binary = "";
  const bytes = new Uint8Array(buffer);
  const len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return btoa(binary);
}

async function initializeGemini(profile = "interview", language = "en-US") {
  const apiKey = await storage.getApiKey();
  if (apiKey) {
    const prefs = await storage.getPreferences();
    const success = await ipcRenderer.invoke(
      "initialize-gemini",
      apiKey,
      prefs.customPrompt || "",
      profile,
      language,
    );
    if (success) {
      cheatingDaddy.setStatus("Live");
    } else {
      cheatingDaddy.setStatus("error");
    }
  }
}

async function initializeLocal(profile = "interview") {
  const prefs = await storage.getPreferences();
  const localConfig = {
    llmProvider: prefs.llmProvider || "lmstudio",
    sttProvider: prefs.sttProvider || "nemotron-sidecar",
    localLlmBaseUrl: prefs.localLlmBaseUrl || "http://127.0.0.1:1234/v1",
    localLlmModel: prefs.localLlmModel || "",
    localLlmApiKey: prefs.localLlmApiKey || "",
    localSttUrl: prefs.localSttUrl || "ws://127.0.0.1:8765/v1/asr/stream",
    localSttLanguage: prefs.localSttLanguage || "en-US",
    ollamaHost: prefs.ollamaHost || "http://127.0.0.1:11434",
    ollamaModel: prefs.ollamaModel || "llama3.1",
    whisperModel: prefs.whisperModel || "Xenova/whisper-small",
    profile,
    customPrompt: prefs.customPrompt || "",
  };

  const success = await ipcRenderer.invoke("initialize-local", localConfig);
  if (success) {
    cheatingDaddy.setStatus("Local AI Live");
    return true;
  } else {
    cheatingDaddy.setStatus("error");
    return false;
  }
}

// Listen for status updates
ipcRenderer.on("update-status", (event, status) => {
  console.log("Status update:", status);
  cheatingDaddy.setStatus(status);
});

async function startCapture(
  screenshotIntervalSeconds = 5,
  imageQuality = "medium",
) {
  // Store the image quality for manual screenshots
  currentImageQuality = imageQuality;

  // Refresh preferences cache
  await loadPreferencesCache();
  const audioMode = preferencesCache.audioMode || "speaker_only";

  try {
    if (isMacOS) {
      // On macOS, use SystemAudioDump for audio and getDisplayMedia for screen
      console.log("Starting macOS capture with SystemAudioDump...");

      // Start macOS audio capture
      const audioResult = await ipcRenderer.invoke("start-macos-audio");
      if (!audioResult.success) {
        throw new Error(
          "Failed to start macOS audio capture: " + audioResult.error,
        );
      }

      // Get screen capture for screenshots
      mediaStream = await navigator.mediaDevices.getDisplayMedia({
        video: {
          frameRate: 1,
          width: { ideal: 1920 },
          height: { ideal: 1080 },
        },
        audio: false, // Don't use browser audio on macOS
      });

      console.log(
        "macOS screen capture started - audio handled by SystemAudioDump",
      );

      if (audioMode === "mic_only" || audioMode === "both") {
        let micStream = null;
        try {
          micStream = await navigator.mediaDevices.getUserMedia({
            audio: {
              sampleRate: SAMPLE_RATE,
              channelCount: 1,
              echoCancellation: true,
              noiseSuppression: true,
              autoGainControl: true,
            },
            video: false,
          });
          console.log("macOS microphone capture started");
          setupLinuxMicProcessing(micStream);
        } catch (micError) {
          console.warn("Failed to get microphone access on macOS:", micError);
        }
      }
    } else if (isLinux) {
      // Linux - use display media for screen capture and try to get system audio
      try {
        // First try to get system audio via getDisplayMedia (works on newer browsers)
        mediaStream = await navigator.mediaDevices.getDisplayMedia({
          video: {
            frameRate: 1,
            width: { ideal: 1920 },
            height: { ideal: 1080 },
          },
          audio: {
            sampleRate: SAMPLE_RATE,
            channelCount: 1,
            echoCancellation: false, // Don't cancel system audio
            noiseSuppression: false,
            autoGainControl: false,
          },
        });

        console.log("Linux system audio capture via getDisplayMedia succeeded");

        // Setup audio processing for Linux system audio
        setupLinuxSystemAudioProcessing();
      } catch (systemAudioError) {
        console.warn(
          "System audio via getDisplayMedia failed, trying screen-only capture:",
          systemAudioError,
        );

        // Fallback to screen-only capture
        mediaStream = await navigator.mediaDevices.getDisplayMedia({
          video: {
            frameRate: 1,
            width: { ideal: 1920 },
            height: { ideal: 1080 },
          },
          audio: false,
        });
      }

      // Additionally get microphone input for Linux based on audio mode
      if (audioMode === "mic_only" || audioMode === "both") {
        let micStream = null;
        try {
          micStream = await navigator.mediaDevices.getUserMedia({
            audio: {
              sampleRate: SAMPLE_RATE,
              channelCount: 1,
              echoCancellation: true,
              noiseSuppression: true,
              autoGainControl: true,
            },
            video: false,
          });

          console.log("Linux microphone capture started");

          // Setup audio processing for microphone on Linux
          setupLinuxMicProcessing(micStream);
        } catch (micError) {
          console.warn("Failed to get microphone access on Linux:", micError);
          // Continue without microphone if permission denied
        }
      }

      console.log(
        "Linux capture started - system audio:",
        mediaStream.getAudioTracks().length > 0,
        "microphone mode:",
        audioMode,
      );
    } else {
      // Windows - use display media with loopback for system audio
      mediaStream = await navigator.mediaDevices.getDisplayMedia({
        video: {
          frameRate: 1,
          width: { ideal: 1920 },
          height: { ideal: 1080 },
        },
        audio: {
          sampleRate: SAMPLE_RATE,
          channelCount: 1,
          echoCancellation: true,
          noiseSuppression: true,
          autoGainControl: true,
        },
      });

      console.log("Windows capture started with loopback audio");

      // Setup audio processing for Windows loopback audio only
      setupWindowsLoopbackProcessing();

      if (audioMode === "mic_only" || audioMode === "both") {
        let micStream = null;
        try {
          micStream = await navigator.mediaDevices.getUserMedia({
            audio: {
              sampleRate: SAMPLE_RATE,
              channelCount: 1,
              echoCancellation: true,
              noiseSuppression: true,
              autoGainControl: true,
            },
            video: false,
          });
          console.log("Windows microphone capture started");
          setupLinuxMicProcessing(micStream);
        } catch (micError) {
          console.warn("Failed to get microphone access on Windows:", micError);
        }
      }
    }

    console.log("MediaStream obtained:", {
      hasVideo: mediaStream.getVideoTracks().length > 0,
      hasAudio: mediaStream.getAudioTracks().length > 0,
      videoTrack: mediaStream.getVideoTracks()[0]?.getSettings(),
    });

    // Manual mode only - screenshots captured on demand via shortcut
    console.log(
      "Manual mode enabled - screenshots will be captured on demand only",
    );
  } catch (err) {
    console.error("Error starting capture:", err);
    cheatingDaddy.setStatus("error");
  }
}

function setupLinuxMicProcessing(micStream) {
  // Setup microphone audio processing for Linux
  const micAudioContext = new AudioContext({ sampleRate: SAMPLE_RATE });
  const micSource = micAudioContext.createMediaStreamSource(micStream);
  const micProcessor = micAudioContext.createScriptProcessor(BUFFER_SIZE, 1, 1);

  let audioBuffer = [];
  const samplesPerChunk = SAMPLE_RATE * AUDIO_CHUNK_DURATION;

  micProcessor.onaudioprocess = async (e) => {
    const inputData = e.inputBuffer.getChannelData(0);
    audioBuffer.push(...inputData);

    // Process audio in chunks
    while (audioBuffer.length >= samplesPerChunk) {
      const chunk = audioBuffer.splice(0, samplesPerChunk);
      const pcmData16 = convertFloat32ToInt16(chunk);
      const base64Data = arrayBufferToBase64(pcmData16.buffer);

      await ipcRenderer.invoke("send-mic-audio-content", {
        data: base64Data,
        mimeType: "audio/pcm;rate=24000",
      });
    }
  };

  micSource.connect(micProcessor);
  micProcessor.connect(micAudioContext.destination);

  // Store processor reference for cleanup
  micAudioProcessor = micProcessor;
}

function setupLinuxSystemAudioProcessing() {
  // Setup system audio processing for Linux (from getDisplayMedia)
  audioContext = new AudioContext({ sampleRate: SAMPLE_RATE });
  const source = audioContext.createMediaStreamSource(mediaStream);
  audioProcessor = audioContext.createScriptProcessor(BUFFER_SIZE, 1, 1);

  let audioBuffer = [];
  const samplesPerChunk = SAMPLE_RATE * AUDIO_CHUNK_DURATION;

  audioProcessor.onaudioprocess = async (e) => {
    const inputData = e.inputBuffer.getChannelData(0);
    audioBuffer.push(...inputData);

    // Process audio in chunks
    while (audioBuffer.length >= samplesPerChunk) {
      const chunk = audioBuffer.splice(0, samplesPerChunk);
      const pcmData16 = convertFloat32ToInt16(chunk);
      const base64Data = arrayBufferToBase64(pcmData16.buffer);

      await ipcRenderer.invoke("send-audio-content", {
        data: base64Data,
        mimeType: "audio/pcm;rate=24000",
      });
    }
  };

  source.connect(audioProcessor);
  audioProcessor.connect(audioContext.destination);
}

function setupWindowsLoopbackProcessing() {
  // Setup audio processing for Windows loopback audio only
  audioContext = new AudioContext({ sampleRate: SAMPLE_RATE });
  const source = audioContext.createMediaStreamSource(mediaStream);
  audioProcessor = audioContext.createScriptProcessor(BUFFER_SIZE, 1, 1);

  let audioBuffer = [];
  const samplesPerChunk = SAMPLE_RATE * AUDIO_CHUNK_DURATION;

  audioProcessor.onaudioprocess = async (e) => {
    const inputData = e.inputBuffer.getChannelData(0);
    audioBuffer.push(...inputData);

    // Process audio in chunks
    while (audioBuffer.length >= samplesPerChunk) {
      const chunk = audioBuffer.splice(0, samplesPerChunk);
      const pcmData16 = convertFloat32ToInt16(chunk);
      const base64Data = arrayBufferToBase64(pcmData16.buffer);

      await ipcRenderer.invoke("send-audio-content", {
        data: base64Data,
        mimeType: "audio/pcm;rate=24000",
      });
    }
  };

  source.connect(audioProcessor);
  audioProcessor.connect(audioContext.destination);
}

async function captureScreenshot(imageQuality = "medium", isManual = false) {
  console.log(`Capturing ${isManual ? "manual" : "automated"} screenshot...`);
  if (!mediaStream) return;

  // Lazy init of video element
  if (!hiddenVideo) {
    hiddenVideo = document.createElement("video");
    hiddenVideo.srcObject = mediaStream;
    hiddenVideo.muted = true;
    hiddenVideo.playsInline = true;
    await hiddenVideo.play();

    await new Promise((resolve) => {
      if (hiddenVideo.readyState >= 2) return resolve();
      hiddenVideo.onloadedmetadata = () => resolve();
    });

    // Lazy init of canvas based on video dimensions
    offscreenCanvas = document.createElement("canvas");
    offscreenCanvas.width = hiddenVideo.videoWidth;
    offscreenCanvas.height = hiddenVideo.videoHeight;
    offscreenContext = offscreenCanvas.getContext("2d");
  }

  // Check if video is ready
  if (hiddenVideo.readyState < 2) {
    console.warn("Video not ready yet, skipping screenshot");
    return;
  }

  offscreenContext.drawImage(
    hiddenVideo,
    0,
    0,
    offscreenCanvas.width,
    offscreenCanvas.height,
  );

  // Check if image was drawn properly by sampling a pixel
  const imageData = offscreenContext.getImageData(0, 0, 1, 1);
  const isBlank = imageData.data.every((value, index) => {
    // Check if all pixels are black (0,0,0) or transparent
    return index === 3 ? true : value === 0;
  });

  if (isBlank) {
    console.warn("Screenshot appears to be blank/black");
  }

  let qualityValue;
  switch (imageQuality) {
    case "high":
      qualityValue = 0.9;
      break;
    case "medium":
      qualityValue = 0.7;
      break;
    case "low":
      qualityValue = 0.5;
      break;
    default:
      qualityValue = 0.7; // Default to medium
  }

  offscreenCanvas.toBlob(
    async (blob) => {
      if (!blob) {
        console.error("Failed to create blob from canvas");
        return;
      }

      const reader = new FileReader();
      reader.onloadend = async () => {
        const base64data = reader.result.split(",")[1];

        // Validate base64 data
        if (!base64data || base64data.length < 100) {
          console.error("Invalid base64 data generated");
          return;
        }

        const result = await ipcRenderer.invoke("send-image-content", {
          data: base64data,
        });

        if (result.success) {
          console.log(
            `Image sent successfully (${offscreenCanvas.width}x${offscreenCanvas.height})`,
          );
        } else {
          console.error("Failed to send image:", result.error);
        }
      };
      reader.readAsDataURL(blob);
    },
    "image/jpeg",
    qualityValue,
  );
}

const MANUAL_SCREENSHOT_PROMPT = `Analyze this screen and help me. Give me the answer directly, no BS.
- If it's a coding problem, algorithm challenge, or live coding exercise: provide 2-3 bullet approach points, then the COMPLETE WORKING CODE with comments. Never say "open your IDE" — give the actual code.
- If it's a question about the website content, give me the direct answer.
- If it's a multiple choice question, give me the correct answer with brief justification.
- If there's anything else important on screen, tell me.`;

async function captureManualScreenshot(imageQuality = null) {
  console.log("Manual screenshot triggered");
  const quality = imageQuality || currentImageQuality;

  if (!mediaStream) {
    console.error("No media stream available");
    return;
  }

  // Lazy init of video element
  if (!hiddenVideo) {
    hiddenVideo = document.createElement("video");
    hiddenVideo.srcObject = mediaStream;
    hiddenVideo.muted = true;
    hiddenVideo.playsInline = true;
    await hiddenVideo.play();

    await new Promise((resolve) => {
      if (hiddenVideo.readyState >= 2) return resolve();
      hiddenVideo.onloadedmetadata = () => resolve();
    });

    // Lazy init of canvas based on video dimensions
    offscreenCanvas = document.createElement("canvas");
    offscreenCanvas.width = hiddenVideo.videoWidth;
    offscreenCanvas.height = hiddenVideo.videoHeight;
    offscreenContext = offscreenCanvas.getContext("2d");
  }

  // Check if video is ready
  if (hiddenVideo.readyState < 2) {
    console.warn("Video not ready yet, skipping screenshot");
    return;
  }

  // Downscale to max 1280px wide for faster transfer — vision models don't need 4K
  const MAX_WIDTH = 1280;
  const srcW = hiddenVideo.videoWidth;
  const srcH = hiddenVideo.videoHeight;
  let destW = srcW;
  let destH = srcH;
  if (srcW > MAX_WIDTH) {
    destW = MAX_WIDTH;
    destH = Math.round(srcH * (MAX_WIDTH / srcW));
  }
  offscreenCanvas.width = destW;
  offscreenCanvas.height = destH;
  offscreenContext.drawImage(hiddenVideo, 0, 0, destW, destH);

  let qualityValue;
  switch (quality) {
    case "high":
      qualityValue = 0.85;
      break;
    case "medium":
      qualityValue = 0.6;
      break;
    case "low":
      qualityValue = 0.4;
      break;
    default:
      qualityValue = 0.6;
  }

  offscreenCanvas.toBlob(
    async (blob) => {
      if (!blob) {
        console.error("Failed to create blob from canvas");
        return;
      }

      const reader = new FileReader();
      reader.onloadend = async () => {
        const base64data = reader.result.split(",")[1];

        if (!base64data || base64data.length < 100) {
          console.error("Invalid base64 data generated");
          return;
        }

        console.log(
          `Sending image: ${destW}x${destH}, ~${Math.round(base64data.length / 1024)}KB`,
        );

        // Send image with prompt to HTTP API (response streams via IPC events)
        const result = await ipcRenderer.invoke("send-image-content", {
          data: base64data,
          prompt: MANUAL_SCREENSHOT_PROMPT,
        });

        if (result.success) {
          console.log(`Image response completed from ${result.model}`);
          // Response already displayed via streaming events (new-response/update-response)
        } else {
          console.error("Failed to get image response:", result.error);
          cheatingDaddy.addNewResponse(`Error: ${result.error}`);
        }
      };
      reader.readAsDataURL(blob);
    },
    "image/jpeg",
    qualityValue,
  );
}

// Expose functions to global scope for external access
window.captureManualScreenshot = captureManualScreenshot;

function stopCapture() {
  if (screenshotInterval) {
    clearInterval(screenshotInterval);
    screenshotInterval = null;
  }

  if (audioProcessor) {
    audioProcessor.disconnect();
    audioProcessor = null;
  }

  // Clean up microphone audio processor (Linux only)
  if (micAudioProcessor) {
    micAudioProcessor.disconnect();
    micAudioProcessor = null;
  }

  if (audioContext) {
    audioContext.close();
    audioContext = null;
  }

  if (mediaStream) {
    mediaStream.getTracks().forEach((track) => track.stop());
    mediaStream = null;
  }

  // Stop macOS audio capture if running
  if (isMacOS) {
    ipcRenderer.invoke("stop-macos-audio").catch((err) => {
      console.error("Error stopping macOS audio:", err);
    });
  }

  // Clean up hidden elements
  if (hiddenVideo) {
    hiddenVideo.pause();
    hiddenVideo.srcObject = null;
    hiddenVideo = null;
  }
  offscreenCanvas = null;
  offscreenContext = null;
}

// Send text message to Gemini
async function sendTextMessage(text) {
  if (!text || text.trim().length === 0) {
    console.warn("Cannot send empty text message");
    return { success: false, error: "Empty message" };
  }

  try {
    const result = await ipcRenderer.invoke("send-text-message", text);
    if (result.success) {
      console.log("Text message sent successfully");
    } else {
      console.error("Failed to send text message:", result.error);
    }
    return result;
  } catch (error) {
    console.error("Error sending text message:", error);
    return { success: false, error: error.message };
  }
}

// Expand the last response — continues the conversation with a detailed version
async function expandLastResponse() {
  const app = cheatingDaddyApp;
  if (!app || app.responses.length === 0 || app.currentResponseIndex < 0) {
    console.warn("No response to expand");
    return { success: false, error: "No response to expand" };
  }

  const previousResponse = app.responses[app.currentResponseIndex];
  if (!previousResponse || previousResponse.trim().length === 0) {
    console.warn("Current response is empty");
    return { success: false, error: "Current response is empty" };
  }

  try {
    const result = await ipcRenderer.invoke("expand-last-response", {
      previousResponse: previousResponse,
      originalContext: "",
    });

    if (result.success) {
      console.log("Expand request sent successfully");
    } else {
      console.error("Failed to expand response:", result.error);
    }
    return result;
  } catch (error) {
    console.error("Error expanding response:", error);
    return { success: false, error: error.message };
  }
}

// Listen for conversation data from main process and save to storage
ipcRenderer.on("save-conversation-turn", async (event, data) => {
  try {
    await storage.saveSession(data.sessionId, {
      conversationHistory: data.fullHistory,
    });
    console.log("Conversation session saved:", data.sessionId);
  } catch (error) {
    console.error("Error saving conversation session:", error);
  }
});

// Listen for session context (profile info) when session starts
ipcRenderer.on("save-session-context", async (event, data) => {
  try {
    await storage.saveSession(data.sessionId, {
      profile: data.profile,
      customPrompt: data.customPrompt,
    });
    console.log(
      "Session context saved:",
      data.sessionId,
      "profile:",
      data.profile,
    );
  } catch (error) {
    console.error("Error saving session context:", error);
  }
});

// Listen for screen analysis responses (from ctrl+enter)
ipcRenderer.on("save-screen-analysis", async (event, data) => {
  try {
    await storage.saveSession(data.sessionId, {
      screenAnalysisHistory: data.fullHistory,
      profile: data.profile,
      customPrompt: data.customPrompt,
    });
    console.log("Screen analysis saved:", data.sessionId);
  } catch (error) {
    console.error("Error saving screen analysis:", error);
  }
});

// Listen for emergency erase command from main process
ipcRenderer.on("clear-sensitive-data", async () => {
  console.log("Clearing all data...");
  await storage.clearAll();
});

// Handle shortcuts based on current view
function handleShortcut(shortcutKey) {
  const currentView = cheatingDaddy.getCurrentView();

  if (shortcutKey === "ctrl+enter" || shortcutKey === "cmd+enter") {
    if (currentView === "main") {
      cheatingDaddy.element().handleStart();
    } else {
      captureManualScreenshot();
    }
  }
}

// Create reference to the main app element
const cheatingDaddyApp = document.querySelector("cheating-daddy-app");

// ============ THEME SYSTEM ============
const theme = {
  themes: {
    dark: {
      background: "#101010",
      text: "#e0e0e0",
      textSecondary: "#a0a0a0",
      textMuted: "#6b6b6b",
      border: "#2a2a2a",
      accent: "#ffffff",
      btnPrimaryBg: "#ffffff",
      btnPrimaryText: "#000000",
      btnPrimaryHover: "#e0e0e0",
      tooltipBg: "#1a1a1a",
      tooltipText: "#ffffff",
      keyBg: "rgba(255,255,255,0.1)",
    },
    light: {
      background: "#ffffff",
      text: "#1a1a1a",
      textSecondary: "#555555",
      textMuted: "#888888",
      border: "#e0e0e0",
      accent: "#000000",
      btnPrimaryBg: "#1a1a1a",
      btnPrimaryText: "#ffffff",
      btnPrimaryHover: "#333333",
      tooltipBg: "#1a1a1a",
      tooltipText: "#ffffff",
      keyBg: "rgba(0,0,0,0.1)",
    },
    midnight: {
      background: "#0d1117",
      text: "#c9d1d9",
      textSecondary: "#8b949e",
      textMuted: "#6e7681",
      border: "#30363d",
      accent: "#58a6ff",
      btnPrimaryBg: "#58a6ff",
      btnPrimaryText: "#0d1117",
      btnPrimaryHover: "#79b8ff",
      tooltipBg: "#161b22",
      tooltipText: "#c9d1d9",
      keyBg: "rgba(88,166,255,0.15)",
    },
    sepia: {
      background: "#f4ecd8",
      text: "#5c4b37",
      textSecondary: "#7a6a56",
      textMuted: "#998875",
      border: "#d4c8b0",
      accent: "#8b4513",
      btnPrimaryBg: "#5c4b37",
      btnPrimaryText: "#f4ecd8",
      btnPrimaryHover: "#7a6a56",
      tooltipBg: "#5c4b37",
      tooltipText: "#f4ecd8",
      keyBg: "rgba(92,75,55,0.15)",
    },
    catppuccin: {
      background: "#1e1e2e",
      text: "#cdd6f4",
      textSecondary: "#a6adc8",
      textMuted: "#585b70",
      border: "#313244",
      accent: "#cba6f7",
      btnPrimaryBg: "#cba6f7",
      btnPrimaryText: "#1e1e2e",
      btnPrimaryHover: "#b4befe",
      tooltipBg: "#313244",
      tooltipText: "#cdd6f4",
      keyBg: "rgba(203,166,247,0.12)",
    },
    gruvbox: {
      background: "#1d2021",
      text: "#ebdbb2",
      textSecondary: "#a89984",
      textMuted: "#665c54",
      border: "#3c3836",
      accent: "#fe8019",
      btnPrimaryBg: "#fe8019",
      btnPrimaryText: "#1d2021",
      btnPrimaryHover: "#fabd2f",
      tooltipBg: "#3c3836",
      tooltipText: "#ebdbb2",
      keyBg: "rgba(254,128,25,0.12)",
    },
    rosepine: {
      background: "#191724",
      text: "#e0def4",
      textSecondary: "#908caa",
      textMuted: "#6e6a86",
      border: "#26233a",
      accent: "#ebbcba",
      btnPrimaryBg: "#ebbcba",
      btnPrimaryText: "#191724",
      btnPrimaryHover: "#f6c177",
      tooltipBg: "#26233a",
      tooltipText: "#e0def4",
      keyBg: "rgba(235,188,186,0.12)",
    },
    solarized: {
      background: "#002b36",
      text: "#93a1a1",
      textSecondary: "#839496",
      textMuted: "#586e75",
      border: "#073642",
      accent: "#2aa198",
      btnPrimaryBg: "#2aa198",
      btnPrimaryText: "#002b36",
      btnPrimaryHover: "#268bd2",
      tooltipBg: "#073642",
      tooltipText: "#93a1a1",
      keyBg: "rgba(42,161,152,0.12)",
    },
    tokyonight: {
      background: "#1a1b26",
      text: "#c0caf5",
      textSecondary: "#9aa5ce",
      textMuted: "#565f89",
      border: "#292e42",
      accent: "#7aa2f7",
      btnPrimaryBg: "#7aa2f7",
      btnPrimaryText: "#1a1b26",
      btnPrimaryHover: "#bb9af7",
      tooltipBg: "#292e42",
      tooltipText: "#c0caf5",
      keyBg: "rgba(122,162,247,0.12)",
    },
  },

  current: "dark",

  get(name) {
    return this.themes[name] || this.themes.dark;
  },

  getAll() {
    const names = {
      dark: "Dark",
      light: "Light",
      midnight: "Midnight Blue",
      sepia: "Sepia",
      catppuccin: "Catppuccin Mocha",
      gruvbox: "Gruvbox Dark",
      rosepine: "Ros\u00e9 Pine",
      solarized: "Solarized Dark",
      tokyonight: "Tokyo Night",
    };
    return Object.keys(this.themes).map((key) => ({
      value: key,
      name: names[key] || key,
      colors: this.themes[key],
    }));
  },

  hexToRgb(hex) {
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result
      ? {
          r: parseInt(result[1], 16),
          g: parseInt(result[2], 16),
          b: parseInt(result[3], 16),
        }
      : { r: 30, g: 30, b: 30 };
  },

  lightenColor(rgb, amount) {
    return {
      r: Math.min(255, rgb.r + amount),
      g: Math.min(255, rgb.g + amount),
      b: Math.min(255, rgb.b + amount),
    };
  },

  darkenColor(rgb, amount) {
    return {
      r: Math.max(0, rgb.r - amount),
      g: Math.max(0, rgb.g - amount),
      b: Math.max(0, rgb.b - amount),
    };
  },

  applyBackgrounds(backgroundColor, alpha = 0.8) {
    const root = document.documentElement;
    const baseRgb = this.hexToRgb(backgroundColor);

    // For light themes, darken; for dark themes, lighten
    const isLight = (baseRgb.r + baseRgb.g + baseRgb.b) / 3 > 128;
    const adjust = isLight
      ? this.darkenColor.bind(this)
      : this.lightenColor.bind(this);

    const secondary = adjust(baseRgb, 10);
    const tertiary = adjust(baseRgb, 22);
    const hover = adjust(baseRgb, 28);

    const bgBase = `rgba(${baseRgb.r}, ${baseRgb.g}, ${baseRgb.b}, ${alpha})`;
    const bgSurface = `rgba(${secondary.r}, ${secondary.g}, ${secondary.b}, ${alpha})`;
    const bgElevated = `rgba(${tertiary.r}, ${tertiary.g}, ${tertiary.b}, ${alpha})`;
    const bgHover = `rgba(${hover.r}, ${hover.g}, ${hover.b}, ${alpha})`;

    // New design tokens (used by components)
    root.style.setProperty("--bg-app", bgBase);
    root.style.setProperty("--bg-surface", bgSurface);
    root.style.setProperty("--bg-elevated", bgElevated);
    root.style.setProperty("--bg-hover", bgHover);

    // Legacy aliases
    root.style.setProperty("--header-background", bgBase);
    root.style.setProperty("--main-content-background", bgBase);
    root.style.setProperty("--bg-primary", bgBase);
    root.style.setProperty("--bg-secondary", bgSurface);
    root.style.setProperty("--bg-tertiary", bgElevated);
    root.style.setProperty("--input-background", bgElevated);
    root.style.setProperty("--input-focus-background", bgElevated);
    root.style.setProperty("--hover-background", bgHover);
    root.style.setProperty("--scrollbar-background", bgBase);
  },

  apply(themeName, alpha = 0.8) {
    const colors = this.get(themeName);
    this.current = themeName;
    const root = document.documentElement;

    // Determine if theme is light or dark
    const lightThemes = ["light", "sepia"];
    const isLightTheme = lightThemes.includes(themeName);
    document.body.setAttribute(
      "data-theme-type",
      isLightTheme ? "light" : "dark",
    );

    // New design tokens (used by components)
    root.style.setProperty("--text-primary", colors.text);
    root.style.setProperty("--text-secondary", colors.textSecondary);
    root.style.setProperty("--text-muted", colors.textMuted);
    root.style.setProperty("--border", colors.border);
    root.style.setProperty("--border-strong", colors.accent);
    root.style.setProperty("--accent", colors.btnPrimaryBg);
    root.style.setProperty("--accent-hover", colors.btnPrimaryHover);

    // Legacy aliases
    root.style.setProperty("--text-color", colors.text);
    root.style.setProperty("--border-color", colors.border);
    root.style.setProperty("--border-default", colors.accent);
    root.style.setProperty("--placeholder-color", colors.textMuted);
    root.style.setProperty("--scrollbar-thumb", colors.border);
    root.style.setProperty("--scrollbar-thumb-hover", colors.textMuted);
    root.style.setProperty("--key-background", colors.keyBg);
    // Primary button
    root.style.setProperty("--btn-primary-bg", colors.btnPrimaryBg);
    root.style.setProperty("--btn-primary-text", colors.btnPrimaryText);
    root.style.setProperty("--btn-primary-hover", colors.btnPrimaryHover);
    // Start button (same as primary)
    root.style.setProperty("--start-button-background", colors.btnPrimaryBg);
    root.style.setProperty("--start-button-color", colors.btnPrimaryText);
    root.style.setProperty(
      "--start-button-hover-background",
      colors.btnPrimaryHover,
    );
    // Tooltip
    root.style.setProperty("--tooltip-bg", colors.tooltipBg);
    root.style.setProperty("--tooltip-text", colors.tooltipText);
    // Error color (stays constant)
    root.style.setProperty("--error-color", "#f14c4c");
    root.style.setProperty("--success-color", "#4caf50");

    // Also apply background colors from theme
    this.applyBackgrounds(colors.background, alpha);
  },

  async load() {
    try {
      const prefs = await storage.getPreferences();
      const themeName = prefs.theme || "dark";
      const alpha = prefs.backgroundTransparency ?? 0.8;
      this.apply(themeName, alpha);
      return themeName;
    } catch (err) {
      this.apply("dark");
      return "dark";
    }
  },

  async save(themeName) {
    await storage.updatePreference("theme", themeName);
    this.apply(themeName);
  },
};

// Consolidated cheatingDaddy object - all functions in one place
const cheatingDaddy = {
  // App version
  getVersion: async () => ipcRenderer.invoke("get-app-version"),

  // Element access
  element: () => cheatingDaddyApp,
  e: () => cheatingDaddyApp,

  // App state functions - access properties directly from the app element
  getCurrentView: () => cheatingDaddyApp.currentView,
  getLayoutMode: () => cheatingDaddyApp.layoutMode,

  // Status and response functions
  setStatus: (text) => cheatingDaddyApp.setStatus(text),
  addNewResponse: (response) => cheatingDaddyApp.addNewResponse(response),
  updateCurrentResponse: (response) =>
    cheatingDaddyApp.updateCurrentResponse(response),

  // Core functionality
  initializeGemini,
  initializeLocal,
  startCapture,
  stopCapture,
  sendTextMessage,
  expandLastResponse,
  handleShortcut,

  // Storage API
  storage,

  // Theme API
  theme,

  // Refresh preferences cache (call after updating preferences)
  refreshPreferencesCache: loadPreferencesCache,

  // Platform detection
  isLinux: isLinux,
  isMacOS: isMacOS,
};

// Make it globally available
window.cheatingDaddy = cheatingDaddy;

// Load theme after DOM is ready
if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", () => theme.load());
} else {
  theme.load();
}
