import {
  type ReactNode,
  useState,
  useRef,
  useEffect,
  useCallback,
} from 'react';
import { Controller, useFormContext } from 'react-hook-form';

import Stack from '@material-hu/mui/Stack';

import { type SxProps } from '@material-hu/mui/styles';

import Dropdown from '@material-hu/components/design-system/Dropdown';
import List from '@material-hu/components/design-system/List';
import ListItem from '@material-hu/components/design-system/List/components/ListItem';
import Tooltip from '@material-hu/components/design-system/Tooltip';

type FormDropdownProps = {
  name: string;
  options?: { label: string; value: string }[];
  placeholder: string;
  sx?: SxProps;
  disabled?: boolean;
  children?:
    | ReactNode
    | ((
        anchorEl: HTMLElement | null,
        onClose: () => void,
        keepOpen: () => void,
      ) => ReactNode);
  onOptionSelect?: (value: string) => boolean | void;
  customLabel?: string;
  onOpen?: () => void;
  required?: boolean;
};

const FormDropdown = ({
  name,
  options,
  placeholder,
  sx,
  disabled,
  children,
  onOptionSelect,
  customLabel,
  onOpen: onOpenProp,
  required,
}: FormDropdownProps) => {
  const { control, watch } = useFormContext();
  const fieldValue = watch(name);
  const [open, setOpen] = useState(false);
  const [isTruncated, setIsTruncated] = useState(false);
  const buttonRef = useRef<HTMLElement | null>(null);
  const containerRef = useRef<HTMLDivElement | null>(null);
  const textRef = useRef<HTMLSpanElement | null>(null);

  const checkTruncation = useCallback(() => {
    setTimeout(() => {
      if (textRef.current) {
        setIsTruncated(
          textRef.current.scrollWidth > textRef.current.clientWidth,
        );
      }
    }, 0);
  }, []);

  useEffect(() => {
    checkTruncation();
    window.addEventListener('resize', checkTruncation);
    return () => window.removeEventListener('resize', checkTruncation);
  }, [checkTruncation, fieldValue, customLabel]);

  const handleOpen = () => {
    setOpen(true);
    onOpenProp?.();
  };

  const handleClose = () => {
    setOpen(false);
  };

  const keepOpen = () => {
    setOpen(true);
  };

  const setupButtonRef = (ref: HTMLDivElement | null) => {
    if (ref) {
      const button = ref.querySelector('button');
      if (button) {
        buttonRef.current = button;
      }
    }
  };

  return (
    <Controller
      control={control}
      name={name}
      rules={{ required }}
      render={({ field, fieldState: { error } }) => {
        const selectedOption = options?.find(
          option => option.value === field.value,
        );
        const displayLabel =
          customLabel ?? (selectedOption?.label || placeholder);
        return (
          <Tooltip
            title={displayLabel}
            direction="top"
            disableTooltip={!isTruncated}
          >
            <Stack
              ref={ref => {
                containerRef.current = ref;
                setupButtonRef(ref);
              }}
              sx={{
                flex: 1,
                width: '100%',
                minWidth: 0,
                position: 'relative',
                ...sx,
              }}
            >
              <Dropdown
                open={open}
                onClose={handleClose}
                onOpen={handleOpen}
                label={
                  <span
                    ref={textRef}
                    style={{
                      display: 'block',
                      overflow: 'hidden',
                      textOverflow: 'ellipsis',
                      whiteSpace: 'nowrap',
                    }}
                  >
                    {displayLabel}
                  </span>
                }
                buttonProps={{
                  variant: 'secondary',
                  disabled: disabled,
                  size: 'small',
                  sx: {
                    height: '36px',
                    minWidth: '100px',
                    maxWidth: '100%',
                    backgroundColor: theme =>
                      theme.palette.new.background.layout.tertiary,
                    borderColor: theme =>
                      error ? theme.palette.error.main : undefined,
                    flex: 1,
                  },
                }}
              >
                {typeof children === 'function' &&
                  children(buttonRef.current, handleClose, keepOpen)}
                {typeof children !== 'function' &&
                  (children || (
                    <List>
                      {options?.map(option => (
                        <ListItem
                          key={option.value}
                          onClick={() => {
                            field.onChange(option.value);
                            const shouldKeepOpen = onOptionSelect?.(
                              option.value,
                            );
                            if (!shouldKeepOpen) {
                              handleClose();
                            }
                          }}
                          text={{
                            title: option.label,
                          }}
                        />
                      ))}
                    </List>
                  ))}
              </Dropdown>
            </Stack>
          </Tooltip>
        );
      }}
    />
  );
};

export default FormDropdown;
