📄 src/ui/dialog.ts
import type { FailureReason } from '../errors';
import {
  DIALOG_CLOSE_LABEL,
  DIALOG_FALLBACK_BUTTON,
  DIALOG_TITLE,
  FAILURE_MESSAGES,
} from './strings';

/**
 * A small, pretty error dialog (Swedish) rendered in a closed shadow root so
 * the site's styles and ours can never clash. One clear action: open the
 * paper the way the site would have without the extension.
 */

const HOST_ID = 'vf-pdf-opener-dialog';

const ICON_SVG = `<svg viewBox="0 0 24 24" width="40" height="40" aria-hidden="true">
  <circle cx="12" cy="12" r="12" fill="#bd2428"/>
  <path fill="#fff" d="M12 5.6a1.5 1.5 0 0 1 1.5 1.62l-.45 6.4a1.05 1.05 0 0 1-2.1 0l-.45-6.4A1.5 1.5 0 0 1 12 5.6Z"/>
  <circle cx="12" cy="16.9" r="1.35" fill="#fff"/>
</svg>`;

const DIALOG_CSS = `
  .overlay {
    position: fixed;
    inset: 0;
    background: rgba(15, 17, 20, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'Lato', -apple-system, 'Segoe UI', system-ui, sans-serif;
    animation: vfpe-fade 0.15s ease;
  }
  @keyframes vfpe-fade { from { opacity: 0; } }
  .card {
    background: #fff;
    border-radius: 14px;
    box-shadow: 0 18px 60px rgba(0, 0, 0, 0.3);
    width: min(400px, calc(100vw - 40px));
    padding: 28px;
    position: relative;
    text-align: center;
    animation: vfpe-pop 0.18s ease;
  }
  @keyframes vfpe-pop {
    from { opacity: 0; transform: translateY(8px) scale(0.98); }
  }
  .icon { margin-bottom: 14px; }
  h2 { font-size: 20px; color: #23262b; margin: 0 0 8px; font-weight: 700; }
  p { font-size: 14.5px; line-height: 1.55; color: #55595f; margin: 0 0 22px; }
  button.primary {
    background: #bd2428;
    color: #fff;
    border: none;
    font: inherit;
    font-size: 15px;
    font-weight: 700;
    padding: 12px 24px;
    border-radius: 9px;
    cursor: pointer;
    width: 100%;
  }
  button.primary:hover { background: #a41f23; }
  button.primary:focus-visible { outline: 3px solid rgba(189, 36, 40, 0.35); outline-offset: 2px; }
  button.close {
    position: absolute;
    top: 10px;
    right: 10px;
    background: none;
    border: none;
    cursor: pointer;
    font-size: 20px;
    line-height: 1;
    color: #9aa0a8;
    padding: 6px;
    border-radius: 6px;
  }
  button.close:hover { color: #55595f; background: #f2f3f5; }
`;

export function showErrorDialog(reason: FailureReason, onFallback: () => void): void {
  dismissDialog();

  const host = document.createElement('div');
  host.id = HOST_ID;
  host.style.cssText = 'all: initial; position: fixed; inset: 0; z-index: 2147483647;';
  const shadow = host.attachShadow({ mode: 'open' });

  const style = document.createElement('style');
  style.textContent = DIALOG_CSS;

  const overlay = document.createElement('div');
  overlay.className = 'overlay';

  const card = document.createElement('div');
  card.className = 'card';
  card.setAttribute('role', 'alertdialog');
  card.setAttribute('aria-modal', 'true');
  card.setAttribute('aria-labelledby', 'vfpe-dialog-title');
  card.setAttribute('aria-describedby', 'vfpe-dialog-message');

  const closeButton = document.createElement('button');
  closeButton.className = 'close';
  closeButton.type = 'button';
  closeButton.setAttribute('aria-label', DIALOG_CLOSE_LABEL);
  closeButton.textContent = '✕';

  const icon = document.createElement('div');
  icon.className = 'icon';
  icon.innerHTML = ICON_SVG;

  const title = document.createElement('h2');
  title.id = 'vfpe-dialog-title';
  title.textContent = DIALOG_TITLE;

  const message = document.createElement('p');
  message.id = 'vfpe-dialog-message';
  message.textContent = FAILURE_MESSAGES[reason];

  const fallbackButton = document.createElement('button');
  fallbackButton.className = 'primary';
  fallbackButton.type = 'button';
  fallbackButton.textContent = DIALOG_FALLBACK_BUTTON;

  card.append(closeButton, icon, title, message, fallbackButton);
  overlay.append(card);
  shadow.append(style, overlay);

  const cleanup = () => {
    document.removeEventListener('keydown', onKeydown);
    host.remove();
  };
  const onKeydown = (event: KeyboardEvent) => {
    if (event.key === 'Escape') cleanup();
  };

  overlay.addEventListener('click', (event) => {
    if (event.target === overlay) cleanup();
  });
  closeButton.addEventListener('click', cleanup);
  fallbackButton.addEventListener('click', () => {
    cleanup();
    onFallback();
  });
  document.addEventListener('keydown', onKeydown);

  document.body.append(host);
  fallbackButton.focus();
}

/** Remove any dialog we previously opened. */
function dismissDialog(): void {
  document.getElementById(HOST_ID)?.remove();
}