import { type FC, useEffect, useState } from 'react';
import { useFormContext } from 'react-hook-form';

import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';

import HuFormInputClassic from '@material-hu/components/design-system/Inputs/Classic/form';
import HuTooltip from '@material-hu/components/design-system/Tooltip';

import {
  InputType,
  type SectionComponent,
  type TextStyles,
} from 'src/pages/dashboard/serviceManagement/types';

import { usePdfCompletion } from '../../contexts/PdfFormCompletionProvider';
import { NUMBER_MAX_LENGTH, TEXT_MAX_LENGTH } from '../utils/constants';
import { getFieldContainerSxProps } from '../utils/utils';

import useFieldErrorMessages from './useFieldErrorMessages';
import useFocusField from './useFocusField';

const typographyOverflowSxProps = {
  textOverflow: 'ellipsis',
  overflow: 'hidden',
  maxWidth: '100%',
  maxHeight: '100%',
  whiteSpace: 'nowrap',
  lineHeight: 1,
};

type Props = {
  // Dimensions in pixels
  dimensions: {
    width: number;
    height: number;
  };
  field: SectionComponent;
  textStyles: TextStyles;
};

const TextField: FC<Props> = ({ dimensions, field, textStyles }) => {
  const { width, height } = dimensions;
  const {
    nameId: name,
    content: { title, required },
    type,
    validations,
  } = field;

  const theme = useTheme();
  const { showErrors } = usePdfCompletion();
  const { isFocused, handleFocus, removeFocus, id } = useFocusField();
  const { watch, trigger } = useFormContext();
  const answer = watch(name);
  // Track if the input has been blurred to show errors in the tooltip
  const [blurred, setBlurred] = useState(false);

  const { hasErrors, getTooltipProps } = useFieldErrorMessages({
    showErrors: showErrors || blurred,
    field,
    answer,
  });

  const dimensionSxProps = {
    width: `${width}px`,
    height: `${height}px`,
  };

  const hasAnswer = !(
    answer === undefined ||
    answer === null ||
    (typeof answer === 'string' && answer === '')
  );
  const isNumberInput = type === InputType.INTEGER || type === InputType.FLOAT;

  const transform = (raw: string) => {
    if (!isNumberInput) return raw;
    const str = String(raw ?? '');
    if (str === '') return str;
    // Keep digits and a single leading '-' only; handle one decimal point for floats
    let cleaned = str.replace(/[^\d.-]/g, '');
    const negative = cleaned.startsWith('-');
    cleaned = cleaned.replace(/-/g, '');
    cleaned = (negative ? '-' : '') + cleaned;
    if (type === InputType.INTEGER) {
      cleaned = cleaned.replace(/\./g, '');
    } else {
      const [intPart, ...rest] = cleaned.split('.');
      cleaned = intPart + (rest.length ? `.${rest.join('')}` : '');
    }
    return cleaned as string;
  };

  // biome-ignore lint/correctness/useExhaustiveDependencies: trigger is used to re-validate the field when the error source changes
  useEffect(() => {
    // Re-validate when error source changes so the input reflects error styles via rules
    trigger(name);
  }, [hasErrors, name, trigger]);

  // Input (focused)
  if (isFocused) {
    return (
      <HuTooltip
        {...getTooltipProps()}
        open={isFocused}
      >
        <span
          style={{
            width: dimensionSxProps.width,
            height: dimensionSxProps.height,
          }}
        >
          <HuFormInputClassic
            name={name}
            rules={{
              required: required,
              // Use hasErrors as the source of truth to drive error state via rules
              validate: () => !hasErrors,
            }}
            inputProps={{
              id,
              multiline: true,
              autoFocus: true,
              hasCounter: !!validations?.maxLength,
              maxLength: isNumberInput
                ? NUMBER_MAX_LENGTH
                : (validations?.maxLength ?? TEXT_MAX_LENGTH),
              type: isNumberInput ? 'number' : 'text',
              transform: { input: transform },
              onBlur: () => {
                setBlurred(true);
                removeFocus();
              },
              showClear: false,
              sx: {
                width: '100%',
                height: '100%',
                '& .MuiInputBase-root': {
                  padding: '2px',
                  borderRadius: theme.shape.borderRadiusS,
                  opacity: 0.8,
                  lineHeight: 1,
                  boxSizing: 'border-box',
                  backgroundColor: hasErrors
                    ? theme.palette.new.background.feedback.error
                    : theme.palette.new.background.layout.tertiary,
                },
                '& svg': {
                  width: `${textStyles.fontSize * 0.8}px`,
                  height: `${textStyles.fontSize * 0.8}px`,
                },
                '& .MuiInputAdornment-root': {
                  alignSelf: 'center',
                  gap: 0,
                  margin: 0,
                },
                '& textarea': {
                  ...textStyles,
                  color: `${textStyles.color} !important`,
                  width: '100%',
                  minHeight: '100% !important',
                  height: '100% !important',
                  padding: '0 !important',
                  whiteSpace: 'pre-wrap',
                  wordBreak: 'break-word',
                  overflowWrap: 'break-word',
                  boxSizing: 'border-box',
                  // Hide scrollbars but keep scrolling enabled
                  scrollbarWidth: 'none', // Firefox
                  msOverflowStyle: 'none', // IE and old Edge
                  '&::-webkit-scrollbar': {
                    display: 'none', // Chrome, Safari, new Edge
                  },
                },
                '& input[type=number]': {
                  MozAppearance: 'textfield',
                },
                '& input[type=number]::-webkit-outer-spin-button': {
                  WebkitAppearance: 'none',
                  margin: 0,
                },
                '& input[type=number]::-webkit-inner-spin-button': {
                  WebkitAppearance: 'none',
                  margin: 0,
                },
              },
            }}
          />
        </span>
      </HuTooltip>
    );
  }

  const containerSxProps = getFieldContainerSxProps(
    hasErrors,
    { width: dimensionSxProps.width, height: dimensionSxProps.height },
    theme,
  );

  const typographySxProps = {
    ...textStyles,
    ...typographyOverflowSxProps,
  };

  // Has answer and not focused
  if (hasAnswer) {
    return (
      <HuTooltip {...getTooltipProps()}>
        <Stack
          onClick={handleFocus}
          sx={{
            justifyContent: 'flex-start',
            backgroundColor: hasErrors
              ? theme.palette.new.background.feedback.error
              : theme.palette.new.background.layout.tertiary,
            ...containerSxProps,
          }}
        >
          <Typography
            sx={{
              ...typographySxProps,
              whiteSpace: 'pre-wrap',
              textOverflow: 'clip',
              wordBreak: 'break-word',
              width: 1,
              height: 1,
            }}
          >
            {answer}
          </Typography>
        </Stack>
      </HuTooltip>
    );
  }

  // No answer and not focused
  return (
    <HuTooltip {...getTooltipProps()}>
      <Stack
        onClick={handleFocus}
        sx={{
          flexDirection: 'row',
          alignItems: 'flex-start',
          gap: 0.5,
          backgroundColor: hasErrors
            ? theme.palette.new.background.feedback.error
            : theme.palette.new.background.layout.brand,
          ...containerSxProps,
        }}
      >
        <Typography sx={{ ...typographySxProps, typographyOverflowSxProps }}>
          {title}
        </Typography>
        {required && (
          <Typography
            sx={{ ...textStyles, color: theme.palette.new.text.feedback.error }}
          >
            *
          </Typography>
        )}
      </Stack>
    </HuTooltip>
  );
};

export default TextField;
