(function(root, factory) {
  const api = factory();
  if (typeof module === 'object' && module.exports) module.exports = api;
  else root.createIssueFilingReview = api;
})(typeof self !== 'undefined' ? self : this, function() {
  'use strict';

  const INTENT_LABELS = {
    'create-and-assign': 'Create & assign to me',
    'create-and-start': 'Create & start',
    'follow-up-and-next': 'Create follow-up & next',
  };

  function clone(value) {
    if (typeof structuredClone === 'function') return structuredClone(value);
    return JSON.parse(JSON.stringify(value));
  }

  function create(options) {
    let reviewed = null;
    let trigger = null;
    let busy = false;
    let evidenceItems = [];
    const generatedUrls = new Set();

    function releaseEvidenceUrls() {
      generatedUrls.forEach(url => options.revokeObjectURL?.(url));
      generatedUrls.clear();
      evidenceItems = [];
    }

    function evidenceUrl(attachment) {
      if (attachment?.blob) {
        const url = options.createObjectURL(attachment.blob);
        generatedUrls.add(url);
        return url;
      }
      if (attachment?.data) {
        return 'data:' + String(attachment.contentType || 'application/octet-stream') +
          ';base64,' + String(attachment.data);
      }
      return '';
    }

    function selectEvidence(index) {
      const selected = evidenceItems[index];
      if (!selected) return;
      evidenceItems.forEach((item, position) =>
        item.button.setAttribute('aria-pressed', position === index ? 'true' : 'false'));
      const filename = selected.attachment.filename || 'Screenshot';
      options.evidencePreview.hidden = false;
      options.evidenceImage.src = selected.url;
      options.evidenceImage.alt = 'Evidence ' + (index + 1) + ' of ' + evidenceItems.length + ': ' + filename;
      options.evidencePosition.textContent = 'Evidence ' + (index + 1) + ' of ' + evidenceItems.length;
      options.evidenceFilename.textContent = filename;
      options.evidenceNote.textContent = selected.attachment.note || 'No evidence note.';
    }

    function renderVisualEvidence(attachments) {
      releaseEvidenceUrls();
      options.evidenceEmpty.hidden = attachments.length > 0;
      options.evidencePreview.hidden = true;
      options.evidenceImage.src = '';
      evidenceItems = attachments.map((attachment, index) => {
        const url = evidenceUrl(attachment);
        const item = options.document.createElement('li');
        const button = options.document.createElement('button');
        const image = options.document.createElement('img');
        const filename = attachment.filename || 'Screenshot';
        button.setAttribute('type', 'button');
        button.className = 'issue-filing-evidence-selector';
        button.setAttribute('aria-label', 'Preview evidence ' + (index + 1) + ' of ' + attachments.length + ': ' + filename);
        button.setAttribute('aria-pressed', 'false');
        image.src = url;
        image.alt = '';
        button.appendChild(image);
        item.appendChild(button);
        return { attachment, button, item, url };
      });
      evidenceItems.forEach((entry, index) =>
        entry.button.addEventListener('click', () => selectEvidence(index)));
      options.evidenceList.replaceChildren(...evidenceItems.map(entry => entry.item));
      if (evidenceItems.length) selectEvidence(0);
    }

    function close() {
      options.sheet.hidden = true;
      const previousTrigger = trigger;
      trigger = null;
      reviewed = null;
      busy = false;
      releaseEvidenceUrls();
      options.confirmButton.disabled = false;
      previousTrigger?.focus();
    }

    function render(payload) {
      const draft = payload.draft;
      options.repository.textContent = draft.repository || 'No repository';
      options.intent.textContent = draft.unassigned === true ? 'Create unassigned' :
        (INTENT_LABELS[payload.intent] || payload.intent);
      if (options.issueType) options.issueType.textContent = draft.templateName || 'Blank issue';
      options.title.textContent = draft.title;
      options.body.textContent = draft.body || 'No note provided.';
      const labels = (draft.labels || []).map(label => typeof label === 'string' ? label : label.name);
      const milestone = draft.milestone?.title || draft.milestoneTitle || 'No milestone';
      const dueDate = draft.dueDate || draft.due_date || 'No due date';
      const owner = draft.unassigned === true ? 'Owner: No owner' : (draft.assignee
        ? 'Owner: ' + (draft.assigneeName || draft.assignee) + ' (@' + draft.assignee + ')'
        : 'Assigned to you');
      const planning = [];
      if (Number.isInteger(draft.estimateMinutes)) {
        planning.push('Estimate: ' + draft.estimateMinutes + ' min');
        const projected = draft.todayCapacity?.projectedMinutes;
        if (Number.isInteger(projected)) planning.push(projected >= 0
          ? 'Today after start: ' + projected + ' min free'
          : 'Today after start: ' + Math.abs(projected) + ' min over capacity');
      }
      options.metadata.textContent = [
        labels.length ? 'Labels: ' + labels.join(', ') : 'No labels',
        'Milestone: ' + milestone,
        'Due: ' + dueDate,
        owner,
        ...planning,
      ].join(' · ');
      if (options.blockerList) {
        options.blockerList.replaceChildren(...(draft.blockers || []).map(blocker => {
          const item = options.document.createElement('li');
          item.textContent = blocker.repository + ' #' + blocker.number + ' — ' + blocker.title;
          return item;
        }));
      }
      const attachments = (draft.attachments || (draft.attachment ? [draft.attachment] : [])).filter(Boolean);
      if (options.evidencePreview) {
        renderVisualEvidence(attachments);
        return;
      }
      options.evidenceList.replaceChildren(...attachments.map((attachment, index) => {
        const item = options.document.createElement('li');
        item.textContent = (index + 1) + '. ' + (attachment.filename || 'Screenshot') +
          (attachment.note ? ' — ' + attachment.note : '');
        return item;
      }));
    }

    function open(payload, opener) {
      reviewed = clone(payload);
      trigger = opener || null;
      busy = false;
      options.confirmButton.disabled = false;
      render(reviewed);
      options.sheet.hidden = false;
      options.backButton.focus();
    }

    options.backButton.addEventListener('click', close);
    options.confirmButton.addEventListener('click', async () => {
      if (!reviewed || busy) return;
      busy = true;
      options.confirmButton.disabled = true;
      try {
        await options.onConfirm(reviewed);
        close();
      } catch (error) {
        busy = false;
        options.confirmButton.disabled = false;
        if (options.status) options.status.textContent = error.message;
        options.confirmButton.focus();
      }
    });
    options.document.addEventListener('keydown', event => {
      if (!options.sheet.hidden && event.key === 'Escape' && !busy) {
        event.preventDefault();
        close();
      }
    });
    return { close, open };
  }

  return create;
});
