import { useCallback, useRef } from 'react';

import type { DialogBoxApi, DialogBoxProps } from '~/src/components/DialogBox';
import type { CSSProperties, FC, ReactNode } from 'react';

import Box from '~/src/components/Box';
import { ConfirmButton } from '~/src/components/Button/ConfirmButton';
import Card from '~/src/components/Card';
import Clickable from '~/src/components/Clickable';
import ClickableModal from '~/src/components/ClickableModal';
import DialogBox from '~/src/components/DialogBox';
import { DialogBoxHeader } from '~/src/components/DialogBox/DialogBoxHeader';
import { FORM_SECTION_SPACING } from '~/src/components/Form';
import GripIcon from '~/src/components/Icon/GripIcon';
import MoreIcon from '~/src/components/Icon/MoreIcon';
import { useEditActions } from '~/src/components/ItemPage/ItemPageEdit/useEditActions';
import Text from '~/src/components/Text';
import useHash from '~/src/hooks/useHash';
import useIsLargeScreen from '~/src/hooks/useIsLargeScreen';
import { useI18n } from '~/src/lib/i18n';
import { toRgba } from '~/src/lib/utils/color';
import wait from '~/src/lib/utils/wait';
import { usePageTheme } from '../../../hooks/theme';
import DashedSectionBox from '../../../ItemPageEdit/components/DashedSectionBox';

interface EditWrapperProps {
  children: ReactNode;
  sectionPath: string;
  renderSettingsContent?: DialogBoxProps['renderContent'];
  renderSettingsHeader?: DialogBoxProps['renderHeader'];
  onSettingsClose?: () => void;
  padding?: string;
  headerStyle?: CSSProperties;
  renderHeaderContent?: () => ReactNode;
  settingsTitle?: string;
  borderColor?: string;

  /**
   * Indicates that the component is shared from another layout.
   * EditWrapper will disable some interactions.
   */
  isShared?: boolean;

  /**
   * Indicates that the component is mandatory and cannot be removed.
   */
  isMandatory?: boolean;

  style?: CSSProperties;
  isSortable?: boolean;
  withSettingsButton?: boolean;
  withInlineHeader?: boolean;
}

// WARN: must match PageSectionSortableContainer
const DRAG_HANDLE_CLASS = 'dragHandle';

export const EditWrapper: FC<EditWrapperProps> = ({
  renderSettingsContent,
  renderSettingsHeader,
  renderHeaderContent,
  onSettingsClose,
  settingsTitle,
  children,
  padding,
  sectionPath,
  headerStyle,
  isShared,
  isSortable = true,
  isMandatory,
  withSettingsButton = true,
  withInlineHeader,
  style,
}) => {
  const { t } = useI18n();
  const { hashParams, setHashParam, backToBeforeFirstHash } = useHash();
  const settingsOpen = hashParams.settings === sectionPath;
  const pageTheme = usePageTheme();

  const onDialogClose = useCallback(() => {
    backToBeforeFirstHash();
    onSettingsClose?.();
  }, [backToBeforeFirstHash, onSettingsClose]);

  return (
    <DashedSectionBox padding={padding} style={style}>
      <Box
        positionAbsolute
        left={0}
        top={0}
        right={0}
        zIndex={2}
        flexRow
        alignCenter
        padding="0.2rem 0 0"
        style={{
          ...(withInlineHeader
            ? {
                position: 'relative',
                background: toRgba(pageTheme.textColor, 0.15),
                padding: 0,
                height: '4.8rem',
              }
            : {}),

          ...headerStyle,
        }}
      >
        {isSortable && (
          <div className={DRAG_HANDLE_CLASS} data-testid="dragHandle">
            <GripIcon size="2.8rem" />
          </div>
        )}
        {renderHeaderContent && renderHeaderContent()}
        {withSettingsButton && (
          <MoreIcon
            testId="settingsButton"
            onClick={() => setHashParam({ settings: sectionPath })}
            margin="0 0 0 auto"
            padding="1rem 0.5rem"
            opacity={0.9}
            direction="left"
            size="2.8rem"
          />
        )}
      </Box>
      {isShared ? (
        <ClickableModal text={t('itemEdit.editSharedComponentWarning')}>
          <div style={{ opacity: 0.5, pointerEvents: 'none' }}>{children}</div>
        </ClickableModal>
      ) : (
        children
      )}
      {settingsOpen && (
        <SettingsDialogBox
          title={settingsTitle}
          sectionPath={sectionPath}
          onClose={onDialogClose}
          renderContent={renderSettingsContent}
          renderHeader={renderSettingsHeader}
          isShared={isShared}
          isMandatory={isMandatory}
        />
      )}
      <style jsx>{`
        .dragHandle {
          cursor: grab;
          padding: 1rem 0.6rem;
          opacity: 0.5;
        }

        .dragHandle:hover {
          opacity: 1;
        }

        :active {
          cursor: grabbing;
        }
      `}</style>
    </DashedSectionBox>
  );
};

const SettingsDialogBox = ({
  onClose,
  renderContent,
  sectionPath,
  isShared,
  isMandatory,
  title,
  renderHeader,
}: {
  sectionPath: string;
  title?: string;
  onClose: () => void;
  renderContent?: DialogBoxProps['renderContent'];
  renderHeader?: DialogBoxProps['renderHeader'];
  isShared?: boolean;
  isMandatory?: boolean;
}) => {
  const { t } = useI18n();
  const apiRef = useRef<DialogBoxApi>(null);
  const close = () => apiRef.current?.close();
  const isLargeScreen = useIsLargeScreen();
  const { removeLayoutSection } = useEditActions();

  return (
    <DialogBox
      testId="settingsDialog"
      fillViewport={!isLargeScreen}
      apiRef={apiRef}
      onClose={onClose}
      renderHeader={
        renderHeader ??
        (() => (
          <DialogBoxHeader
            onCloseClick={close}
            title={title ?? t('itemEdit.labels.settings')}
            renderRight={({ textProps }) => (
              <Clickable onClick={close} testId="doneButton">
                <Text {...textProps}>{t('app.actions.done')}</Text>
              </Clickable>
            )}
          />
        ))
      }
      renderContent={useCallback(
        (params) => {
          const { paddingX, paddingY } = params;
          const content = renderContent ? renderContent(params) : null;

          return (
            <>
              <Box padding={`0.3rem ${paddingX} ${paddingY}`}>
                {!isShared ? (
                  content
                ) : (
                  <Card padding="1rem">
                    <Text isParagraph size="1.3rem" centered opacity={0.6}>
                      {t('itemEdit.editSharedComponentHelp')}
                    </Text>
                  </Card>
                )}
                {!isMandatory && (
                  <ConfirmButton
                    text={t('itemEdit.actions.removeComponent')}
                    height="4.5rem"
                    testId="removeButton"
                    margin={`${content ? FORM_SECTION_SPACING : 0} 0 0`}
                    onClick={async () => {
                      await close();

                      // if we remove the layout item too soon then
                      // the onClose callback is never run and the hash
                      // not updated causing odd behaviour
                      await wait(100);

                      removeLayoutSection({ layoutSectionPath: sectionPath });
                    }}
                  />
                )}
              </Box>
            </>
          );
        },
        [renderContent]
      )}
    />
  );
};
