// preview.jsx — right-hand HTML / Inbox / Preview pane (step 4).
//
// Purely derived from the live `blocks` array and `subject` — nothing here
// keeps its own copy of the email, so it is regenerated on every render, the
// same way the canvas itself already is. window.buildEmailHtmlRanges
// (email-export.js) is the SAME renderer that builds the real send/export
// HTML — this pane can never drift from what Send/Export would actually
// produce, because it calls the one function that builds both.

// Splits on '\n' the same way the HTML was joined, so line N here is line N
// of what a "View source" on the real email would show.
function previewSplitLines(html) {
  return html.split('\n');
}

// Which 0-based line indexes a [start, end) character range (as reported by
// buildEmailHtmlRanges) touches, walking the lines once rather than
// re-scanning the whole string per line.
function previewLinesTouchedBy(lines, start, end) {
  const touched = new Set();
  let pos = 0;
  for (let i = 0; i < lines.length; i++) {
    const lineStart = pos;
    const lineEnd = lineStart + lines[i].length; // excludes the '\n' split() ate
    if (lineEnd >= start && lineStart < end) touched.add(i);
    pos = lineEnd + 1;
    if (lineStart >= end) break;
  }
  return touched;
}

// Reduces the FULL document (head, Outlook conditional comments, the one
// <style> block, markup) to the plain text an inbox's preview snippet would
// actually show — just the visible body text, with entities (ATOL's ✈, etc.)
// decoded rather than left as literal "&#9992;". Outlook's conditional
// comments and the <style> rules both live inside <head> in every document
// buildEmailHtml produces, so dropping <head> first also removes the one
// place CSS rule text or MSO comment contents (e.g. "96" out of
// <o:PixelsPerInch>96...>) could otherwise leak into the snippet. This runs
// only in the browser, so a scratch element does the entity decoding and tag
// stripping that a regex alone would get wrong.
function previewStripHtml(html) {
  const body = html
    .replace(/<!--[\s\S]*?-->/g, ' ')
    .replace(/<head[\s\S]*?<\/head>/gi, ' ');
  const scratch = document.createElement('div');
  scratch.innerHTML = body;
  return (scratch.textContent || '').replace(/\s+/g, ' ').trim();
}

function PreviewHtmlTab({ blocks, selectedId }) {
  const { html, ranges } = React.useMemo(
    () => window.buildEmailHtmlRanges(blocks, { platform: 'preview' }),
    [blocks]
  );
  const lines = React.useMemo(() => previewSplitLines(html), [html]);
  const selectedRange = selectedId ? ranges.find((r) => r.id === selectedId) : null;
  const highlighted = React.useMemo(
    () => (selectedRange ? previewLinesTouchedBy(lines, selectedRange.start, selectedRange.end) : new Set()),
    [lines, selectedRange]
  );
  return (
    <div className="bld-preview-html">
      <pre className="bld-preview-html-pre">
        {lines.map((line, i) => (
          <div key={i} className={"bld-preview-html-line" + (highlighted.has(i) ? " is-selected" : "")}>
            <span className="bld-preview-html-lineno">{i + 1}</span>
            <span className="bld-preview-html-text">{line || " "}</span>
          </div>
        ))}
      </pre>
    </div>
  );
}

function PreviewInboxTab({ blocks, subject }) {
  const { html } = React.useMemo(
    () => window.buildEmailHtmlRanges(blocks, { platform: 'preview' }),
    [blocks]
  );
  const snippet = React.useMemo(() => {
    const text = previewStripHtml(html);
    return text.length > 110 ? text.slice(0, 110) + '…' : text;
  }, [html]);
  return (
    <div className="bld-preview-inbox">
      <div className="bld-preview-inbox-hint">How this looks in an inbox list — the subject and the preview snippet most inboxes show alongside it.</div>
      <div className="bld-preview-inbox-row">
        <div className="bld-preview-inbox-subject">{subject || '(no subject)'}</div>
        <div className="bld-preview-inbox-snippet">{snippet || 'This email has no content yet.'}</div>
      </div>
    </div>
  );
}

function PreviewDeviceTab({ blocks }) {
  const [width, setWidth] = React.useState(600);
  const { html } = React.useMemo(
    () => window.buildEmailHtmlRanges(blocks, { platform: 'preview' }),
    [blocks]
  );
  return (
    <div className="bld-preview-device">
      <div className="bld-preview-device-toggle">
        <button type="button" className={"bld-preview-device-btn" + (width === 600 ? " is-active" : "")} onClick={() => setWidth(600)}>Desktop · 600px</button>
        <button type="button" className={"bld-preview-device-btn" + (width === 375 ? " is-active" : "")} onClick={() => setWidth(375)}>Mobile · 375px</button>
      </div>
      <div className="bld-preview-device-frame-wrap">
        <iframe
          className="bld-preview-device-frame"
          title="Email preview"
          style={{ width: width + 'px' }}
          srcDoc={html}
          sandbox=""
        />
      </div>
    </div>
  );
}

const PREVIEW_TABS = [['html', 'HTML'], ['inbox', 'Inbox'], ['preview', 'Preview']];

function PreviewPanel({ blocks, selectedId, subject }) {
  const [tab, setTab] = React.useState('html');
  return (
    <aside className="bld-preview-panel">
      <div className="bld-preview-tabs">
        {PREVIEW_TABS.map(([key, label]) => (
          <button key={key} type="button" className={"bld-preview-tab" + (tab === key ? " is-active" : "")} onClick={() => setTab(key)}>{label}</button>
        ))}
      </div>
      <div className="bld-preview-body">
        {tab === 'html' && <PreviewHtmlTab blocks={blocks} selectedId={selectedId} />}
        {tab === 'inbox' && <PreviewInboxTab blocks={blocks} subject={subject} />}
        {tab === 'preview' && <PreviewDeviceTab blocks={blocks} />}
      </div>
    </aside>
  );
}

window.PreviewPanel = PreviewPanel;
