import * as React from 'react';

import './styles/main.css';

import { UI_LAYER } from '@usercentrics/cmp-browser-sdk';
import { InitialBanner } from './components/InitialBanner/InitialBanner';
import { InitialDialog } from './components/InitialDialog/InitialDialog';
import { SettingsModal } from './components/SettingsModal/SettingsModal';
import { DetailsModal } from './components/DetailsModal/DetailsModal';
import { useUsercentrics } from './contexts/UsercentricsContext';
import { DecisionsContext, selectAllUserDecisions } from './contexts/DecisionsContext';

interface CustomEvent extends Event {
  detail: {
    action: string;
    event: string;
    type: 'implicit' | 'explicit';
    [key: string]: string;
  };
}

export interface ContainerProps {
  afterFirstLayerAcceptedAll?: VoidFunction;
  afterFirstLayerCloseAndAcceptedAll?: VoidFunction;
  afterSecondLayerAcceptedAll?: VoidFunction;
  afterSecondLayerCloseAndAcceptedAll?: VoidFunction;
  afterSettingsSaved?: VoidFunction;
  afterSettingsOpened?: VoidFunction;
  onConsentStatusUpdate: (details: Record<string, string>) => void;
}

export const Container = (props: ContainerProps): JSX.Element => {
  const { categories, handlers, appearance, activeLayer, consentEventName } = useUsercentrics();
  const { decisions } = React.useContext(DecisionsContext);
  const { onConsentStatusUpdate } = props;

  const [isDetailsModalOpen, setDetailsModalOpen] = React.useState(false);
  const openDetailsModal = () => setDetailsModalOpen(true);
  const closeDetailsModal = () => setDetailsModalOpen(false);

  const handleFirstLayerAcceptAll = () => {
    handlers?.acceptAll();
    props.afterFirstLayerAcceptedAll?.();
  };

  const handleFirstLayerCloseAndAcceptAll = () => {
    handlers?.acceptAll();
    props.afterFirstLayerCloseAndAcceptedAll?.();
  };

  const handleSecondLayerAcceptAll = () => {
    handlers?.acceptAll();
    props.afterSecondLayerAcceptedAll?.();
  };

  const handleSecondLayerCloseAndAcceptAll = () => {
    handlers?.acceptAll();
    props.afterSecondLayerCloseAndAcceptedAll?.();
  };

  const handleSettingsModalSave = () => {
    handlers?.accept(selectAllUserDecisions(decisions));
    handlers?.setActiveLayer(UI_LAYER.NONE);
    props.afterSettingsSaved?.();
  };

  const handleOpenSettings = () => {
    handlers?.setActiveLayer(UI_LAYER.SECOND_LAYER);
    props.afterSettingsOpened?.();
  };

  const detailsModalAfterAcceptedAll = () => props.afterSecondLayerAcceptedAll?.();

  const handleConsentUpdate = React.useCallback(
    (event: CustomEvent) => {
      if (event.detail && event.detail.event === 'consent_status') {
        onConsentStatusUpdate(event.detail);
      }
    },
    [onConsentStatusUpdate]
  );

  React.useEffect(() => {
    window.addEventListener(consentEventName as any, handleConsentUpdate);
    return () => {
      window.removeEventListener(consentEventName as any, handleConsentUpdate);
    };
  }, [consentEventName, onConsentStatusUpdate, handleConsentUpdate]);

  switch (activeLayer) {
    case UI_LAYER.FIRST_LAYER:
      return (
        <>
          <InitialBanner
            visible={appearance === 'banner'}
            onAcceptAll={handleFirstLayerAcceptAll}
            onSettings={handleOpenSettings}
          />
          <InitialDialog
            isOpen={appearance === 'wall'}
            onAcceptAll={handleFirstLayerAcceptAll}
            onSettings={handleOpenSettings}
            onCloseAndAcceptAll={handleFirstLayerCloseAndAcceptAll}
          />
        </>
      );

    case UI_LAYER.SECOND_LAYER:
      return (
        <>
          <SettingsModal
            categories={categories}
            isOpen={true}
            onAcceptAll={handleSecondLayerAcceptAll}
            onCloseAndAcceptAll={handleSecondLayerCloseAndAcceptAll}
            onSave={handleSettingsModalSave}
            onMoreInfo={openDetailsModal}
          />
          <DetailsModal
            isOpen={isDetailsModalOpen}
            onClose={closeDetailsModal}
            afterAcceptedAll={detailsModalAfterAcceptedAll}
          />
        </>
      );
    default:
      return <></>;
  }
};
