import { h } from '../core/dom';

export interface ModalHandle {
  el: HTMLElement;
  body: HTMLElement;
  footer: HTMLElement;
  close(result?: any): void;
  setBusy(busy: boolean, label?: string): void;
  onClose(cb: (result: any) => void): void;
}

export interface ModalOptions {
  title: string;
  subtitle?: string;
  icon?: Node;
  width?: number;
  dismissable?: boolean;
}

/** Create a glassmorphism modal dialog. Returns a handle to fill body/footer. */
export function modal(opts: ModalOptions): ModalHandle {
  const closeCbs: ((r: any) => void)[] = [];
  let result: any;

  const body = h('div.modal-body');
  const footer = h('div.modal-footer');
  const busyOverlay = h(
    'div.modal-busy',
    h('div.spinner spinner-ink'),
    h('div.modal-busy-label', 'Working…'),
  );

  const dialog = h(
    'div.modal glass',
    { style: { maxWidth: `${opts.width ?? 520}px` }, role: 'dialog', 'aria-modal': 'true' },
    h(
      'div.modal-head',
      opts.icon ? h('div.modal-icon', opts.icon) : null,
      h(
        'div.modal-titles',
        h('h3.modal-title', opts.title),
        opts.subtitle ? h('p.modal-sub', opts.subtitle) : null,
      ),
      opts.dismissable !== false
        ? h('button.modal-x', { onclick: () => close(), 'aria-label': 'Close' }, '×')
        : null,
    ),
    body,
    footer,
    busyOverlay,
  );

  const backdrop = h('div.modal-backdrop', dialog);
  backdrop.addEventListener('mousedown', (e) => {
    if (e.target === backdrop && opts.dismissable !== false) close();
  });
  const onKey = (e: KeyboardEvent) => {
    if (e.key === 'Escape' && opts.dismissable !== false) close();
  };
  document.addEventListener('keydown', onKey);

  document.body.appendChild(backdrop);
  requestAnimationFrame(() => backdrop.classList.add('in'));

  function close(r?: any) {
    if (r !== undefined) result = r;
    document.removeEventListener('keydown', onKey);
    backdrop.classList.remove('in');
    setTimeout(() => backdrop.remove(), 220);
    closeCbs.forEach((cb) => cb(result));
  }
  function setBusy(busy: boolean, label = 'Working…') {
    (busyOverlay.querySelector('.modal-busy-label') as HTMLElement).textContent = label;
    busyOverlay.classList.toggle('show', busy);
  }

  return {
    el: dialog,
    body,
    footer,
    close,
    setBusy,
    onClose: (cb) => closeCbs.push(cb),
  };
}

/** Simple confirm dialog. Resolves true/false. */
export function confirmDialog(opts: {
  title: string;
  message: string;
  confirmLabel?: string;
  danger?: boolean;
}): Promise<boolean> {
  return new Promise((resolve) => {
    const m = modal({ title: opts.title, width: 440 });
    m.body.appendChild(h('p.modal-text', opts.message));
    m.footer.append(
      h('button.btn btn-soft', { onclick: () => m.close(false) }, 'Cancel'),
      h(
        `button.btn ${opts.danger ? 'btn-danger' : 'btn-primary'}`,
        { onclick: () => m.close(true) },
        opts.confirmLabel ?? 'Confirm',
      ),
    );
    m.onClose((r) => resolve(!!r));
  });
}
