import { lazy, Suspense, useMemo } from 'react';

import { transformIntegerInput } from '@composed-components/dynamic-forms/utils/extraUtils';
import { type FormTimePickerProps } from '@composed-components/TimePicker/types';
import { type CheckboxProps } from '@design-system/Checkbox/Checkbox';
import { type FormAutocompleteProps } from '@design-system/Inputs/Autocomplete/types';
import { type FormInputClassicProps } from '@design-system/Inputs/Classic/types';
import { type FormDatePickerProps } from '@design-system/Inputs/DatePicker/types';
import { type FormInputPhoneProps } from '@design-system/Inputs/Phone/types';
import Spinner from '@design-system/ProgressIndicators/Spinner';
import { type RadioButtonProps } from '@design-system/RadioButton/RadioButton';
import { type FormRatingProps } from '@design-system/Rating/types';
import Typography from '@mui/material/Typography';
import { type DateView } from '@mui/x-date-pickers';

import {
  type DynamicFormComponent,
  type DynamicFormInputType,
} from '../../types';

import InputFile, { type InputFileProps } from './InputFile';
import { type InputSignProps } from './InputSign';

const FormAutocomplete = lazy(
  () => import('@design-system/Inputs/Autocomplete/form'),
);
const FormDatePicker = lazy(
  () => import('@design-system/Inputs/DatePicker/form'),
);
const FormInputClassic = lazy(
  () => import('@design-system/Inputs/Classic/form'),
);
const FormInputPhone = lazy(() => import('@design-system/Inputs/Phone/form'));
const FormRating = lazy(() => import('@design-system/Rating/form'));
const FormTimePicker = lazy(
  () => import('@composed-components/TimePicker/form'),
);
const InputSelectableList = lazy(() => import('./InputSelectableList'));
const InputSign = lazy(() => import('./InputSign'));

const ComponentLoader = ({ children }: { children: React.ReactNode }) => {
  return <Suspense fallback={<Spinner />}>{children}</Suspense>;
};

const getDatePickerConfig = (pattern: string | undefined) => {
  if (pattern === 'MM/dd/yyyy') {
    return {
      views: ['year', 'month', 'day'] as DateView[],
      format: 'MM/dd/yyyy',
    };
  }
  if (pattern?.includes('dd')) {
    return {
      views: ['year', 'month', 'day'] as DateView[],
      format: 'dd/MM/yyyy',
    };
  }
  return {
    views: ['month', 'year'] as DateView[],
    format: 'MM/yyyy',
  };
};

export type FormInputProps = {
  name: string;
  component: DynamicFormComponent;
  isFrozen?: boolean;
  slotProps?: FormInputSlotProps;
};

export type FormInputSlotProps = {
  fields?: {
    AUTOCOMPLETE?: FormInputClassicProps['inputProps'];
    TEXT?: FormInputClassicProps['inputProps'];
    DATE?: FormDatePickerProps['inputProps'];
    TIME?: FormTimePickerProps['inputProps'];
    PHONE?: FormInputPhoneProps['inputProps'];
    SIGNATURE?: Omit<InputSignProps, 'name'>;
    INTEGER?: FormInputClassicProps['inputProps'];
    FLOAT?: FormInputClassicProps['inputProps'];
    DROPDOWN?: FormAutocompleteProps['autocompleteProps'];
    CHECKBOX?: RadioButtonProps;
    MULTIPLE_CHOICE?: CheckboxProps;
    RATING?: FormRatingProps['inputProps'];
    FILE?: Omit<InputFileProps, 'initialFiles' | 'name'>;
    STAR_RATING?: FormRatingProps['inputProps'];
  };
};

const FormInput = ({
  name,
  component,
  isFrozen,
  slotProps,
}: FormInputProps) => {
  const disabled = component.content.disabled;
  const disabledOrFrozen = disabled || isFrozen || false;

  const options = useMemo(() => {
    const inputsWithOptions: DynamicFormInputType[] = [
      'DROPDOWN',
      'MULTIPLE_CHOICE',
      'CHECKBOX',
      'RATING',
    ];

    if (
      'choices' in component.content &&
      inputsWithOptions.includes(component.type)
    ) {
      return component.content.choices?.map((choice, index) => ({
        id: index,
        label: choice,
        value: choice,
      }));
    }

    return [];
  }, [component.content, component.type]);

  const isMultipleSelect =
    component.type === 'RATING' || component.type === 'CHECKBOX';

  const RenderInput = useMemo(() => {
    switch (component.type) {
      case 'AUTOCOMPLETE':
        return (
          <ComponentLoader>
            <FormInputClassic
              name={name}
              inputProps={{
                disabled: disabledOrFrozen,
                autoComplete: 'off',
                autoCorrect: 'off',
                ...slotProps?.fields?.AUTOCOMPLETE,
              }}
            />
          </ComponentLoader>
        );
      case 'TEXT':
        return (
          <ComponentLoader>
            <FormInputClassic
              name={name}
              inputProps={{
                disabled: disabledOrFrozen,
                autoComplete: 'off',
                autoCorrect: 'off',
                ...slotProps?.fields?.TEXT,
              }}
            />
          </ComponentLoader>
        );
      case 'DATE': {
        const { views, format } = getDatePickerConfig(
          component.validations?.pattern,
        );

        return (
          <ComponentLoader>
            <FormDatePicker
              name={name}
              inputProps={{
                disabled: disabledOrFrozen,
                views,
                format,
                fullWidth: true,
                ...slotProps?.fields?.DATE,
              }}
            />
          </ComponentLoader>
        );
      }
      case 'TIME':
        return (
          <ComponentLoader>
            <FormTimePicker
              name={name}
              inputProps={{
                disabled: disabledOrFrozen,
                fullWidth: true,
                ...slotProps?.fields?.TIME,
              }}
            />
          </ComponentLoader>
        );
      case 'PHONE':
        return (
          <ComponentLoader>
            <FormInputPhone
              name={name}
              disabled={disabledOrFrozen}
              inputProps={{
                ...slotProps?.fields?.PHONE,
              }}
            />
          </ComponentLoader>
        );
      case 'SIGNATURE':
        return (
          <ComponentLoader>
            <InputSign
              name={name}
              disabled={disabledOrFrozen}
              {...slotProps?.fields?.SIGNATURE}
            />
          </ComponentLoader>
        );
      case 'INTEGER':
        return (
          <ComponentLoader>
            <FormInputClassic
              name={name}
              inputProps={{
                step: 1,
                disabled: disabledOrFrozen,
                inputMode: 'numeric',
                autoComplete: 'off',
                autoCorrect: 'off',
                hasCounter: false,
                transform: {
                  input: value => value?.replace(/[^0-9]/g, '') || '',
                },
                ...slotProps?.fields?.INTEGER,
              }}
            />
          </ComponentLoader>
        );
      case 'FLOAT':
        return (
          <ComponentLoader>
            <FormInputClassic
              name={name}
              inputProps={{
                disabled: disabledOrFrozen,
                step: 0.01,
                inputMode: 'decimal',
                autoComplete: 'off',
                autoCorrect: 'off',
                hasCounter: false,
                transform: {
                  input: transformIntegerInput,
                },
                ...slotProps?.fields?.FLOAT,
              }}
            />
          </ComponentLoader>
        );
      case 'DROPDOWN':
        return (
          <ComponentLoader>
            <FormAutocomplete
              name={name}
              options={options}
              disabled={disabledOrFrozen}
              // @ts-expect-error - This had to be added due to TypeScript limitations on complex types
              autocompleteProps={{
                disabled: disabledOrFrozen,
                multiple: isMultipleSelect,
                isServerFiltered: false,
                ...slotProps?.fields?.DROPDOWN,
              }}
            />
          </ComponentLoader>
        );
      case 'CHECKBOX':
        return (
          <ComponentLoader>
            <InputSelectableList
              name={name}
              options={options}
              disabled={disabledOrFrozen}
              isMultipleSelect={isMultipleSelect}
              fieldProps={slotProps?.fields?.CHECKBOX}
            />
          </ComponentLoader>
        );
      case 'MULTIPLE_CHOICE':
        return (
          <ComponentLoader>
            <InputSelectableList
              name={name}
              options={options}
              disabled={disabledOrFrozen}
              isMultipleSelect={isMultipleSelect}
              fieldProps={slotProps?.fields?.MULTIPLE_CHOICE}
            />
          </ComponentLoader>
        );
      case 'RATING':
        return (
          <ComponentLoader>
            <InputSelectableList
              name={name}
              options={options}
              disabled={disabledOrFrozen}
              isMultipleSelect={isMultipleSelect}
            />
          </ComponentLoader>
        );
      case 'STAR_RATING':
        return (
          <ComponentLoader>
            <FormRating
              name={name}
              inputProps={{
                disabled: disabledOrFrozen,
                ...slotProps?.fields?.STAR_RATING,
              }}
            />
          </ComponentLoader>
        );
      case 'FILE':
        return (
          <ComponentLoader>
            <InputFile
              initialFiles={component.answer || []}
              readOnly={isFrozen}
              name={name}
              disabled={disabled}
              uploadFn={slotProps?.fields?.FILE?.uploadFn}
              slotProps={{
                uploader: {
                  disabled,
                  sx: {
                    width: '100%',
                  },
                },
              }}
            />
          </ComponentLoader>
        );
      case 'INFO':
        return null;
      default:
        return null;
    }
  }, [component.type, name, disabled, options, isMultipleSelect, component]);

  return RenderInput;
};

export default FormInput;
