import {
  FloatingFocusManager,
  FloatingPortal,
  useDismiss,
  useFloating,
  useInteractions,
  useRole,
} from '@floating-ui/react';
import { Transition } from '@headlessui/react';
import { FocusScope } from '@react-aria/focus';
import { ThemeProvider, useTheme } from '@wise/components-theming';
import { clsx } from 'clsx';
import { Fragment, useState } from 'react';

import { CloseButton } from '../common/closeButton';
import { useVirtualKeyboard } from '../common/hooks/useVirtualKeyboard';
import { PreventScroll } from '../common/preventScroll/PreventScroll';
import { Size } from '../common/propsValues/size';

export interface BottomSheetProps {
  open: boolean;
  renderTrigger?: (args: {
    ref: React.RefCallback<Element>;
    getInteractionProps: (customEventHandlers?: React.HTMLProps<Element>) => {
      [key: string]: unknown;
    };
  }) => React.ReactNode;
  title?: string;
  initialFocusRef?: React.MutableRefObject<HTMLElement | null>;
  padding?: 'none' | 'md';
  children?: React.ReactNode;
  onClose?: () => void;
  onCloseEnd?: () => void;
}

export function BottomSheet({
  open,
  renderTrigger,
  title,
  initialFocusRef,
  padding = 'md',
  children,
  onClose,
  onCloseEnd,
}: BottomSheetProps) {
  useVirtualKeyboard();

  const { refs, context } = useFloating<Element>({
    open,
    onOpenChange: (value) => {
      if (!value) {
        onClose?.();
      }
    },
  });

  const dismiss = useDismiss(context);
  const role = useRole(context);
  const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, role]);

  const [floatingKey, setFloatingKey] = useState(0);

  const { theme, screenMode } = useTheme();

  return (
    <>
      {open ? <PreventScroll /> : null}
      {renderTrigger?.({
        ref: refs.setReference,
        getInteractionProps: getReferenceProps,
      })}

      <FloatingPortal>
        <ThemeProvider
          theme="personal"
          screenMode={theme === 'personal' ? screenMode : 'light'}
          isNotRootProvider
        >
          <Transition
            show={open}
            className="np-bottom-sheet-v2-container"
            beforeEnter={() => {
              setFloatingKey((prev) => prev + 1);
            }}
            afterLeave={onCloseEnd}
          >
            <Transition.Child
              className="np-bottom-sheet-v2-backdrop"
              enterFrom="np-bottom-sheet-v2-backdrop--closed"
              leaveTo="np-bottom-sheet-v2-backdrop--closed"
            />

            <div className="np-bottom-sheet-v2">
              <FocusScope>
                <FloatingFocusManager context={context} initialFocus={initialFocusRef}>
                  <Fragment
                    key={floatingKey} // Force inner state invalidation on open
                  >
                    <Transition.Child
                      ref={refs.setFloating}
                      className="np-bottom-sheet-v2-content"
                      enterFrom="np-bottom-sheet-v2-content--closed"
                      leaveTo="np-bottom-sheet-v2-content--closed"
                      {...getFloatingProps()}
                    >
                      <div className="np-bottom-sheet-v2-header">
                        <CloseButton
                          size={Size.SMALL}
                          onClick={() => {
                            onClose?.();
                          }}
                        />
                      </div>
                      <div
                        className={clsx(
                          'np-bottom-sheet-v2-content-inner',
                          title && 'np-bottom-sheet-v2-content-inner--has-title',
                          padding === 'md' && 'np-bottom-sheet-v2-content-inner--padding-md',
                        )}
                      >
                        {title ? (
                          <h2 className="np-bottom-sheet-v2-title np-text-title-body">{title}</h2>
                        ) : null}
                        <div className="np-bottom-sheet-v2-body np-text-body-default">
                          {children}
                        </div>
                      </div>
                    </Transition.Child>
                  </Fragment>
                </FloatingFocusManager>
              </FocusScope>
            </div>
          </Transition>
        </ThemeProvider>
      </FloatingPortal>
    </>
  );
}
