'use strict';

(() => {

/**
 * Small modal factories used by the renderer. They stay intentionally plain:
 * a modal title, a few form rows, and action buttons. No decorative clutter.
 */

function labeledRow(labelText, control, { stacked = false } = {}) {
  return el(stacked ? 'div.form-row.stacked' : 'div.form-row', {},
    el('label', {}, labelText),
    control
  );
}

function makeInput(value = '', type = 'text', attrs = {}) {
  return el('input', { type, value, ...attrs });
}

function makeSelect(value, options) {
  return el('select', {},
    options.map((opt) => el('option', { value: opt.value, selected: opt.value === value }, opt.label))
  );
}

async function promptText({ title, label = 'Value', value = '', placeholder = '', multiline = false } = {}) {
  return new Promise((resolve) => {
    const field = multiline
      ? el('textarea', { rows: 6, placeholder }, value)
      : el('input', { type: 'text', value, placeholder });

    const { close } = openModal({
      title,
      body: labeledRow(label, field, { stacked: multiline }),
      footer: [
        el('button', { onClick: () => { close(); resolve(null); } }, 'Cancel'),
        el('button.primary', { onClick: () => { close(); resolve(field.value); } }, 'OK'),
      ],
      onClose: () => resolve(null),
    });

    field.addEventListener('keydown', (e) => {
      if (!multiline && e.key === 'Enter') {
        e.preventDefault();
        close();
        resolve(field.value);
      }
    });

    setTimeout(() => field.focus(), 0);
  });
}

function showQuickActions({ query = '', commands = [], searchFn, onOpenItem, onClose } = {}) {
  return new Promise((resolve) => {
    const input = el('input', {
      type: 'search',
      value: query,
      placeholder: 'Search guides, steps, and commands',
      autocomplete: 'off',
      spellcheck: false,
    });
    const results = el('div.qa-results');
    const hint = el('div.muted', {}, 'Type to search, arrows to move, Enter to open.');
    let items = [];
    let active = 0;

    function renderItems() {
      clearNode(results);
      if (!items.length) {
        results.append(el('div.muted', { style: { padding: '8px 2px' } }, 'No matches.'));
        return;
      }
      items.forEach((item, idx) => {
        results.append(el('div.qa-item', {
          className: `qa-item${idx === active ? ' active' : ''}`,
          onMouseenter: () => { active = idx; renderItems(); },
          onClick: () => choose(idx),
        },
        el('span.kind', {}, item.kind || 'cmd'),
        el('div', {},
          el('div', { style: { fontWeight: 600 } }, item.label),
          item.description ? el('div.snippet', {}, item.description) : null,
        )));
      });
    }

    function choose(idx = active) {
      const item = items[idx];
      if (!item) return;
      close();
      if (item.action) item.action();
      if (onOpenItem) onOpenItem(item);
      resolve(item);
    }

    async function refresh() {
      const q = input.value.trim();
      const commandMatches = commands.filter((cmd) => {
        if (!q) return true;
        const needle = q.toLowerCase();
        return `${cmd.label} ${cmd.description || ''}`.toLowerCase().includes(needle);
      }).map((cmd) => ({ ...cmd, kind: cmd.kind || 'cmd' }));
      const searchResults = q && searchFn ? await searchFn(q) : [];
      items = [...commandMatches, ...searchResults];
      if (active >= items.length) active = 0;
      renderItems();
    }

    const { close } = openModal({
      title: 'Quick Actions',
      body: el('div.quick-actions', {},
        input,
        hint,
        results,
      ),
      wide: true,
      footer: [
        el('button', { onClick: () => { close(); resolve(null); } }, 'Close'),
      ],
      onClose: () => {
        if (onClose) onClose();
        resolve(null);
      },
    });

    const debounced = debounce(refresh, 60);
    input.addEventListener('input', debounced);
    input.addEventListener('keydown', (e) => {
      if (e.key === 'ArrowDown') { e.preventDefault(); active = Math.min(items.length - 1, active + 1); renderItems(); }
      else if (e.key === 'ArrowUp') { e.preventDefault(); active = Math.max(0, active - 1); renderItems(); }
      else if (e.key === 'Enter') { e.preventDefault(); choose(); }
      else if (e.key === 'Escape') { e.preventDefault(); close(); resolve(null); }
    });

    refresh();
    setTimeout(() => input.focus(), 0);
  });
}

function showSettingsDialog({
  settings,
  placeholders = {},
  onSave,
} = {}) {
  return new Promise((resolve) => {
    const form = el('form', { className: 'settings-form' });

    const appearance = makeSelect(settings.appearance || 'system', [
      { value: 'system', label: 'System' },
      { value: 'light', label: 'Light' },
      { value: 'dark', label: 'Dark' },
    ]);
    const spellcheck = el('input', { type: 'checkbox', checked: Boolean(settings.spellcheck) });
    const delayMs = makeInput(settings.capture?.delayMs ?? 0, 'number', { min: 0, step: 50 });
    const captureMode = makeSelect(settings.capture?.mode || 'fullscreen', [
      { value: 'fullscreen', label: 'Fullscreen' },
      { value: 'window', label: 'Window' },
      { value: 'region', label: 'Region' },
    ]);
    const clickMarker = el('input', { type: 'checkbox', checked: Boolean(settings.capture?.clickMarker) });
    const captureHotkey = makeInput(settings.capture?.hotkeyCapture || '', 'text');
    const pauseHotkey = makeInput(settings.capture?.hotkeyPauseResume || '', 'text');
    const focusedDefault = el('input', { type: 'checkbox', checked: Boolean(settings.editor?.focusedViewDefaultForNewSteps) });
    const previewCount = makeInput(settings.exports?.previewStepCount ?? 3, 'number', { min: 1, step: 1 });
    const openFolder = el('input', { type: 'checkbox', checked: Boolean(settings.exports?.openFolderAfterExport) });
    const captureOutside = el('input', { type: 'checkbox', checked: Boolean(settings.capture?.captureOutsideClicks) });
    const confirmSimple = el('input', { type: 'checkbox', checked: Boolean(settings.capture?.confirmSimpleCapture) });
    const keepLast = makeInput(settings.backups?.keepLast ?? 10, 'number', { min: 0, step: 1 });

    const placeholderRows = el('div', { className: 'placeholder-rows' });
    const rows = [];
    const addPlaceholderRow = (key = '', value = '') => {
      const keyInput = makeInput(key);
      const valueInput = makeInput(value);
      const removeBtn = el('button.icon', {
        type: 'button',
        title: 'Remove placeholder',
        onClick: () => {
          row.remove();
          rows.splice(rows.indexOf(row), 1);
        },
      }, '−');
      const row = el('div.placeholder-row', {},
        keyInput,
        valueInput,
        removeBtn,
      );
      rows.push(row);
      placeholderRows.append(row);
      return row;
    };
    Object.entries(placeholders || {}).forEach(([k, v]) => addPlaceholderRow(k, v));

    const addPlaceholderBtn = el('button', {
      type: 'button',
      onClick: () => addPlaceholderRow(),
    }, 'Add placeholder');

    form.append(
      el('fieldset', {},
        el('legend', {}, 'Appearance'),
        labeledRow('Theme', appearance),
        labeledRow('Spellcheck', spellcheck),
        labeledRow('Open folder after export', openFolder),
      ),
      el('fieldset', {},
        el('legend', {}, 'Capture'),
        labeledRow('Default mode', captureMode),
        labeledRow('Delay (ms)', delayMs),
        labeledRow('Click marker', clickMarker),
        labeledRow('Capture outside clicks', captureOutside),
        labeledRow('Confirm simple capture', confirmSimple),
        labeledRow('Capture hotkey', captureHotkey),
        labeledRow('Pause / resume hotkey', pauseHotkey),
      ),
      el('fieldset', {},
        el('legend', {}, 'Editor'),
        labeledRow('Focused view for new steps', focusedDefault),
        labeledRow('Preview step count', previewCount),
      ),
      el('fieldset', {},
        el('legend', {}, 'Backups'),
        labeledRow('Keep last snapshots', keepLast),
      ),
      el('fieldset', {},
        el('legend', {}, 'Global placeholders'),
        placeholderRows,
        el('div.row', { style: { justifyContent: 'flex-start' } }, addPlaceholderBtn),
      ),
    );

    const { close } = openModal({
      title: 'Settings',
      body: form,
      wide: true,
      footer: [
        el('button', { type: 'button', onClick: () => { close(); resolve(false); } }, 'Cancel'),
        el('button.primary', {
          type: 'submit',
          onClick: async (e) => {
            e.preventDefault();
            const next = {
              appearance: appearance.value,
              spellcheck: spellcheck.checked,
              capture: {
                ...settings.capture,
                delayMs: Number(delayMs.value || 0),
                mode: captureMode.value,
                clickMarker: clickMarker.checked,
                hotkeyCapture: captureHotkey.value.trim(),
                hotkeyPauseResume: pauseHotkey.value.trim(),
                captureOutsideClicks: captureOutside.checked,
                confirmSimpleCapture: confirmSimple.checked,
              },
              editor: {
                ...settings.editor,
                focusedViewDefaultForNewSteps: focusedDefault.checked,
              },
              exports: {
                ...settings.exports,
                previewStepCount: Number(previewCount.value || 3),
                openFolderAfterExport: openFolder.checked,
              },
              backups: {
                ...settings.backups,
                keepLast: Number(keepLast.value || 0),
              },
              placeholders: rows.reduce((acc, row) => {
                const inputs = row.querySelectorAll('input');
                const key = inputs[0].value.trim();
                const value = inputs[1].value;
                if (key) acc[key] = value;
                return acc;
              }, {}),
            };
            await onSave(next);
            close();
            resolve(true);
          },
        }, 'Save'),
      ],
      onClose: () => resolve(false),
    });

    form.addEventListener('submit', (e) => e.preventDefault());
  });
}

function showExportDialog({
  formats,
  templatesByFormat = {},
  defaultFormat = 'pdf',
  defaultOutDir = '',
  onChooseDir,
  onExport,
  onPreview,
  onLoadDefaults,      // async (format) => exporter DEFAULT_TEMPLATE
  onLoadTemplate,      // async (format, name) => saved options
  onSaveTemplate,      // async (format, name, options)
  onManageTemplates,   // async (format) => refreshed template name list
} = {}) {
  return new Promise((resolve) => {
    const formatOptions = (formats || []).map((f) => {
      if (typeof f === 'string') return { value: f, label: f };
      return { value: f.id || f.value || f.name, label: f.label || f.id || f.value || f.name };
    });
    const formatSelect = makeSelect(defaultFormat, formatOptions);
    const templateSelect = makeSelect('', [{ value: '', label: 'Default template' }]);
    const outDirInput = makeInput(defaultOutDir, 'text', { placeholder: 'Choose an output folder' });
    const optionsHost = el('div', { className: 'export-options' });

    // The effective option set shown to (and edited by) the user.
    let defaults = {};
    let current = {};

    function renderOptions() {
      clearNode(optionsHost);
      const entries = Object.entries(defaults)
        .filter(([, v]) => ['boolean', 'number', 'string'].includes(typeof v));
      if (!entries.length) {
        optionsHost.append(el('div.muted', {}, 'This format has no adjustable options.'));
        return;
      }
      for (const [key, defVal] of entries) {
        const value = current[key] ?? defVal;
        const label = key.replace(/([A-Z])/g, ' $1').replace(/^./, (c) => c.toUpperCase());
        let control;
        if (typeof defVal === 'boolean') {
          control = el('input', { type: 'checkbox', checked: Boolean(value) });
          control.addEventListener('change', () => { current[key] = control.checked; });
        } else if (typeof defVal === 'number') {
          control = makeInput(value, 'number', { step: 'any' });
          control.addEventListener('input', () => { current[key] = Number(control.value); });
        } else {
          control = makeInput(value, 'text');
          control.addEventListener('input', () => { current[key] = control.value; });
        }
        optionsHost.append(labeledRow(label, control));
      }
    }

    async function refreshOptions() {
      defaults = (await onLoadDefaults?.(formatSelect.value)) || {};
      const saved = templateSelect.value
        ? (await onLoadTemplate?.(formatSelect.value, templateSelect.value)) || {}
        : {};
      current = { ...saved };
      renderOptions();
    }

    function refreshTemplates(list = templatesByFormat[formatSelect.value] || []) {
      clearNode(templateSelect);
      templateSelect.append(el('option', { value: '' }, 'Default template'));
      for (const name of list) templateSelect.append(el('option', { value: name }, name));
    }

    formatSelect.addEventListener('change', () => { refreshTemplates(); refreshOptions(); });
    templateSelect.addEventListener('change', () => refreshOptions());
    refreshTemplates();
    refreshOptions();

    const effectiveOptions = () => {
      // only keep values that differ from defaults, so templates stay minimal
      const out = {};
      for (const [k, v] of Object.entries(current)) {
        if (v !== undefined && v !== defaults[k]) out[k] = v;
      }
      return out;
    };

    const saveTplBtn = el('button', {
      type: 'button',
      onClick: async () => {
        const name = await promptText({ title: 'Save template', label: 'Template name', value: templateSelect.value || '' });
        if (!name || !name.trim()) return;
        await onSaveTemplate?.(formatSelect.value, name.trim(), effectiveOptions());
        const list = await onManageTemplates?.(formatSelect.value, null);
        refreshTemplates(list || []);
        templateSelect.value = name.trim();
      },
    }, 'Save as template…');

    const manageBtn = el('button', {
      type: 'button',
      onClick: async () => {
        const list = await onManageTemplates?.(formatSelect.value, 'manage');
        refreshTemplates(list || []);
        refreshOptions();
      },
    }, 'Manage…');

    const body = el('div.export-dialog', {},
      labeledRow('Format', formatSelect),
      labeledRow('Template', el('div.row', {}, templateSelect, saveTplBtn, manageBtn)),
      labeledRow('Output folder', el('div.row', {}, outDirInput, el('button', {
        type: 'button',
        disabled: typeof onChooseDir !== 'function',
        onClick: async () => {
          if (typeof onChooseDir !== 'function') return;
          const chosen = await onChooseDir(formatSelect.value);
          if (chosen) outDirInput.value = chosen;
        },
      }, 'Choose…'))),
      el('fieldset', {}, el('legend', {}, 'Options'), optionsHost),
    );

    const payload = () => ({
      format: formatSelect.value,
      templateName: templateSelect.value || null,
      options: effectiveOptions(),
      outDir: outDirInput.value.trim() || null,
    });

    const { close } = openModal({
      title: 'Export',
      body,
      footer: [
        el('button', { onClick: () => { close(); resolve(false); } }, 'Cancel'),
        el('button', {
          onClick: async () => {
            if (typeof onPreview !== 'function') return;
            await onPreview(payload()); // keep dialog open so settings can be tweaked
          },
        }, 'Preview'),
        el('button.primary', {
          onClick: async () => {
            if (typeof onExport !== 'function') return;
            const ok = await onExport(payload());
            if (ok !== false) {
              close();
              resolve(true);
            }
          },
        }, 'Export'),
      ],
      wide: true,
      onClose: () => resolve(false),
    });
  });
}

/** Template management list: rename / duplicate / delete / import / export. */
function showTemplateManager({ format, names = [], onRename, onDuplicate, onDelete, onImport, onExport }) {
  return new Promise((resolve) => {
    let list = [...names];
    const rows = el('div', { className: 'card-list' });

    function renderRows() {
      clearNode(rows);
      if (!list.length) {
        rows.append(el('div.muted', {}, 'No templates saved for this format yet.'));
        return;
      }
      for (const name of list) {
        rows.append(el('div.row', { style: { justifyContent: 'space-between', gap: '8px' } },
          el('span', {}, name),
          el('div.row', {},
            el('button', {
              type: 'button',
              onClick: async () => {
                const next = await promptText({ title: 'Rename template', label: 'Name', value: name });
                if (next && next.trim() && next.trim() !== name) {
                  list = await onRename(name, next.trim());
                  renderRows();
                }
              },
            }, 'Rename'),
            el('button', { type: 'button', onClick: async () => { list = await onDuplicate(name); renderRows(); } }, 'Duplicate'),
            el('button', { type: 'button', onClick: async () => { await onExport(name); } }, 'Share…'),
            el('button.danger', { type: 'button', onClick: async () => { list = await onDelete(name); renderRows(); } }, 'Delete'),
          ),
        ));
      }
    }

    const { close } = openModal({
      title: `Templates — ${format}`,
      body: el('div', {},
        el('div.row', { style: { marginBottom: '10px' } },
          el('button', { type: 'button', onClick: async () => { list = await onImport(); renderRows(); } }, 'Import .sfglt…'),
          el('span.muted', {}, 'Templates are shareable as .sfglt files.'),
        ),
        rows,
      ),
      footer: [el('button.primary', { onClick: () => { close(); resolve(list); } }, 'Done')],
      wide: true,
      onClose: () => resolve(list),
    });
    renderRows();
  });
}

function showLinkedGuideDialog({ guide, lock, onSave, onForceSave, onOpenArchive } = {}) {
  return new Promise((resolve) => {
    const linked = guide.linkedSource || {};
    const conflict = lock && !lock.acquired;
    const conflictInfo = lock && lock.conflict ? lock.conflict : {};
    const lockInfo = conflict
      ? `Locked by ${conflictInfo.user || 'another user'}@${conflictInfo.host || 'another host'}`
      : 'No active conflict';

    const body = el('div', { className: 'linked-guide' },
      el('div', { className: 'card-list' },
        el('div.row', {}, el('span.muted', {}, 'Archive'), el('strong', {}, linked.path || 'Not linked')),
        el('div.row', {}, el('span.muted', {}, 'Opened'), el('span', {}, fmtDate(linked.openedAt) || 'Unknown')),
        el('div.row', {}, el('span.muted', {}, 'Last saved'), el('span', {}, fmtDate(linked.lastSavedAt) || 'Never')),
        el('div.row', {}, el('span.muted', {}, 'Lock'), el('span', {}, lockInfo)),
      ),
      conflict ? el('div', { className: 'warn-banner' }, 'Another editor has the archive locked. You can force-save if you intend to overwrite it.') : null,
    );

    const { close } = openModal({
      title: 'Linked Guide',
      body,
      footer: [
        el('button', { onClick: () => { close(); resolve(false); } }, 'Close'),
        el('button', {
          onClick: async () => {
            await onOpenArchive?.(guide);
          },
        }, 'Show file'),
        conflict ? el('button.primary', {
          onClick: async () => {
            await onForceSave?.(guide);
            close();
            resolve(true);
          },
        }, 'Force save') : el('button.primary', {
          onClick: async () => {
            await onSave?.(guide);
            close();
            resolve(true);
          },
        }, 'Save now'),
      ],
      wide: true,
      onClose: () => resolve(false),
    });
  });
}

function showBackupsDialog({ snapshots = [], onCreate, onRestore } = {}) {
  return new Promise((resolve) => {
    let list = [...snapshots];
    const rows = el('div', { className: 'card-list' });

    function renderRows() {
      clearNode(rows);
      if (!list.length) {
        rows.append(el('div.muted', {}, 'No snapshots yet. Automatic snapshots are created as you work; create one manually any time.'));
        return;
      }
      for (const name of list) {
        rows.append(el('div.row', { style: { justifyContent: 'space-between', gap: '10px' } },
          el('span', { style: { overflow: 'hidden', textOverflow: 'ellipsis' } }, name),
          el('button', {
            type: 'button',
            onClick: async () => {
              const restored = await onRestore?.(name);
              if (restored) close();
            },
          }, 'Restore'),
        ));
      }
    }

    const createBtn = el('button.primary', {
      type: 'button',
      onClick: async () => {
        const refreshed = await onCreate?.();
        if (Array.isArray(refreshed)) {
          list = refreshed;
          renderRows();
        }
      },
    }, 'Create snapshot');

    const { close } = openModal({
      title: 'Backups & snapshots',
      body: el('div', {},
        el('div.row', { style: { marginBottom: '10px' } }, createBtn,
          el('span.muted', {}, 'Restores are undoable — the current state is snapshotted first.')),
        rows,
      ),
      footer: [el('button', { onClick: () => { close(); resolve(true); } }, 'Close')],
      wide: true,
      onClose: () => resolve(true),
    });
    renderRows();
  });
}

function showPlaceholdersDialog({ title = 'Placeholders', hint = '', values = {}, onSave } = {}) {
  return new Promise((resolve) => {
    const rowsHost = el('div', { className: 'placeholder-rows' });
    const rows = [];
    const addRow = (key = '', value = '') => {
      const keyInput = makeInput(key, 'text', { placeholder: 'Name' });
      const valueInput = makeInput(value, 'text', { placeholder: 'Value' });
      const row = el('div.placeholder-row', {}, keyInput, valueInput,
        el('button.icon', {
          type: 'button', title: 'Remove',
          onClick: () => { row.remove(); rows.splice(rows.indexOf(row), 1); },
        }, '−'));
      rows.push(row);
      rowsHost.append(row);
    };
    Object.entries(values || {}).forEach(([k, v]) => addRow(k, v));
    if (!Object.keys(values || {}).length) addRow();

    const { close } = openModal({
      title,
      body: el('div', {},
        hint ? el('div.muted', { style: { marginBottom: '10px' } }, hint) : null,
        rowsHost,
        el('div.row', { style: { marginTop: '8px' } },
          el('button', { type: 'button', onClick: () => addRow() }, 'Add placeholder')),
      ),
      footer: [
        el('button', { onClick: () => { close(); resolve(false); } }, 'Cancel'),
        el('button.primary', {
          onClick: async () => {
            const next = rows.reduce((acc, row) => {
              const inputs = row.querySelectorAll('input');
              const key = inputs[0].value.trim();
              if (key) acc[key] = inputs[1].value;
              return acc;
            }, {});
            await onSave?.(next);
            close();
            resolve(true);
          },
        }, 'Save'),
      ],
      onClose: () => resolve(false),
    });
  });
}

const SHORTCUTS = [
  ['Capture & steps', [
    ['Ctrl+S', 'Save (writes linked archive when guide is linked)'],
    ['Ctrl+/', 'Quick actions palette'],
    ['PageUp / PageDown', 'Previous / next step'],
    ['Alt+↑ / Alt+↓', 'Move step up / down'],
    ['Ctrl+Delete', 'Delete current step'],
    ['Ctrl+V', 'Paste annotation, or clipboard image as new step'],
  ]],
  ['Canvas tools', [
    ['S R O L A T', 'Select · Rect · Oval · Line · Arrow · Text'],
    ['G N B H M U C', 'Tooltip · Number · Blur · Highlight · Magnify · Cursor · Crop'],
    ['Ctrl+C', 'Copy selected annotation'],
    ['Delete', 'Delete selected annotation'],
    ['Esc', 'Deselect annotation'],
    ['Arrows / Shift+Arrows', 'Nudge selection by 1 px / 10 px'],
  ]],
  ['View', [
    ['Ctrl+= / Ctrl+-', 'Zoom in / out'],
    ['Ctrl+0', 'Fit image to window'],
  ]],
];

function showShortcutsDialog() {
  return new Promise((resolve) => {
    const sections = SHORTCUTS.map(([heading, items]) => el('div', {},
      el('h3', { style: { margin: '8px 0 6px' } }, heading),
      el('table', { style: { width: '100%', borderCollapse: 'collapse' } },
        ...items.map(([keys, what]) => el('tr', {},
          el('td', { style: { padding: '3px 14px 3px 0', whiteSpace: 'nowrap' } }, el('kbd', {}, keys)),
          el('td', { style: { padding: '3px 0' } }, what),
        )),
      ),
    ));
    const { close } = openModal({
      title: 'Keyboard shortcuts',
      body: el('div', {}, ...sections),
      footer: [el('button.primary', { onClick: () => { close(); resolve(true); } }, 'Close')],
      onClose: () => resolve(true),
    });
  });
}

function showInfoDialog(title, bodyText) {
  return new Promise((resolve) => {
    const { close } = openModal({
      title,
      body: el('div', {}, bodyText),
      footer: [el('button.primary', { onClick: () => { close(); resolve(true); } }, 'OK')],
      onClose: () => resolve(false),
    });
  });
}

window.StepForgeDialogs = {
  promptText,
  showQuickActions,
  showSettingsDialog,
  showExportDialog,
  showLinkedGuideDialog,
  showInfoDialog,
  showBackupsDialog,
  showPlaceholdersDialog,
  showShortcutsDialog,
  showTemplateManager,
};
})();
