import { useCallback, useEffect, useMemo, useState } from 'react';
import { NumericFormat } from 'react-number-format';

import { IconArrowRight, IconCash } from '@material-hu/icons/tabler';
import Divider from '@material-hu/mui/Divider';
import InputAdornment from '@material-hu/mui/InputAdornment';
import Slider from '@material-hu/mui/Slider';
import Stack from '@material-hu/mui/Stack';
import { alpha } from '@material-hu/mui/styles';
import TextField from '@material-hu/mui/TextField';
import Typography from '@material-hu/mui/Typography';

import HuAlert from '@material-hu/components/design-system/Alert';
import HuCardContainer from '@material-hu/components/design-system/CardContainer';

import { type LokaliseTFunction, useLokaliseTranslation } from 'src/utils/i18n';

import {
  clampAmount,
  formatCurrencyInteger,
  getOfferExpirationInfo,
} from '../../utils/formatters';
import { microloanCardBorderSx } from '../cardSurfaceSx';

import { RequestOfferActions } from './RequestOfferActions';

function amountInputHelperText(
  parsedInputAmount: number | null,
  minBound: number,
  maxBound: number,
  t: LokaliseTFunction,
): string {
  if (parsedInputAmount === null) {
    return t('amount.invalid_amount');
  }
  if (parsedInputAmount < minBound) {
    return t('amount.amount_below_min', {
      min: formatCurrencyInteger(minBound),
    });
  }
  if (parsedInputAmount > maxBound) {
    return t('amount.amount_above_max', {
      max: formatCurrencyInteger(maxBound),
    });
  }
  return t('amount.whole_numbers_only');
}

export type AmountStepProps = {
  amountBounds: { min: number; max: number };
  selectedAmount: number;
  onAmountChange: (value: number) => void;
  onContinue: () => void;

  showContinueButton?: boolean;
  onValidityChange?: (isValid: boolean) => void;

  offerWindow?: { expiresAt?: string };
};

export const AmountStep = ({
  amountBounds,
  selectedAmount,
  onAmountChange,
  onContinue,
  showContinueButton = true,
  onValidityChange,
  offerWindow,
}: AmountStepProps) => {
  const { t } = useLokaliseTranslation('loans');
  const { min: minMxn, max: maxMxn } = amountBounds;
  const minBound = Math.ceil(minMxn);
  const maxBound = Math.floor(maxMxn);
  const [amountDraft, setAmountDraft] = useState(() => String(selectedAmount));
  const [isAmountInputFocused, setIsAmountInputFocused] = useState(false);

  useEffect(() => {
    if (isAmountInputFocused) {
      return;
    }
    const clamped = clampAmount(selectedAmount, minBound, maxBound);
    if (clamped !== selectedAmount) {
      onAmountChange(clamped);
    }
  }, [
    isAmountInputFocused,
    maxBound,
    minBound,
    onAmountChange,
    selectedAmount,
  ]);

  useEffect(() => {
    if (isAmountInputFocused) {
      return;
    }
    setAmountDraft(String(selectedAmount));
  }, [selectedAmount, isAmountInputFocused]);

  const parsedInputAmount = amountDraft.trim() ? Number(amountDraft) : null;
  const isAmountOutOfRange =
    parsedInputAmount !== null &&
    (parsedInputAmount < minBound || parsedInputAmount > maxBound);
  const isAmountValid =
    parsedInputAmount !== null &&
    parsedInputAmount >= minBound &&
    parsedInputAmount <= maxBound;

  const inputErrorText = amountInputHelperText(
    parsedInputAmount,
    minBound,
    maxBound,
    t,
  );

  useEffect(() => {
    onValidityChange?.(isAmountValid);
  }, [isAmountValid, onValidityChange]);

  const offerExpiryAlertTitle = useMemo(() => {
    const info = getOfferExpirationInfo(offerWindow?.expiresAt);
    if (!info) {
      return null;
    }
    if (info.kind === 'today') {
      return t('expiration.today');
    }
    if (info.kind === 'tomorrow') {
      return t('expiration.tomorrow');
    }
    return t('expiration.days_plural', { count: info.count });
  }, [offerWindow?.expiresAt, t]);

  const handleAmountInputValueChange = useCallback(
    ({ floatValue }: { floatValue: number | undefined }) => {
      if (!isAmountInputFocused) {
        return;
      }
      if (floatValue === undefined) {
        setAmountDraft('');
        return;
      }
      const next = Math.round(floatValue);
      setAmountDraft(String(next));
      if (next >= minBound && next <= maxBound) {
        onAmountChange(next);
      }
    },
    [isAmountInputFocused, maxBound, minBound, onAmountChange],
  );

  return (
    <Stack sx={{ gap: 4, width: '100%' }}>
      <Stack
        sx={{
          flexDirection: { xs: 'column', sm: 'row' },
          alignItems: { xs: 'stretch', sm: 'flex-start' },
          justifyContent: 'space-between',
          gap: 2,
          borderRadius: 3,
          p: 2.5,
          backgroundColor: theme =>
            theme.palette.new.action.button.background.primary.default,
          color: theme => theme.palette.new.action.button.text.primary.default,
          overflow: 'hidden',
          ...microloanCardBorderSx,
        }}
      >
        <Stack sx={{ gap: 1.25, flex: 1, minWidth: 0 }}>
          <Stack
            sx={{
              alignSelf: 'flex-start',
              px: 1.5,
              py: 0.5,
              borderRadius: 999,
              bgcolor: theme =>
                alpha(theme.palette.new.background.layout.default, 0.2),
            }}
          >
            <Typography
              variant="globalXXS"
              sx={{
                fontWeight: 'fontWeightSemiBold',
                color: theme =>
                  theme.palette.new.action.button.text.primary.default,
                letterSpacing: 0.3,
              }}
            >
              {t('title')}
            </Typography>
          </Stack>
          <Typography
            component="h2"
            variant="globalL"
            sx={{
              fontWeight: 'fontWeightBold',
              color: theme =>
                theme.palette.new.action.button.text.primary.default,
              lineHeight: 1.25,
            }}
          >
            {t('amount.title')}
          </Typography>
          <Typography
            variant="globalS"
            sx={{
              color: theme =>
                theme.palette.new.action.button.text.primary.default,
              opacity: 0.92,
            }}
          >
            {t('amount.max_available', {
              amount: formatCurrencyInteger(maxBound),
            })}
          </Typography>
        </Stack>
        <Stack
          sx={{
            alignSelf: 'center',
            alignItems: 'center',
            justifyContent: 'center',
            color: theme =>
              theme.palette.new.action.button.text.primary.default,
            opacity: 0.95,
          }}
          aria-hidden
        >
          <IconCash
            size={56}
            stroke={1.25}
          />
        </Stack>
      </Stack>

      <HuCardContainer
        fullWidth
        padding={0}
        sx={{ minWidth: 0 }}
      >
        <Stack sx={{ gap: 2, p: 2 }}>
          <Stack sx={{ gap: 1 }}>
            <Typography
              variant="globalS"
              sx={{
                fontWeight: 'fontWeightBold',
                color: theme => theme.palette.new.text.neutral.default,
              }}
            >
              {t('amount.input_label')}
            </Typography>
            <NumericFormat
              customInput={TextField}
              fullWidth
              variant="outlined"
              helperText={inputErrorText}
              value={amountDraft}
              thousandSeparator=","
              decimalScale={0}
              allowNegative={false}
              valueIsNumericString
              error={isAmountOutOfRange}
              onFocus={() => setIsAmountInputFocused(true)}
              onBlur={() => setIsAmountInputFocused(false)}
              onValueChange={handleAmountInputValueChange}
              inputProps={{
                'aria-valuemin': minBound,
                'aria-valuemax': maxBound,
                inputMode: 'numeric',
              }}
              InputProps={{
                startAdornment: (
                  <InputAdornment position="start">
                    <Typography
                      component="span"
                      variant="globalS"
                      sx={{
                        color: theme =>
                          isAmountOutOfRange
                            ? theme.palette.new.text.feedback.error
                            : theme.palette.new.text.neutral.default,
                      }}
                    >
                      $
                    </Typography>
                  </InputAdornment>
                ),
                endAdornment: (
                  <InputAdornment position="end">
                    <Typography
                      component="span"
                      variant="globalS"
                      sx={{
                        color: theme => theme.palette.new.text.neutral.lighter,
                      }}
                    >
                      MXN
                    </Typography>
                  </InputAdornment>
                ),
              }}
              sx={{
                '& .MuiInputBase-input': {
                  typography: 'globalS',
                  color: theme =>
                    isAmountOutOfRange
                      ? theme.palette.new.text.feedback.error
                      : theme.palette.new.text.neutral.default,
                },
                '& .MuiFormHelperText-root': {
                  typography: 'globalXS',
                  ml: 0,
                },
              }}
            />
          </Stack>

          <Stack sx={{ gap: 0.5, pt: 0.5 }}>
            <Slider
              value={clampAmount(selectedAmount, minBound, maxBound)}
              min={minBound}
              max={maxBound}
              step={1}
              onChange={(_, value) => {
                setIsAmountInputFocused(false);
                const next =
                  typeof value === 'number' ? value : (value[0] ?? minBound);
                onAmountChange(clampAmount(next, minBound, maxBound));
              }}
              sx={{
                mx: 0.5,
                '& .MuiSlider-thumb': {
                  width: 18,
                  height: 18,
                  backgroundColor: theme =>
                    theme.palette.new.background.layout.default,
                  border: theme =>
                    `2px solid ${theme.palette.new.border.neutral.brand}`,
                  boxShadow: 'none',
                  '&:hover, &.Mui-focusVisible': {
                    boxShadow: theme =>
                      `0 0 0 8px ${alpha(theme.palette.new.background.layout.brand, 0.18)}`,
                  },
                },
                '& .MuiSlider-track': {
                  border: 'none',
                  height: 6,
                  borderRadius: 999,
                  backgroundColor: theme =>
                    theme.palette.new.action.button.background.primary.default,
                },
                '& .MuiSlider-rail': {
                  height: 6,
                  borderRadius: 999,
                  opacity: 1,
                  backgroundColor: theme =>
                    theme.palette.new.background.elements.grey,
                },
              }}
            />
            <Stack
              sx={{ flexDirection: 'row', justifyContent: 'space-between' }}
            >
              <Typography
                variant="globalXS"
                sx={{ color: theme => theme.palette.new.text.neutral.lighter }}
              >
                {formatCurrencyInteger(minBound)}
              </Typography>
              <Typography
                variant="globalXS"
                sx={{ color: theme => theme.palette.new.text.neutral.lighter }}
              >
                {formatCurrencyInteger(maxBound)}
              </Typography>
            </Stack>
          </Stack>
        </Stack>

        {offerExpiryAlertTitle && (
          <>
            <Divider />
            <Stack sx={{ p: 2 }}>
              <HuAlert
                severity="info"
                title={offerExpiryAlertTitle}
              />
            </Stack>
          </>
        )}
      </HuCardContainer>

      {showContinueButton && (
        <RequestOfferActions
          layout="column"
          actions={[
            {
              label: t('continue'),
              variant: 'primary',
              fullWidth: true,
              disabled: !isAmountValid,
              onClick: onContinue,
              endIcon: (
                <IconArrowRight
                  size={18}
                  stroke={2}
                />
              ),
            },
          ]}
        />
      )}
    </Stack>
  );
};
