import { TextInput } from './TextInput';
import { LabeledInput, LabeledInputProps } from '@/components/ra-inputs/LabeledInput';
import { localizedValueHasAllLocales, localizedValueHasAtLeastOneLocale } from '@/utils';
import { Box, Chip, ListItemText, Menu, MenuItem, PopoverOrigin, Typography } from '@mui/material';
import _ from 'lodash';
import {
  ValidationError,
  ValidationErrorMessage,
  composeValidators,
  useInput,
  useLocaleState,
  useLocales
} from 'ra-core';
import { TextInputProps } from 'ra-ui-materialui';
import { ReactElement, useCallback, useMemo, useState } from 'react';
import { useWatch } from 'react-hook-form';

const ANCHOR_ORIGIN: PopoverOrigin = { vertical: 'bottom', horizontal: 'right' };
const TRANSFORM_ORIGIN: PopoverOrigin = { vertical: 'top', horizontal: 'right' };

type ILocalizedTextInputProps = TextInputProps &
  LabeledInputProps & {
    /**
     * Indicates if at least one locale is required.
     */
    requiredAtLeastOneLocale?: boolean;
    /**
     * Indicates the locale that is required.
     * If not provided, one of the locales will be required.
     */
    requiredLocale?: string;
  };

function LocalizedTextInput({
  requiredAtLeastOneLocale,
  requiredLocale,
  validate: _validate,
  required: _required,
  ...props
}: ILocalizedTextInputProps) {
  const { source } = props;
  const locales = useLocales();
  const required = useCallback(
    (requiredMessage = 'ra.validation.required', specificRequiredMessage = 'ra.validation.required_locale') => {
      return (value: any) => {
        if (requiredAtLeastOneLocale && !requiredLocale && !localizedValueHasAtLeastOneLocale(value, locales)) {
          return requiredMessage;
        } else if (requiredLocale && (!_.has(value, requiredLocale) || _.isEmpty(_.get(value, requiredLocale)))) {
          return { message: specificRequiredMessage, args: { locale: requiredLocale } };
        } else if (!requiredAtLeastOneLocale && _required && !localizedValueHasAllLocales(value, locales)) {
          return requiredMessage;
        }
        return undefined;
      };
    },
    [requiredAtLeastOneLocale, requiredLocale, locales, _required]
  );
  const validate = useMemo(() => {
    return composeValidators(_validate, required());
  }, [_validate, required]);
  const { fieldState } = useInput({ ...props, validate });
  const { error } = fieldState;
  const value = useWatch({ name: source });
  const isMissingLocalizations = !localizedValueHasAllLocales(value, locales);
  const [currentLocale] = useLocaleState();
  const [locale, setLocale] = useState(currentLocale);
  const [anchorEl, setAnchorEl] = useState<null | HTMLDivElement>(null);
  const open = Boolean(anchorEl);
  const toggle = useCallback(
    (e: React.MouseEvent<HTMLDivElement>) => setAnchorEl(open ? null : e.currentTarget),
    [open, setAnchorEl]
  );
  const handleClose = useCallback(() => setAnchorEl(null), [setAnchorEl]);

  const MenuItems: Array<ReactElement> = useMemo(() => {
    return _.map(locales, (l, index) => {
      return (
        <MenuItem
          key={index}
          onClick={() => {
            setLocale(l.locale);
            handleClose();
          }}
        >
          <ListItemText primary={`${l.locale.toUpperCase()}: ${(value ?? {})[l.locale] ?? ''}`} />
        </MenuItem>
      );
    });
  }, [locales, setLocale, handleClose, value]);
  return (
    <LabeledInput
      {...props}
      validate={validate}
      helperText={
        error?.message ? <ValidationError error={error?.message as ValidationErrorMessage} /> : props?.helperText
      }
    >
      <>
        <Box flex={1}>
          {_.map(locales, (l, index) => {
            return (
              <TextInput
                key={index}
                {...props}
                source={`${source}.${l.locale}`}
                sx={{ width: '100%', display: l.locale === locale ? 'inline-flex' : 'none' }}
                label={false}
                helperText={false}
                required={false}
                InputProps={{
                  endAdornment: (
                    <Chip
                      label={<Typography variant="button">{locale}</Typography>}
                      size="small"
                      onClick={toggle}
                      color={isMissingLocalizations ? 'warning' : undefined}
                    />
                  )
                }}
              />
            );
          })}
          <Menu
            anchorEl={anchorEl}
            open={open}
            anchorOrigin={ANCHOR_ORIGIN}
            transformOrigin={TRANSFORM_ORIGIN}
            onClose={handleClose}
          >
            {MenuItems}
          </Menu>
        </Box>
      </>
    </LabeledInput>
  );
}

export type { ILocalizedTextInputProps };
export { LocalizedTextInput };
