import { gradioApp } from './script';
import { updateInput } from './ui';

type AccordionElement = HTMLElement & {
  visibleCheckbox: HTMLInputElement;
  onVisibleCheckboxChange: () => void;
  onChecked: (checked: boolean) => void;
};

export function inputAccordionChecked(id: string, checked: boolean): void {
  const accordion = gradioApp().getElementById(id);
  if (!(accordion instanceof HTMLElement)) return;
  const acc = accordion as AccordionElement;
  acc.visibleCheckbox.checked = checked;
  acc.onVisibleCheckboxChange();
}

function setupAccordion(accordion: Element): void {
  if (!(accordion instanceof HTMLElement)) return;
  const acc = accordion as AccordionElement;
  const labelWrap = accordion.querySelector('.label-wrap');
  const gradioCheckbox = gradioApp().querySelector(`#${accordion.id}-checkbox input`);
  const extra = gradioApp().querySelector(`#${accordion.id}-extra`);
  if (!(labelWrap instanceof HTMLElement) || !(gradioCheckbox instanceof HTMLInputElement)) return;
  const span = labelWrap.querySelector('span');
  if (!(span instanceof HTMLElement)) return;
  let linked = true;
  const isOpen = () => labelWrap.classList.contains('open');
  const observerAccordionOpen = new MutationObserver((mutations) => {
    mutations.forEach((mutationRecord) => {
      accordion.classList.toggle('input-accordion-open', isOpen());
      if (linked) {
        acc.visibleCheckbox.checked = isOpen();
        acc.onVisibleCheckboxChange();
      }
    });
  });
  observerAccordionOpen.observe(labelWrap, { attributes: true, attributeFilter: ['class'] });
  if (extra instanceof Node) labelWrap.insertBefore(extra, labelWrap.lastElementChild);
  acc.onChecked = (checked: boolean) => {
    if (isOpen() !== checked) labelWrap.click();
  };

  const visibleCheckbox = document.createElement('INPUT');
  visibleCheckbox.type = 'checkbox';
  visibleCheckbox.checked = isOpen();
  visibleCheckbox.id = `${accordion.id}-visible-checkbox`;
  visibleCheckbox.className = `${gradioCheckbox.className} input-accordion-checkbox`;
  span.insertBefore(visibleCheckbox, span.firstChild);
  acc.visibleCheckbox = visibleCheckbox as any;
  acc.onVisibleCheckboxChange = () => {
    if (linked && isOpen() !== visibleCheckbox.checked) labelWrap.click();
    gradioCheckbox.checked = visibleCheckbox.checked;
    updateInput(gradioCheckbox);
  };

  visibleCheckbox.addEventListener('click', (event) => {
    linked = false;
    event.stopPropagation();
  });
  visibleCheckbox.addEventListener('input', acc.onVisibleCheckboxChange);
}

window.inputAccordionChecked = inputAccordionChecked;

// onUiLoaded(() => {
//  for (const accordion of gradioApp().querySelectorAll('.input-accordion')) setupAccordion(accordion);
// });

export function initAccordions() {
  for (const accordion of gradioApp().querySelectorAll('.input-accordion')) setupAccordion(accordion);
}