import { confirmDialog, requestSubmitWithFallback } from '../core/app-confirm-dialog.js';

const CONFIRM_ATTR = 'data-confirm-message';
const confirmedSubmitterByForm = new WeakMap();
const confirmedClickElements = new WeakSet();

const trimAttr = (element, attr) => String(element?.getAttribute(attr) || '').trim();

const isSubmitControl = (element) => {
  if (!(element instanceof HTMLElement)) {
    return false;
  }
  if (element instanceof HTMLButtonElement) {
    const type = String(element.getAttribute('type') || 'submit').trim().toLowerCase();
    return type === '' || type === 'submit';
  }
  if (element instanceof HTMLInputElement) {
    const type = String(element.type || '').trim().toLowerCase();
    return type === 'submit' || type === 'image';
  }
  return false;
};

const submitterByForm = new Map();
const belongsToForm = (control, form) => {
  if (!(control instanceof HTMLElement) || !(form instanceof HTMLFormElement)) {
    return false;
  }
  const owner = control.form;
  if (owner instanceof HTMLFormElement) {
    return owner === form;
  }
  const controlFormAttr = trimAttr(control, 'form');
  const formId = trimAttr(form, 'id');
  if (controlFormAttr !== '' && formId !== '') {
    return controlFormAttr === formId;
  }
  return form.contains(control);
};

const readConfirmOption = (primary, fallback, suffix) => {
  const attr = `data-confirm-${suffix}`;
  return trimAttr(primary, attr) || trimAttr(fallback, attr);
};

const buildConfirmOptions = (message, primary, fallback) => ({
  message,
  title: readConfirmOption(primary, fallback, 'title'),
  confirmLabel: readConfirmOption(primary, fallback, 'confirm-label'),
  cancelLabel: readConfirmOption(primary, fallback, 'cancel-label'),
  variant: readConfirmOption(primary, fallback, 'variant'),
  focus: readConfirmOption(primary, fallback, 'focus'),
  describedBy: readConfirmOption(primary, fallback, 'describedby')
    || readConfirmOption(primary, fallback, 'described-by'),
  actionKind: readConfirmOption(primary, fallback, 'action-kind')
});

const onClickCapture = (event) => {
  const trigger = event.target instanceof HTMLElement ? event.target.closest('a, button, input') : null;
  if (!(trigger instanceof HTMLElement)) {
    return;
  }

  if (confirmedClickElements.has(trigger)) {
    confirmedClickElements.delete(trigger);
    return;
  }

  if (isSubmitControl(trigger)) {
    const form = trigger.form instanceof HTMLFormElement ? trigger.form : null;
    if (form) {
      submitterByForm.set(form, trigger);
    }
    return;
  }

  const confirmMessage = String(trigger.getAttribute(CONFIRM_ATTR) || '').trim();
  if (confirmMessage === '') {
    return;
  }

  event.preventDefault();
  event.stopPropagation();

  void confirmDialog.confirm(buildConfirmOptions(confirmMessage, trigger, null))
    .then((approved) => {
      if (!approved || !document.contains(trigger)) {
        return;
      }
      confirmedClickElements.add(trigger);
      trigger.click();
    });
};

const onSubmitCapture = (event) => {
  const form = event.target instanceof HTMLFormElement ? event.target : null;
  if (!(form instanceof HTMLFormElement)) {
    return;
  }

  const submitter = event.submitter instanceof HTMLElement
    ? event.submitter
    : (submitterByForm.get(form) || null);
  submitterByForm.delete(form);

  const confirmedSubmitter = confirmedSubmitterByForm.get(form);
  if (confirmedSubmitter && (confirmedSubmitter === true || confirmedSubmitter === submitter || confirmedSubmitter === null)) {
    confirmedSubmitterByForm.delete(form);
    return;
  }

  const submitterMessage = String(submitter?.getAttribute(CONFIRM_ATTR) || '').trim();
  const formMessage = String(form.getAttribute(CONFIRM_ATTR) || '').trim();
  const confirmMessage = submitterMessage !== '' ? submitterMessage : formMessage;

  if (confirmMessage === '') {
    return;
  }

  event.preventDefault();
  event.stopPropagation();

  void confirmDialog.confirm(buildConfirmOptions(confirmMessage, submitter, form))
    .then((approved) => {
      if (!approved || !document.contains(form)) {
        return;
      }
      const submitterForSubmit = submitter && belongsToForm(submitter, form) ? submitter : null;
      confirmedSubmitterByForm.set(form, submitterForSubmit || true);
      requestSubmitWithFallback(form, submitterForSubmit);
    });
};

document.addEventListener('click', onClickCapture, true);
document.addEventListener('submit', onSubmitCapture, true);
