import { h } from '../core/dom';
import { modal, type ModalHandle } from '../ui/modal';
import { dropzone } from '../ui/dropzone';
import { icon } from '../ui/icons';
import { download, readBytes, isProbablyPdf, formatBytes, suffixName } from '../core/util';
import { celebrateExport, toast } from '../ui/toast';
import type { ToolContext } from './registry';

export interface LoadedFile {
  name: string;
  bytes: Uint8Array;
}

/** Open a feature modal with the standard chrome. */
export function featureModal(title: string, subtitle: string, iconName: string, width = 520): ModalHandle {
  return modal({ title, subtitle, icon: icon(iconName, 20), width });
}

/** Deliver result bytes to the user (download) and show the privacy celebration. */
export function deliver(bytes: Uint8Array, filename: string) {
  download(bytes, filename);
  celebrateExport(filename);
}

/**
 * A reusable PDF source picker. If launched from inside the editor, offers the
 * current document as the default source; otherwise shows a dropzone.
 * `onReady` fires with the selected file(s).
 */
export function pdfSource(
  ctx: ToolContext,
  opts: { multiple?: boolean; onChange: (files: LoadedFile[]) => void },
): HTMLElement {
  const multiple = !!opts.multiple;
  const wrap = h('div.source-picker');
  const files: LoadedFile[] = [];
  const list = h('div.source-list');
  // The entry added via the "use the open document" button, if any and
  // still present — tracked by identity so removing it (or replacing the
  // single-file slot with a fresh upload) can bring the button back.
  let currentDocEntry: LoadedFile | null = null;
  let currentBtn: HTMLButtonElement | null = null;

  const setCurrentBtnVisible = (visible: boolean) => { if (currentBtn) currentBtn.hidden = !visible; };

  const emit = () => opts.onChange(files.slice());
  const addFile = (f: LoadedFile, fromCurrent = false) => {
    if (!multiple) {
      files.length = 0;
      currentDocEntry = null;
    }
    files.push(f);
    if (fromCurrent) currentDocEntry = f;
    setCurrentBtnVisible(!currentDocEntry);
    renderList();
    emit();
  };
  const renderList = () => {
    list.replaceChildren();
    files.forEach((f, i) => {
      list.appendChild(
        h('div.source-file',
          h('span.source-file-icon', icon('file', 16)),
          h('span.source-file-name', f.name),
          h('span.source-file-size', formatBytes(f.bytes.length)),
          h('button.source-file-x', {
            title: 'Remove',
            onclick: () => {
              const [removed] = files.splice(i, 1);
              if (removed === currentDocEntry) {
                currentDocEntry = null;
                setCurrentBtnVisible(true);
              }
              renderList();
              emit();
            },
          }, '×'),
        ),
      );
    });
  };

  const dz = dropzone({
    accept: 'application/pdf,.pdf',
    multiple: opts.multiple,
    compact: true,
    label: multiple ? 'Add PDF files' : 'Drop a PDF or click to browse',
    onFiles: async (fs) => {
      for (const f of fs) {
        const bytes = await readBytes(f);
        if (!isProbablyPdf(bytes)) { toast(`${f.name} isn’t a PDF.`, { type: 'error' }); continue; }
        addFile({ name: f.name, bytes });
      }
    },
  });

  // offer the current editor document as a quick source
  const current = ctx.currentBytes?.();
  if (current && current.length) {
    currentBtn = h('button.source-current', {
      onclick: () => addFile({ name: ctx.currentName?.() ?? 'document.pdf', bytes: current }, true),
    }, icon('file', 16), `Use the open document (${ctx.currentName?.() ?? 'current PDF'})`) as HTMLButtonElement;
    wrap.appendChild(currentBtn);
  }
  wrap.append(dz, list);
  return wrap;
}

/** Primary/secondary footer buttons. */
export function footerButtons(m: ModalHandle, primaryLabel: string, onPrimary: () => void, primaryIcon = 'download'): { primary: HTMLButtonElement } {
  const primary = h('button.btn btn-primary', { onclick: onPrimary }, icon(primaryIcon, 16), primaryLabel) as HTMLButtonElement;
  m.footer.append(h('button.btn btn-soft', { onclick: () => m.close() }, 'Cancel'), primary);
  return { primary };
}

export { suffixName };
