import { SectionsWidget } from './SectionsWidget';
import { render, createPortal } from 'react-dom';
import { Fragment, memo, useEffect, useState } from 'react';
import { Provider as CacheContextProvider, type Cache } from './cache';

const EVENT_MOUNT = 'wpj:sections-autocomplete:mount';

export type RuntimeProps = {
   runtimeTarget: HTMLElement;
   onInit?: () => void;
};

export type WidgetProps = {
   // Buttons
   onAddSection?: (sectionId: number) => void;
   onAddWithSubsections?: (topsectionId: number) => void;

   // Row click
   onSelect?: (idSection: number) => void;
   shouldHideAfterSelect?: boolean;
};

export type MountEvent = CustomEvent<{
   mountTarget: HTMLElement;
} & WidgetProps>;

let CacheInitialized = false;

export function RuntimeComponent({ options }: { options: RuntimeProps }) {
   const { runtimeTarget, onInit } = options;
   const [portals, setPortals] = useState<MountEvent['detail'][]>([]);
   const [cache, setCache] = useState<Cache>({
      topLevelSections: [],
      _query: {},
      _fetchTopLevelSections: fetchTopLevelSections,
   });

   function fetchTopLevelSections() {
      if (CacheInitialized) {
         return;
      }

      const url = new URL('/admin/autocomplete/sections', `${window.location.protocol}//${window.location.host}`);
      fetch(url.href)
         .then(r => r.json())
         .then(sections => {
            setCache(p => ({ ...p, topLevelSections: sections }));
            CacheInitialized = true;
         })
         .catch(alert);
   }

   useEffect(() => {
      function mountEventHandler(ev: Event | MountEvent) {
         if (ev.type !== EVENT_MOUNT) {
            return;
         }
         const mountEvent = ev as MountEvent;

         setPortals(previous => [...previous, mountEvent.detail]);
      }

      runtimeTarget.addEventListener(EVENT_MOUNT, mountEventHandler);
      if (onInit) {
         onInit();
      }

      return () => {
         runtimeTarget.removeEventListener(EVENT_MOUNT, mountEventHandler);
      };
   }, []);

   return (
      <CacheContextProvider value={[cache, setCache]}>
         <PortalMounter portals={portals} />
      </CacheContextProvider>
   );
}

const PortalMounter = memo(({ portals }: { portals: MountEvent['detail'][] }) => {
   return (
      <>
         {portals.map((props, index) => (
            <Fragment key={index}>
               {createPortal(<SectionsWidget {...props} />, props.mountTarget, index.toString())}
            </Fragment>
         ))}
      </>
   );
});

export function prepareRuntime(runtimeTarget?: HTMLElement) {
   if (!runtimeTarget) {
      const elem = document.createElement('meta');
      document.body.insertAdjacentElement('beforeend', elem);

      runtimeTarget = elem;
   }

   runtimeTarget.dataset.sectionsAutocompleteRuntime = '';

   return new Promise<HTMLElement>((resolve) => {
      const options = { runtimeTarget, onInit: () => { resolve(runtimeTarget!) } } as RuntimeProps;

      render(
         <RuntimeComponent options={options} />,
         options.runtimeTarget,
      );
   });
}

export function mountAutocomplete(target: HTMLElement, options: WidgetProps = { shouldHideAfterSelect: true }) {
   const event: MountEvent = new CustomEvent(EVENT_MOUNT, {
      detail: {
         mountTarget: target,
         ...options,
      },
      bubbles: true,
   });

   const runtimeElement = document.querySelector('[data-sections-autocomplete-runtime]');
   if (!runtimeElement) {
      throw new Error('SectionsAutocomplete runtime not found');
   }

   runtimeElement.dispatchEvent(event);
}
