/**
 * RE::SPARKS Extension - Content Script v2
 * =========================================
 *
 * FLOW:
 * 1. Page load → Phase 1 (Vertex AI retrieval) → Quick check
 * 2. If matches found → Show spark icon in corner (not highlights yet!)
 * 3. User clicks spark icon → Phase 2 (Mistral reasoning) triggered
 * 4. After Phase 2 → Gold highlight on matching text
 * 5. User clicks highlighted text → Save dialog appears
 * 6. User confirms → Saved to Sparks with URL
 */

console.log('[SPARKS CONTENT] ===== CONTENT SCRIPT LOADED v2 =====');

// =============================================================================
// CONFIGURATION
// =============================================================================

const CONFIG = {
  CHUNK_SIZE: 500,
  CHUNK_OVERLAP: 100,
  MIN_CHUNK_LENGTH: 50,
  PHASE1_THRESHOLD: 0.5,
  PHASE2_THRESHOLD: 0.7,
  // Patterns for link sections to filter out
  LINK_SECTION_PATTERNS: [
    /^czytaj (też|także|więcej)/i,
    /^zobacz (też|również|także)/i,
    /^polecamy/i,
    /^powiązane/i,
    /^więcej na (ten )?temat/i,
    /^w tym samym temacie/i,
    /^sprawdź też/i,
    /^przeczytaj również/i,
    /^może cię zainteresować/i,
    /^warto przeczytać/i,
  ],
};

// =============================================================================
// STATE
// =============================================================================

let state = {
  phase1Candidates: [],
  phase2Matches: [],
  pageInfo: null,
  isAnalyzing: false,
  sparkIconVisible: false,
};

// =============================================================================
// TEXT EXTRACTION & CLEANING
// =============================================================================

/**
 * Check if text is a link section header (e.g., "Czytaj też:", "Zobacz również:")
 */
function isLinkSection(text) {
  const trimmed = text.trim();
  return CONFIG.LINK_SECTION_PATTERNS.some(pattern => pattern.test(trimmed));
}

/**
 * Check if element is likely a link to another article
 */
function isArticleLink(element) {
  // Check if it's inside a link section
  const parent = element.parentElement;
  if (parent) {
    const prevSibling = parent.previousElementSibling;
    if (prevSibling && isLinkSection(prevSibling.textContent)) {
      return true;
    }
  }

  // Check if element itself contains link patterns
  const text = element.textContent.trim();
  if (isLinkSection(text)) return true;

  // Check if it's a short text that's entirely a link
  const links = element.querySelectorAll('a');
  if (links.length === 1 && text.length < 150) {
    const linkText = links[0].textContent.trim();
    if (linkText.length > text.length * 0.8) return true;
  }

  return false;
}

function extractPageContent() {
  const unwantedSelectors = [
    'script', 'style', 'noscript', 'iframe',
    'nav', 'header', 'footer', 'aside',
    '[role="navigation"]', '[role="banner"]', '[role="contentinfo"]',
    '.advertisement', '.ad', '.ads', '.sidebar',
    '.comments', '#comments', '.social-share',
    '.cookie-notice', '.popup', '.modal',
    '.menu', '.nav', '.navigation',
  ];
  
  const mainContent = 
    document.querySelector('article') ||
    document.querySelector('[role="main"]') ||
    document.querySelector('main') ||
    document.querySelector('.post-content') ||
    document.querySelector('.article-content') ||
    document.querySelector('.entry-content') ||
    document.body;
  
  if (!mainContent) return { text: '', paragraphs: [] };
  
  const paragraphs = [];
  const elements = mainContent.querySelectorAll('p, h1, h2, h3, h4, h5, h6, li, td, blockquote');
  
  elements.forEach((el, index) => {
    // Skip unwanted sections
    if (unwantedSelectors.some(sel => el.closest(sel))) return;

    // Skip link sections ("Czytaj też:", "Zobacz również:", etc.)
    if (isArticleLink(el)) {
      console.log('[SPARKS] Skipping link section:', el.textContent.substring(0, 50));
      return;
    }

    const text = el.textContent.trim();
    if (text.length >= CONFIG.MIN_CHUNK_LENGTH) {
      paragraphs.push({ text, element: el, index });
    }
  });
  
  return {
    text: paragraphs.map(p => p.text).join('\n\n'),
    paragraphs,
  };
}

/**
 * Hybrid chunking: paragraphs as base, split long paragraphs into sentences.
 * Returns array of { text, element, index } for each chunk.
 */
function createHybridChunks(paragraphs) {
  const chunks = [];

  paragraphs.forEach((para, paraIndex) => {
    const text = para.text;

    // Short paragraph - use as single chunk
    if (text.length <= CONFIG.CHUNK_SIZE) {
      if (text.length >= CONFIG.MIN_CHUNK_LENGTH) {
        chunks.push({
          text,
          element: para.element,
          index: paraIndex,
          type: 'paragraph'
        });
      }
      return;
    }

    // Long paragraph - split into sentences
    const sentences = text.split(/(?<=[.!?])\s+/);
    let currentChunk = '';

    sentences.forEach((sentence, sentIndex) => {
      // If adding this sentence would exceed limit, save current and start new
      if (currentChunk.length + sentence.length > CONFIG.CHUNK_SIZE && currentChunk.length >= CONFIG.MIN_CHUNK_LENGTH) {
        chunks.push({
          text: currentChunk.trim(),
          element: para.element,
          index: paraIndex,
          type: 'sentence-group'
        });
        currentChunk = '';
      }

      currentChunk += (currentChunk ? ' ' : '') + sentence;
    });

    // Don't forget the last chunk
    if (currentChunk.length >= CONFIG.MIN_CHUNK_LENGTH) {
      chunks.push({
        text: currentChunk.trim(),
        element: para.element,
        index: paraIndex,
        type: 'sentence-group'
      });
    }
  });

  console.log(`[SPARKS] Created ${chunks.length} hybrid chunks from ${paragraphs.length} paragraphs`);
  return chunks;
}

// Legacy function for backward compatibility
function chunkText(text) {
  if (!text || text.length < CONFIG.MIN_CHUNK_LENGTH) return [];

  const chunks = [];
  let start = 0;

  while (start < text.length) {
    const end = Math.min(start + CONFIG.CHUNK_SIZE, text.length);
    const chunk = text.slice(start, end).trim();

    if (chunk.length >= CONFIG.MIN_CHUNK_LENGTH) {
      chunks.push({ text: chunk, start, end });
    }
    start += CONFIG.CHUNK_SIZE - CONFIG.CHUNK_OVERLAP;
  }

  return chunks;
}

// =============================================================================
// SPARK ICON (Corner - Phase 1 complete indicator)
// =============================================================================

function createSparkIcon() {
  removeSparkIcon();
  
  const icon = document.createElement('div');
  icon.id = 'sparks-corner-icon';
  icon.innerHTML = `
    <div class="sparks-icon-inner">
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
        <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
      </svg>
      <span class="sparks-icon-count">${state.phase1Candidates.length}</span>
    </div>
    <div class="sparks-icon-pulse"></div>
    <div class="sparks-icon-tooltip">
      <strong>${state.phase1Candidates.length}</strong> potential match${state.phase1Candidates.length !== 1 ? 'es' : ''} found
      <br><small>Click to analyze with AI</small>
    </div>
  `;
  
  icon.addEventListener('click', onSparkIconClick);
  document.body.appendChild(icon);
  state.sparkIconVisible = true;
  
  requestAnimationFrame(() => icon.classList.add('visible'));
}

function removeSparkIcon() {
  const existing = document.getElementById('sparks-corner-icon');
  if (existing) existing.remove();
  state.sparkIconVisible = false;
}

function updateSparkIconState(status) {
  const icon = document.getElementById('sparks-corner-icon');
  if (!icon) return;
  
  const tooltip = icon.querySelector('.sparks-icon-tooltip');
  
  switch (status) {
    case 'analyzing':
      icon.classList.add('analyzing');
      tooltip.innerHTML = '<strong>Analyzing...</strong><br><small>Mistral AI is verifying matches</small>';
      break;
    case 'verified':
      icon.classList.remove('analyzing');
      icon.classList.add('verified');
      tooltip.innerHTML = `
        <strong>${state.phase2Matches.length}</strong> verified match${state.phase2Matches.length !== 1 ? 'es' : ''}
        <br><small>Click gold highlights to save</small>
      `;
      break;
    case 'no-matches':
      icon.classList.remove('analyzing');
      tooltip.innerHTML = 'No matches verified<br><small>Try selecting text manually</small>';
      setTimeout(() => removeSparkIcon(), 3000);
      break;
  }
}

// =============================================================================
// PHASE 1: QUICK RETRIEVAL
// =============================================================================

async function runPhase1() {
  if (state.isAnalyzing) return;
  state.isAnalyzing = true;

  console.log('[SPARKS] Phase 1: Starting quick retrieval...');

  const { text, paragraphs } = extractPageContent();
  // Use hybrid chunking: paragraphs + sentences for long ones
  const chunks = createHybridChunks(paragraphs);

  if (chunks.length === 0) {
    console.log('[SPARKS] No content to analyze');
    state.isAnalyzing = false;
    return;
  }

  state.pageInfo = {
    url: window.location.href,
    title: document.title,
    paragraphs,
    chunks,  // Now contains hybrid chunks with element references
    fullText: paragraphs.map(p => p.text).join('\n\n'),  // V1.2: full article text for Phase 2
  };

  chrome.runtime.sendMessage({
    action: 'phase1Analysis',
    pageData: {
      url: window.location.href,
      title: document.title,
      chunks: chunks.map(c => c.text),
    },
  }, (response) => {
    state.isAnalyzing = false;

    if (response && response.v2) {
      // === V2 MODE: Two-phase LLM - matches are already verified ===
      console.log(`[SPARKS] V2 analysis complete: ${response.count} verified matches`);
      console.log(`[SPARKS] V2 Phase 1 decision: ${response.phase1_decision}`);

      if (response.candidates && response.candidates.length > 0) {
        // V2 returns verified matches directly (skip Phase 2)
        state.phase2Matches = response.candidates;
        state.phase1Candidates = response.candidates;
        createSparkIcon();
        // Auto-highlight since matches are already verified
        updateSparkIconState('verified');
        setTimeout(() => highlightV2Matches(), 500);
      } else {
        console.log('[SPARKS] V2: No matches found');
      }
      return;
    }

    // === V1 MODE: Embedding-based - requires Phase 2 ===
    if (response && response.candidates && response.candidates.length > 0) {
      state.phase1Candidates = response.candidates;
      console.log(`[SPARKS] Phase 1 complete: ${response.candidates.length} candidates`);
      createSparkIcon();
    } else {
      console.log('[SPARKS] Phase 1: No candidates');
    }
  });
}

// =============================================================================
// PHASE 2: MISTRAL VERIFICATION (on icon click)
// =============================================================================

async function onSparkIconClick(e) {
  e.preventDefault();
  e.stopPropagation();
  
  if (state.phase2Matches.length > 0) {
    toggleHighlights();
    return;
  }
  
  console.log('[SPARKS] Phase 2: Starting LLM verification (uses config from Flow admin)...');
  updateSparkIconState('analyzing');
  
  chrome.runtime.sendMessage({
    action: 'phase2Analysis',
    candidates: state.phase1Candidates,
    pageInfo: {
      url: state.pageInfo.url,
      title: state.pageInfo.title,
      fullText: state.pageInfo.fullText,  // V1.2: full article text
    },
  }, (response) => {
    console.log('[SPARKS] Phase 2 response:', JSON.stringify(response));
    if (response && response.matches && response.matches.length > 0) {
      state.phase2Matches = response.matches;
      console.log(`[SPARKS] Phase 2 complete: ${response.matches.length} verified`);
      console.log('[SPARKS] Calling highlightVerifiedMatches...');
      updateSparkIconState('verified');
      highlightVerifiedMatches();
      console.log('[SPARKS] highlightVerifiedMatches done');
    } else {
      console.log('[SPARKS] Phase 2: No matches verified', 'response:', response);
      updateSparkIconState('no-matches');
    }
  });
}

// =============================================================================
// GOLD HIGHLIGHTS
// =============================================================================

function highlightVerifiedMatches() {
  removeHighlights();
  console.log('[SPARKS] highlightVerifiedMatches: matches=', state.phase2Matches.length, 'chunks=', state.pageInfo?.chunks?.length);
  if (!state.phase2Matches.length || !state.pageInfo) return;

  let firstHighlight = null;

  state.phase2Matches.forEach((match, index) => {
    // V1.2: match has quote field → use findAndHighlightQuote (precise quote search)
    if (match.quote) {
      console.log('[SPARKS V1.2] Highlighting quote:', match.quote.substring(0, 50) + '...');
      const wrapper = findAndHighlightQuote(match.quote, match, index);
      if (wrapper && !firstHighlight) firstHighlight = wrapper;
      return;
    }

    // V1 fallback: use chunk_index (existing code)
    const chunkIndex = match.chunk_index;
    const chunk = state.pageInfo.chunks?.[chunkIndex];

    if (chunk && chunk.element) {
      const chunkText = chunk.text;
      console.log('[SPARKS] Highlighting chunk', chunkIndex, 'length:', chunkText.length);
      const wrapper = highlightTextInElement(chunk.element, chunkText, match, index);
      if (wrapper && !firstHighlight) {
        firstHighlight = wrapper;
      }
      return;
    }

    console.log('[SPARKS] No element found for chunk', chunkIndex);
  });

  // Scroll to first highlight
  if (firstHighlight) {
    firstHighlight.scrollIntoView({ behavior: 'smooth', block: 'center' });
  }
}

/**
 * Highlight text in element with original gold mark style.
 * SUPPORTS text spanning multiple nodes (bold, italic, links, etc.)
 */
function highlightTextInElement(element, chunkText, match, index) {
  // Build full text map with node references (same approach as V2)
  const textNodes = [];
  const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
  let node;
  let fullText = '';

  while (node = walker.nextNode()) {
    const text = node.textContent;
    if (text.trim().length > 0) {
      textNodes.push({
        node,
        start: fullText.length,
        end: fullText.length + text.length,
        text
      });
      fullText += text;
    }
  }

  if (textNodes.length === 0) return null;

  // Normalize and find the chunk start
  const normalizedFull = fullText.replace(/\s+/g, ' ').toLowerCase();
  const searchText = chunkText.replace(/\s+/g, ' ').trim().toLowerCase();
  const searchStart = searchText.substring(0, 40);

  const pos = normalizedFull.indexOf(searchStart);
  if (pos === -1) {
    console.log('[SPARKS V1] Text not found in element');
    return null;
  }

  // Map normalized position to approximate original position
  const ratio = fullText.length / normalizedFull.length;
  const approxStart = Math.floor(pos * ratio);
  const approxEnd = Math.min(approxStart + chunkText.length, fullText.length);

  // Find all nodes that overlap with our range
  const overlappingNodes = textNodes.filter(n =>
    n.start < approxEnd && n.end > approxStart
  );

  if (overlappingNodes.length === 0) return null;

  console.log(`[SPARKS V1] Found text spanning ${overlappingNodes.length} nodes`);

  // Wrap each overlapping node's portion
  const wrappers = [];
  overlappingNodes.forEach((nodeInfo, i) => {
    const nodeStart = Math.max(0, approxStart - nodeInfo.start);
    const nodeEnd = Math.min(nodeInfo.text.length, approxEnd - nodeInfo.start);

    if (nodeEnd <= nodeStart) return;

    try {
      const range = document.createRange();
      range.setStart(nodeInfo.node, nodeStart);
      range.setEnd(nodeInfo.node, nodeEnd);

      const wrapper = document.createElement('mark');
      wrapper.className = 'sparks-gold-highlight';
      wrapper.dataset.matchIndex = index;
      wrapper.dataset.sparkId = match.spark_id;
      wrapper.dataset.sparkTitle = match.spark_title || '';
      wrapper.dataset.multipart = overlappingNodes.length > 1 ? 'true' : 'false';

      // Continuous gold gradient style across nodes
      if (overlappingNodes.length === 1) {
        wrapper.style.cssText = 'background: linear-gradient(135deg, #FFD700, #FFA500) !important; padding: 2px 4px; border-radius: 3px; cursor: pointer;';
      } else if (i === 0) {
        wrapper.style.cssText = 'background: linear-gradient(135deg, #FFD700, #FFA500) !important; padding: 2px 0 2px 4px; border-radius: 3px 0 0 3px; cursor: pointer;';
      } else if (i === overlappingNodes.length - 1) {
        wrapper.style.cssText = 'background: linear-gradient(135deg, #FFD700, #FFA500) !important; padding: 2px 4px 2px 0; border-radius: 0 3px 3px 0; cursor: pointer;';
      } else {
        wrapper.style.cssText = 'background: linear-gradient(135deg, #FFD700, #FFA500) !important; padding: 2px 0; border-radius: 0; cursor: pointer;';
      }

      range.surroundContents(wrapper);
      wrapper.addEventListener('click', () => showSaveDialog(match, wrapper));
      wrappers.push(wrapper);
    } catch (e) {
      console.log('[SPARKS V1] Node wrap failed:', e.message);
    }
  });

  if (wrappers.length > 0) {
    console.log(`[SPARKS V1] ✅ Highlighted ${wrappers.length} segments`);
    return wrappers[0];
  }

  // Fallback: highlight parent element
  element.style.background = 'linear-gradient(135deg, rgba(255,215,0,0.3), rgba(255,165,0,0.2))';
  element.style.borderRadius = '4px';
  element.style.cursor = 'pointer';
  element.addEventListener('click', () => showSaveDialog(match, element));
  return element;
}

function highlightElement(element, searchText, match, index) {
  console.log('[SPARKS] highlightElement called for:', searchText.substring(0, 30));
  // Find text node containing the match
  const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
  let node;
  let nodeCount = 0;

  while (node = walker.nextNode()) {
    nodeCount++;
    const text = node.textContent;
    const searchFor = searchText.substring(0, 40);
    const pos = text.indexOf(searchFor);

    if (pos !== -1) {
      console.log('[SPARKS] Found text at pos', pos, 'in node', nodeCount);
      const range = document.createRange();
      range.setStart(node, pos);
      range.setEnd(node, Math.min(pos + searchText.length, text.length));

      const wrapper = document.createElement('mark');
      wrapper.className = 'sparks-gold-highlight';
      wrapper.dataset.matchIndex = index;
      wrapper.dataset.sparkId = match.spark_id;
      wrapper.dataset.sparkTitle = match.spark_title || '';
      wrapper.style.cssText = 'background: linear-gradient(135deg, #FFD700, #FFA500) !important; padding: 2px 4px; border-radius: 3px; cursor: pointer;';

      try {
        range.surroundContents(wrapper);
        console.log('[SPARKS] ✅ Successfully wrapped text in <mark>');

        // Verify element is in DOM
        const inDOM = document.body.contains(wrapper);
        console.log('[SPARKS] Element in DOM:', inDOM, 'Visible text:', wrapper.textContent.substring(0, 30));

        // Scroll to the highlighted element
        wrapper.scrollIntoView({ behavior: 'smooth', block: 'center' });
        console.log('[SPARKS] Scrolled to element');

        // Add save button
        const saveBtn = document.createElement('button');
        saveBtn.className = 'sparks-inline-save';
        saveBtn.style.cssText = 'display: none; position: absolute; background: #333; color: white; padding: 4px 8px; border-radius: 4px; font-size: 12px; z-index: 99999;';
        saveBtn.innerHTML = `⚡ Save to "${escapeHtml(match.spark_title || 'Spark')}"`;
        saveBtn.onclick = (e) => { e.stopPropagation(); saveMatch(e, match, wrapper.textContent); };
        wrapper.appendChild(saveBtn);

        wrapper.onclick = () => {
          saveBtn.style.display = saveBtn.style.display === 'none' ? 'block' : 'none';
        };
      } catch (e) {
        console.warn('[SPARKS] Could not highlight:', e);
      }

      return;
    }
  }
  console.log('[SPARKS] ❌ Text not found in any of', nodeCount, 'text nodes');
}

/**
 * Highlight V2 matches - uses precise quote positions from two-phase LLM.
 * Uses SAME highlight style as v1 (gold gradient).
 */
function highlightV2Matches() {
  removeHighlights();
  console.log('[SPARKS V2] Highlighting', state.phase2Matches.length, 'verified matches');

  if (!state.phase2Matches.length || !state.pageInfo) return;

  let firstHighlight = null;

  state.phase2Matches.forEach((match, index) => {
    const quote = match.quote;
    if (!quote || quote.length < 10) return;

    console.log('[SPARKS V2] Looking for quote:', quote.substring(0, 50) + '...');

    // Find the quote in the page using text search
    const foundWrapper = findAndHighlightQuote(quote, match, index);

    if (foundWrapper && !firstHighlight) {
      firstHighlight = foundWrapper;
    }
  });

  // Scroll to first highlight
  if (firstHighlight) {
    firstHighlight.scrollIntoView({ behavior: 'smooth', block: 'center' });
  }
}

/**
 * Normalize text for fuzzy matching - remove quotes, extra spaces, normalize punctuation
 */
function normalizeForSearch(text) {
  return text
    .replace(/[„""''«»]/g, '"')  // Normalize all quote types
    .replace(/[–—]/g, '-')       // Normalize dashes
    .replace(/\s+/g, ' ')        // Normalize whitespace
    .replace(/^\s*["']\s*/, '')  // Remove leading quotes
    .replace(/\s*["']\s*$/, '')  // Remove trailing quotes
    .trim()
    .toLowerCase();
}

/**
 * Find quote in page and highlight it with the original gold style.
 * Uses fuzzy matching to handle minor differences.
 * SUPPORTS text spanning multiple nodes (bold, italic, links, etc.)
 */
function findAndHighlightQuote(quote, match, index) {
  // Multiple search strategies - try each until one works
  const searchVariants = [
    quote,                                    // Original
    quote.replace(/^["'„""]/, '').replace(/["'"""]$/, ''),  // Without quotes
    quote.split('.')[0],                      // First sentence only
    quote.substring(0, 60),                   // First 60 chars
  ].map(normalizeForSearch).filter(s => s.length > 15);

  // Search in main content area
  const mainContent =
    document.querySelector('article') ||
    document.querySelector('[role="main"]') ||
    document.querySelector('main') ||
    document.querySelector('.post-content') ||
    document.querySelector('.article-content') ||
    document.body;

  // Build full text map with node references
  const textNodes = [];
  const walker = document.createTreeWalker(mainContent, NodeFilter.SHOW_TEXT);
  let node;
  let fullText = '';

  while (node = walker.nextNode()) {
    const text = node.textContent;
    if (text.trim().length > 0) {
      textNodes.push({
        node,
        start: fullText.length,
        end: fullText.length + text.length,
        text
      });
      fullText += text;
    }
  }

  const normalizedFull = normalizeForSearch(fullText);

  // Try each search variant
  for (const searchText of searchVariants) {
    const searchStart = searchText.substring(0, 40);
    const pos = normalizedFull.indexOf(searchStart);

    if (pos !== -1) {
      // Found! Now find which nodes contain this text
      // Map normalized position to approximate original position
      const ratio = fullText.length / normalizedFull.length;
      const approxStart = Math.floor(pos * ratio);
      const approxEnd = Math.min(approxStart + quote.length, fullText.length);

      // Find all nodes that overlap with our range
      const overlappingNodes = textNodes.filter(n =>
        n.start < approxEnd && n.end > approxStart
      );

      if (overlappingNodes.length === 0) continue;

      console.log(`[SPARKS V2] Found quote spanning ${overlappingNodes.length} text nodes`);

      // Wrap each overlapping node's portion
      const wrappers = [];
      overlappingNodes.forEach((nodeInfo, i) => {
        const nodeStart = Math.max(0, approxStart - nodeInfo.start);
        const nodeEnd = Math.min(nodeInfo.text.length, approxEnd - nodeInfo.start);

        if (nodeEnd <= nodeStart) return;

        try {
          const range = document.createRange();
          range.setStart(nodeInfo.node, nodeStart);
          range.setEnd(nodeInfo.node, nodeEnd);

          const wrapper = document.createElement('mark');
          wrapper.className = 'sparks-gold-highlight';
          wrapper.dataset.matchIndex = index;
          wrapper.dataset.sparkId = match.spark_id;
          wrapper.dataset.sparkTitle = match.spark_title || '';
          wrapper.dataset.v2 = 'true';
          wrapper.dataset.multipart = overlappingNodes.length > 1 ? 'true' : 'false';
          // Gold gradient style - continuous look across nodes
          if (i === 0) {
            wrapper.style.cssText = 'background: linear-gradient(135deg, #FFD700, #FFA500) !important; padding: 2px 0 2px 4px; border-radius: 3px 0 0 3px; cursor: pointer;';
          } else if (i === overlappingNodes.length - 1) {
            wrapper.style.cssText = 'background: linear-gradient(135deg, #FFD700, #FFA500) !important; padding: 2px 4px 2px 0; border-radius: 0 3px 3px 0; cursor: pointer;';
          } else {
            wrapper.style.cssText = 'background: linear-gradient(135deg, #FFD700, #FFA500) !important; padding: 2px 0; border-radius: 0; cursor: pointer;';
          }

          range.surroundContents(wrapper);
          wrapper.addEventListener('click', () => showSaveDialog(match, wrapper));
          wrappers.push(wrapper);
        } catch (e) {
          console.log('[SPARKS V2] Node wrap failed:', e.message);
        }
      });

      if (wrappers.length > 0) {
        console.log(`[SPARKS V2] ✅ Highlighted ${wrappers.length} segments:`, wrappers[0].textContent.substring(0, 40) + '...');
        return wrappers[0];
      }

      // Fallback: highlight common parent
      const parent = overlappingNodes[0].node.parentElement;
      if (parent) {
        parent.style.background = 'linear-gradient(135deg, rgba(255,215,0,0.3), rgba(255,165,0,0.2))';
        parent.style.borderRadius = '4px';
        parent.style.cursor = 'pointer';
        parent.addEventListener('click', () => showSaveDialog(match, parent));
        console.log('[SPARKS V2] ✅ Highlighted parent element');
        return parent;
      }
    }
  }

  console.log('[SPARKS V2] ❌ Quote not found in DOM');
  return null;
}

function removeHighlights() {
  document.querySelectorAll('.sparks-gold-highlight').forEach(el => {
    const parent = el.parentNode;
    if (parent) {
      while (el.firstChild) parent.insertBefore(el.firstChild, el);
      parent.removeChild(el);
    }
  });
}

function toggleHighlights() {
  const highlights = document.querySelectorAll('.sparks-gold-highlight');
  if (highlights.length) {
    highlights.forEach(h => h.classList.toggle('sparks-hidden'));
  } else {
    highlightVerifiedMatches();
  }
}

// =============================================================================
// SAVE FUNCTIONALITY
// =============================================================================

function saveMatch(e, match, text) {
  e.preventDefault();
  e.stopPropagation();
  
  const btn = e.currentTarget;
  btn.textContent = 'Saving...';
  btn.disabled = true;
  
  chrome.runtime.sendMessage({
    action: 'saveSpark',
    data: {
      project_id: match.spark_id || match.project_id || match.topic_id,  // API expects project_id
      content_preview: text,
      url: window.location.href,
      title: document.title,
      source_type: 'snippet',
    },
  }, (response) => {
    if (response && (response.success || response.spark_id || response.spark?.spark_id)) {
      btn.textContent = '✓ Saved!';
      btn.classList.add('saved');
      showToast(`Saved to "${match.spark_title}"`);
      setTimeout(() => btn.classList.remove('visible'), 2000);
    } else {
      console.error('[SPARKS] Save failed:', response);
      btn.textContent = 'Error';
      btn.disabled = false;
    }
  });
}

/**
 * Show save dialog for a match (used by v2 click handlers).
 */
function showSaveDialog(match, element) {
  // Get the text content to save
  const text = element.textContent || match.quote || '';

  chrome.runtime.sendMessage({
    action: 'saveSpark',
    data: {
      project_id: match.spark_id || match.project_id,
      content_preview: text,
      url: window.location.href,
      title: document.title,
      source_type: 'snippet',
      reasoning: match.reasoning || '',
      category: match.category || '',
    },
  }, (response) => {
    if (response && (response.success || response.spark_id || response.spark?.spark_id)) {
      showToast(`Saved to "${match.spark_title || 'Spark'}"`);
      // Mark as saved visually
      element.style.background = 'linear-gradient(135deg, #4CAF50, #45a049)';
    } else {
      console.error('[SPARKS] Save failed:', response);
      showToast('Save failed - try again');
    }
  });
}

function showToast(message) {
  const existing = document.getElementById('sparks-toast');
  if (existing) existing.remove();
  
  const toast = document.createElement('div');
  toast.id = 'sparks-toast';
  toast.innerHTML = `
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <path d="M20 6L9 17l-5-5"/>
    </svg>
    ${escapeHtml(message)}
  `;
  
  document.body.appendChild(toast);
  requestAnimationFrame(() => toast.classList.add('visible'));
  setTimeout(() => {
    toast.classList.remove('visible');
    setTimeout(() => toast.remove(), 300);
  }, 3000);
}

// =============================================================================
// MANUAL SELECTION
// =============================================================================

document.addEventListener('mouseup', (e) => {
  // Ignore clicks inside existing popup
  if (e.target.closest('.sparks-quick-popup')) return;

  const selection = window.getSelection()?.toString()?.trim();
  console.log('[SPARKS] mouseup - selection length:', selection?.length || 0);
  if (selection && selection.length > 30) {
    console.log('[SPARKS] Showing quick save popup...');
    showQuickSavePopup(e, selection);
  }
});

function showQuickSavePopup(e, text) {
  document.querySelectorAll('.sparks-quick-popup').forEach(el => el.remove());

  console.log('[SPARKS] Requesting sparks from background...');
  chrome.runtime.sendMessage({ action: 'getSparks' }, (response) => {
    console.log('[SPARKS] getSparks response:', response);
    if (chrome.runtime.lastError) {
      console.error('[SPARKS] Runtime error:', chrome.runtime.lastError);
    }

    const popup = document.createElement('div');
    popup.className = 'sparks-quick-popup';
    popup.style.left = `${Math.min(e.pageX, window.innerWidth - 220)}px`;
    popup.style.top = `${e.pageY + 15}px`;

    if (!response?.sparks?.length) {
      console.log('[SPARKS] No sparks available');
      popup.innerHTML = `
        <div class="sparks-popup-header">⚡ Spark Catcher</div>
        <div class="sparks-popup-list" style="padding:12px;color:#888;font-size:13px;">
          ${!response ? 'Extension not responding' : 'No Spark Boxes yet. Create one in the extension popup.'}
        </div>
      `;
      document.body.appendChild(popup);
      setTimeout(() => popup.remove(), 3000);
      return;
    }

    popup.innerHTML = `
      <div class="sparks-popup-header">⚡ Save to Spark</div>
      <div class="sparks-popup-list">
        ${response.sparks.map(t => `
          <button data-id="${t.project_id || t.topic_id}" data-title="${escapeHtml(t.title)}">
            <span style="background:${t.color || '#FF9A00'}"></span>
            ${escapeHtml(t.title)}
          </button>
        `).join('')}
      </div>
    `;
    
    popup.querySelectorAll('button').forEach(btn => {
      btn.onclick = (e) => {
        e.preventDefault();
        e.stopPropagation();

        btn.textContent = 'Saving...';
        btn.disabled = true;

        chrome.runtime.sendMessage({
          action: 'saveSpark',
          data: {
            project_id: btn.dataset.id,  // API expects project_id
            content_preview: text,
            url: window.location.href,
            title: document.title,
            source_type: 'snippet',
          },
        }, (res) => {
          console.log('[SPARKS] Save response:', JSON.stringify(res, null, 2));
          if (res?.success || res?.spark_id || res?.spark?.spark_id) {
            showToast(`Saved to "${btn.dataset.title}"`);
            window.getSelection().removeAllRanges();
            popup.remove();
          } else {
            console.error('[SPARKS] Save failed:', res);
            const errorMsg = res?.error || res?.detail || 'Save failed';
            btn.textContent = `Error: ${errorMsg.substring(0, 30)}`;
            btn.disabled = false;
          }
        });
      };
    });
    
    document.body.appendChild(popup);
    
    setTimeout(() => {
      document.addEventListener('click', function close(ev) {
        if (!popup.contains(ev.target)) {
          popup.remove();
          document.removeEventListener('click', close);
        }
      });
    }, 100);
  });
}

// =============================================================================
// MESSAGE HANDLERS
// =============================================================================

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  switch (message.action) {
    case 'getSelection':
      sendResponse({ selection: window.getSelection()?.toString()?.trim() || '' });
      break;
    case 'getPageInfo':
      sendResponse({ url: window.location.href, title: document.title });
      break;
    case 'triggerAnalysis':
      runPhase1();
      sendResponse({ started: true });
      break;
    default:
      sendResponse({ error: 'Unknown' });
  }
  return true;
});

// =============================================================================
// UTILITIES
// =============================================================================

function escapeHtml(text) {
  const div = document.createElement('div');
  div.textContent = text || '';
  return div.innerHTML;
}

// =============================================================================
// INIT
// =============================================================================

function init() {
  console.log('[SPARKS] Loaded on:', window.location.hostname);

  chrome.runtime.sendMessage({ action: 'checkAuth' }, (response) => {
    console.log('[SPARKS] checkAuth response:', JSON.stringify(response), 'lastError:', chrome.runtime.lastError?.message);
    if (response?.isAuthenticated) {
      // First, ensure sparks are synced
      chrome.runtime.sendMessage({ action: 'syncSparks' }, (syncResponse) => {
        console.log('[SPARKS] syncSparks response:', JSON.stringify(syncResponse), 'lastError:', chrome.runtime.lastError?.message);
        const sparkCount = syncResponse?.sparks?.length || syncResponse?.count || 0;
        console.log('[SPARKS] Synced sparks:', sparkCount);

        if (sparkCount > 0) {
          // Run analysis after short delay
          setTimeout(runPhase1, 1500);
        } else {
          // Fallback: try getSparks which uses cached data
          console.log('[SPARKS] No sparks from sync, trying cache...');
          chrome.runtime.sendMessage({ action: 'getSparks' }, (cacheResponse) => {
            const cachedCount = cacheResponse?.sparks?.length || 0;
            console.log('[SPARKS] Cached sparks:', cachedCount);
            if (cachedCount > 0) {
              setTimeout(runPhase1, 1500);
            } else {
              console.log('[SPARKS] No sparks to match against, skipping analysis');
            }
          });
        }
      });
    } else {
      console.log('[SPARKS] Not authenticated, skipping analysis');
    }
  });
}

if (document.readyState === 'complete') init();
else window.addEventListener('load', init);
