/*
 * DigestWindow — floating panel chrome for the digest canvas.
 *
 * Windows look like windows (title bar, rounded corners, shadow, glow accent)
 * but are not actually draggable. The canvas is read on a wall-mounted kiosk and
 * inside a Home Assistant iframe card; neither has a pointer doing window
 * management, and real drag-and-drop would only add state that nothing persists.
 *
 * x/y/w/h are optional. Given, the window is absolutely positioned (percentages
 * of the canvas) — that is the escape hatch for a deliberately composed layout.
 * Omitted, the window participates in the canvas's normal flow/grid layout, which
 * is what render.js does by default so the layout survives any window count the
 * LLM decides to emit.
 */

(function (global) {
  'use strict';

  var counter = 0;

  function escapeHtml(text) {
    return String(text)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;');
  }

  // Intentionally tiny: bold, italic, inline code and paragraph breaks. The
  // schema calls content "markdown-ish", and pulling in a markdown parser for
  // three inline forms would violate this project's no-unnecessary-deps rule.
  function renderInline(text) {
    return escapeHtml(text)
      .replace(/`([^`]+)`/g, '<code>$1</code>')
      .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
      .replace(/(^|[\s(])\*([^*]+)\*/g, '$1<em>$2</em>');
  }

  function renderContent(content) {
    var body = document.createElement('div');
    body.className = 'digest-window-body';

    if (Array.isArray(content)) {
      var list = document.createElement('ul');
      list.className = 'digest-window-list';
      content.forEach(function (item) {
        var li = document.createElement('li');
        li.innerHTML = renderInline(item);
        list.appendChild(li);
      });
      body.appendChild(list);
      return body;
    }

    // Duck-typed rather than `instanceof Node`: render.js hands the globe its
    // mount point through here, and an identity check against a global that may
    // not exist in every embedding context is a needless way to lose the globe.
    if (content && typeof content.nodeType === 'number') {
      body.appendChild(content);
      return body;
    }

    String(content === undefined || content === null ? '' : content)
      .split(/\n{2,}/)
      .forEach(function (block) {
        if (!block.trim()) { return; }
        var p = document.createElement('p');
        p.innerHTML = renderInline(block).replace(/\n/g, '<br>');
        body.appendChild(p);
      });

    return body;
  }

  // Only http(s) becomes a clickable link. The content of every window here is
  // model output, and `javascript:` in an href would be script execution handed to
  // whatever the LLM emitted — the one place this renderer's degrade-don't-throw
  // habit is not enough. Anything else is shown as plain text instead.
  function safeHref(url) {
    var text = String(url || '').trim();
    return /^https?:\/\//i.test(text) ? text : null;
  }

  // The fold-out sources block. Collapsed by default because the digest is read
  // across a room: the claim is what you see, the receipts are one tap away, and
  // an open citation list would push the next window off the screen.
  function renderSources(sources, label) {
    var usable = (sources || []).filter(function (source) {
      return source && (source.title || source.outlet || source.url || source.quote);
    });
    if (!usable.length) { return null; }

    var details = document.createElement('details');
    details.className = 'digest-sources';

    var summary = document.createElement('summary');
    summary.textContent = (label || 'Sources') + ' (' + usable.length + ')';
    details.appendChild(summary);

    var list = document.createElement('ul');
    list.className = 'digest-source-list';

    usable.forEach(function (source) {
      var li = document.createElement('li');

      var head = document.createElement('div');
      head.className = 'digest-source-head';
      var href = safeHref(source.url);
      var titleText = source.title || source.url || source.outlet;
      if (href) {
        var link = document.createElement('a');
        link.href = href;
        link.textContent = titleText;
        link.rel = 'noopener noreferrer';
        head.appendChild(link);
      } else {
        head.appendChild(document.createTextNode(titleText));
      }
      li.appendChild(head);

      // Outlet and ownership sit with the citation rather than in the prose: who
      // published a claim is part of reading it, and it belongs next to the claim.
      var attribution = [source.outlet, source.owner, source.bias]
        .filter(function (part) { return part; })
        .join(' · ');
      if (attribution) {
        var meta = document.createElement('div');
        meta.className = 'digest-source-meta';
        meta.textContent = attribution;
        li.appendChild(meta);
      }

      if (source.quote) {
        var quote = document.createElement('blockquote');
        quote.className = 'digest-source-quote';
        quote.textContent = source.quote;
        li.appendChild(quote);
      }

      list.appendChild(li);
    });

    details.appendChild(list);
    return details;
  }

  var DigestWindow = {
    // Exposed so render.js can attach the same block under a globe marker's brief,
    // where there is no window of its own to hang it on.
    sources: renderSources,

    open: function (options) {
      options = options || {};

      var container = options.container || document.body;

      var el = document.createElement('section');
      el.className = 'digest-window';
      el.id = options.id || ('digest-window-' + (++counter));
      if (options.variant) {
        el.classList.add('digest-window-' + options.variant);
      }

      var bar = document.createElement('header');
      bar.className = 'digest-window-titlebar';

      var dots = document.createElement('span');
      dots.className = 'digest-window-dots';
      dots.setAttribute('aria-hidden', 'true');
      bar.appendChild(dots);

      var title = document.createElement('h2');
      title.className = 'digest-window-title';
      title.textContent = options.title || '';
      bar.appendChild(title);

      el.appendChild(bar);

      var body = renderContent(options.content);
      var sources = renderSources(options.sources);
      if (sources) { body.appendChild(sources); }
      el.appendChild(body);

      if (typeof options.x === 'number' && typeof options.y === 'number') {
        el.classList.add('digest-window-positioned');
        el.style.left = options.x + '%';
        el.style.top = options.y + '%';
      }
      if (typeof options.w === 'number') { el.style.width = options.w + '%'; }
      if (typeof options.h === 'number') { el.style.height = options.h + '%'; }

      container.appendChild(el);
      return el;
    }
  };

  global.DigestWindow = DigestWindow;
})(window);
