import React, { ChangeEvent, forwardRef, useState } from 'react';
import { Box, Text, ThemeColorType } from '@nova-hf/ui';

export type TextInputProps = {
  required?: boolean;
  id: string;
  name: string;
  autoComplete?: AutoCompleteValues;
  value?: string;
  disabled?: boolean;
  backgroundColor?: ThemeColorType;
  textColor?: ThemeColorType;
  isLabeled?: boolean;
  onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
} & React.InputHTMLAttributes<HTMLInputElement>;

const AutoCompleteMapper: Partial<
  Record<
    AutoCompleteValues,
    {
      autoComplete?: AutoCompleteValues;
      format?: string;
    }
  >
> = {
  'cc-number': {
    autoComplete: 'cc-number',
    format: '#### #### #### ####',
  },
  cvc: {
    format: '####',
  },
  'cc-exp': {
    autoComplete: 'cc-exp',
    format: '##/##',
  },
  'national-id': {
    format: '######-####',
  },
  email: {
    autoComplete: 'email',
  },
  tel: {
    autoComplete: 'tel',
    format: '###-####',
  },
};

const formatValue = (value: string, format?: string) => {
  if (!format) return value;
  const digits = value.replace(/\D/g, ''); // Remove non-numeric characters
  let formattedValue = '';
  let digitIndex = 0;

  for (const char of format) {
    if (char === '#' && digitIndex < digits.length) {
      formattedValue += digits[digitIndex];
      digitIndex++;
    } else if (char !== '#' && digitIndex < digits.length) {
      formattedValue += char;
    }
  }
  return formattedValue;
};

const TextInput = forwardRef((props: TextInputProps, ref?: React.Ref<HTMLInputElement>) => {
  const {
    id,
    name,
    autoComplete,
    disabled,
    backgroundColor = 'grey100',
    required,
    onChange,
    onBlur,
    defaultValue = '',
    placeholder,
    textColor = 'grey700',
    isLabeled,
    value,
    onKeyDown,
  } = props;
  const [rawValue, setRawValue] = useState(defaultValue);

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    const isNumericField = autoComplete && AutoCompleteMapper[autoComplete]?.format;
    const newRawValue = isNumericField ? e.target.value.replace(/\D/g, '') : e.target.value;

    setRawValue(newRawValue);
    if (onChange) onChange({ ...e, target: { ...e.target, value: newRawValue } });
  };

  const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
    if (onBlur) onBlur(e);
  };

  const formatPlaceholder = required ? `*${placeholder}` : placeholder;
  return (
    <Box display="flex" width="100%" flexDirection="column" gap={1}>
      {isLabeled && (
        <Box marginLeft={1}>
          <Text color={textColor} variant="pSmallBold" marginBottom={1}>
            {name}
          </Text>
        </Box>
      )}
      <Box
        aria-label={`Text input for ${id} or ${name}`}
        id={id}
        name={name}
        renderAs="input"
        autoComplete={autoComplete}
        onBlur={handleBlur}
        ref={ref}
        {...(required && { 'aria-required': true })}
        onChange={handleChange}
        onKeyDown={onKeyDown}
        width="100%"
        disabled={disabled}
        paddingX={2}
        paddingY={2}
        color={textColor}
        value={
          value
            ? formatValue(
                value.toString(),
                autoComplete ? AutoCompleteMapper[autoComplete]?.format : undefined,
              )
            : rawValue
            ? formatValue(
                rawValue.toString(),
                autoComplete ? AutoCompleteMapper[autoComplete]?.format : undefined,
              )
            : ''
        }
        placeholder={formatPlaceholder}
        display="flex"
        justifyContent="center"
        backgroundColor={backgroundColor}
        borderColor={{ focus: 'attention' }}
        style={{
          fontFamily: 'Poppins',
          fontSize: 16,
          fontWeight: '400',
          lineHeight: 'medium',
          textTransform: 'none',
          borderRadius: '16px',
          border: 'none',
        }}
      />
    </Box>
  );
});

export default TextInput;

export type AutoCompleteValues =
  | 'off'
  | 'on'
  | 'name'
  | 'national-id'
  | 'honorific-prefix'
  | 'given-name'
  | 'additional-name'
  | 'family-name'
  | 'honorific-suffix'
  | 'nickname'
  | 'email'
  | 'username'
  | 'new-password'
  | 'current-password'
  | 'one-time-code'
  | 'organization-title'
  | 'organization'
  | 'street-address'
  | 'address-line1'
  | 'address-line2'
  | 'address-line3'
  | 'address-level4'
  | 'address-level3'
  | 'address-level2'
  | 'address-level1'
  | 'country'
  | 'country-name'
  | 'postal-code'
  | 'cc-name'
  | 'cc-given-name'
  | 'cc-additional-name'
  | 'cc-family-name'
  | 'cc-number'
  | 'cc-exp'
  | 'cc-exp-month'
  | 'cc-exp-year'
  | 'cc-csc'
  | 'cc-type'
  | 'cvc'
  | 'transaction-currency'
  | 'transaction-amount'
  | 'language'
  | 'bday'
  | 'bday-day'
  | 'bday-month'
  | 'bday-year'
  | 'sex'
  | 'tel'
  | 'tel-country-code'
  | 'tel-national'
  | 'tel-area-code'
  | 'tel-local'
  | 'tel-extension'
  | 'impp'
  | 'url'
  | 'photo';
