import {useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {ScrollView} from 'react-native-gesture-handler';
import {useMutation, useQueryClient} from '@tanstack/react-query';
import {IconCircleMinus, IconCirclePlus} from '@tabler/icons-react-native';
import {
  BottomModalFooter,
  InputClassic,
  InputSelect,
  InputTextArea,
  ListRow,
  Title,
  Typography,
} from '@components';
import {Order, OrderBy} from '@config/api';
import {useGoBack} from '@hooks/useGoBack';
import {Navigation} from '@interfaces/navigation';
import {DecimalSeparator} from '@interfaces/numeric';
import {adjustUserBalance} from '@modules/timeOff/services';
import {EventOperation, Unit} from '@modules/timeOff/interfaces';
import Message from '@modules/timeOff/components/Message';
import {TIME_OFF_QUERY_KEYS} from '@modules/timeOff/constants';
import {getTimeUnitKey} from '@modules/timeOff/utils';
import {
  useGetPolicyTypeCycles,
  useTimeOffPanelStyle,
} from '@modules/timeOff/hooks';
import {showSnackbar} from '@redux/dispatchers';
import {
  capitalize,
  getCompleteName,
  getDate,
  roundDecimals,
} from '@shared/utils';
import {Screens} from '@shared/constants';
import {useTheme} from '@shared/theme';
import {COMMA_REGEX} from '@shared/regexs';

import {styles} from './styles';

const ADJUSTMENT_TYPE_SNAP_POINTS = ['25%'];

function BalanceAdjustment({
  route: {
    params: {
      amountRequested,
      currentBalance,
      policyName,
      policyTypeId,
      policyTypeName,
      policyTypeUnit,
      user,
    },
  },
  navigation,
}: Navigation<Screens.BALANCE_ADJUSTMENT>) {
  const {theme} = useTheme();
  const panelStyle = useTimeOffPanelStyle();
  const {t} = useTranslation();
  const queryClient = useQueryClient();
  const {goBack} = useGoBack();
  const [adjustmentType, setAdjustmentType] = useState<EventOperation>();
  const [daysQuantity, setDaysQuantity] = useState('');
  const [description, setDescription] = useState('');
  const [finalAmount, setFinalAmount] = useState<number>();
  const [selectedCycleId, setSelectedCycleId] = useState<number>();
  const currentAmount = currentBalance ?? amountRequested;
  const showMessage = finalAmount !== undefined;
  const isHoursUnit = policyTypeUnit === Unit.Hours;
  const timeUnitKey = getTimeUnitKey(policyTypeUnit, false);
  const timeUnitCapitalized = capitalize(t(timeUnitKey, {count: 2}));

  const {policyTypeCycles, isLoadingPolicyTypeCycles, getNextPolicyTypeCycles} =
    useGetPolicyTypeCycles({
      policyTypeId,
      userId: user.id,
      onlyPositiveBalance: false,
      expired: false,
      order: Order.DESC,
      orderBy: OrderBy.START_DATE,
    });

  const adjustmentOptions = [
    {
      id: EventOperation.ADDITION,
      label: t('time_off.add'),
      AvatarProps: {Icon: IconCirclePlus},
    },
    {
      id: EventOperation.SUBTRACTION,
      label: t('general.subtract'),
      AvatarProps: {Icon: IconCircleMinus},
    },
  ];

  useEffect(() => {
    navigation.setOptions({
      title: t(
        `time_off.${
          currentBalance === null
            ? 'time_used_adjustment'
            : 'time_available_adjustment'
        }`,
      ),
    });
  }, [currentBalance, navigation, t]);

  useEffect(() => {
    const numberDaysQuantity = daysQuantity ? Number(daysQuantity) : 0;
    if (adjustmentType && numberDaysQuantity > 0) {
      const amount =
        adjustmentType === EventOperation.ADDITION
          ? currentAmount + numberDaysQuantity
          : currentAmount - numberDaysQuantity;
      setFinalAmount(roundDecimals(amount, 4));
    } else {
      setFinalAmount(undefined);
    }
  }, [adjustmentType, currentAmount, daysQuantity]);

  const cycleId = useMemo(() => {
    let balanceCycle;
    if (adjustmentType && policyTypeCycles.length > 0) {
      if (adjustmentType === EventOperation.ADDITION) {
        balanceCycle = policyTypeCycles.find(
          cycle => cycle.isDefaultForAddition,
        );
      } else if (adjustmentType === EventOperation.SUBTRACTION) {
        balanceCycle = policyTypeCycles.find(
          cycle => cycle.isDefaultForSubtraction,
        );
      }
    }

    if (balanceCycle) {
      return balanceCycle.id;
    } else {
      return undefined;
    }
  }, [adjustmentType, policyTypeCycles]);

  const {mutate: onAdjustBalance, isPending} = useMutation({
    mutationFn: adjustUserBalance,
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: TIME_OFF_QUERY_KEYS.balanceReport,
      });
      queryClient.invalidateQueries({
        queryKey: TIME_OFF_QUERY_KEYS.policyType(policyTypeId, user.id),
      });
      goBack();
      showSnackbar({title: t('time_off.adjustment_applied_successfully')});
    },
  });

  const onApplyPress = () => {
    onAdjustBalance({
      policyTypeId,
      userId: user.id,
      amount: Number(daysQuantity),
      operation: adjustmentType!,
      observations: description || undefined,
      cycleId: selectedCycleId || cycleId,
    });
  };

  const onChangeAdjustBalance = (amount: string) => {
    setDaysQuantity(amount.replace(COMMA_REGEX, DecimalSeparator.PERIOD));
  };

  const cyclesOptions = useMemo(
    () =>
      policyTypeCycles.map(cycle => ({
        id: cycle.id,
        label: `${getDate(cycle.fromDate)} - ${getDate(cycle.toDate)}`,
      })),
    [policyTypeCycles],
  );

  return (
    <>
      <ScrollView
        bounces={false}
        contentContainerStyle={styles.contentContainer}
        showsVerticalScrollIndicator={false}
        style={{backgroundColor: theme.background.layout.default}}>
        <View style={panelStyle}>
          <View style={styles.collaboratorContainer}>
            <Typography color={theme.text.neutral.lighter} variant="xxs">
              {t('time_off.employee')}
            </Typography>
            <ListRow>
              <ListRow.Avatar url={user.profilePicture} name={user} size="md" />
              <ListRow.Title title={getCompleteName(user)} />
            </ListRow>
          </View>
        </View>
        <View style={panelStyle}>
          <Title
            title={policyTypeName}
            titleNumberOfLines={2}
            topText={t('time_off.policy_type', {count: 1})}
            size="s"
          />
        </View>
        {!!policyName && (
          <View style={panelStyle}>
            <Title
              title={policyName}
              titleNumberOfLines={2}
              topText={t('time_off.policy')}
              size="s"
            />
          </View>
        )}
        <View style={panelStyle}>
          <Title
            title={timeUnitCapitalized}
            topText={t('time_off.time_unit')}
            size="s"
          />
        </View>
        <View style={panelStyle}>
          <View style={styles.adjustmentSection}>
            <Typography color={theme.text.neutral.lighter} variant="xxs">
              {t('time_off.adjustment_type')}
            </Typography>
            <View style={styles.adjustmentFields}>
              <InputSelect
                menuTitle={t('time_off.adjustment_type')}
                onChange={setAdjustmentType}
                options={adjustmentOptions}
                placeholder={t('time_off.adjustment_type')}
                showAvatarInCollapsedInput={false}
                snapPoints={ADJUSTMENT_TYPE_SNAP_POINTS}
                value={adjustmentType}
              />
              <InputClassic
                helper={t(
                  isHoursUnit
                    ? 'time_off.balance_adjustment_helper_hour'
                    : 'time_off.balance_adjustment_helper',
                )}
                keyboardType="numeric"
                maxLength={6}
                onChangeText={onChangeAdjustBalance}
                placeholder={timeUnitCapitalized!}
                value={daysQuantity}
              />
            </View>
          </View>
        </View>
        <View style={panelStyle}>
          <InputSelect
            label={t('time_off.cycle')}
            onChange={setSelectedCycleId}
            options={cyclesOptions}
            placeholder={t('time_off.select_cycle')}
            helper={t('time_off.select_cycle_helper_text')}
            value={selectedCycleId || cycleId}
            disabled={isLoadingPolicyTypeCycles}
            onEndReached={getNextPolicyTypeCycles}
          />
        </View>
        <View style={panelStyle}>
          <InputTextArea
            showCounter
            label={t('time_off.observations')}
            onChangeText={setDescription}
            placeholder={t('time_off.enter_description')}
            value={description}
            showFooterMessage
          />
        </View>
        {showMessage && (
          <View style={panelStyle}>
            <Message
              messages={[
                t(
                  adjustmentType === EventOperation.ADDITION
                    ? isHoursUnit
                      ? 'time_off.adding_hour'
                      : 'time_off.adding_day'
                    : isHoursUnit
                    ? 'time_off.subtracting_hour'
                    : 'time_off.subtracting_day',
                  {count: Number(daysQuantity)},
                ),
                t(
                  currentBalance
                    ? isHoursUnit
                      ? 'time_off.final_balance_hour'
                      : 'time_off.final_balance_day'
                    : isHoursUnit
                    ? 'time_off.final_time_used_hour'
                    : 'time_off.final_time_used_day',
                  {count: finalAmount},
                ),
              ]}
            />
          </View>
        )}
      </ScrollView>
      <BottomModalFooter
        footer={{
          primaryButton: {
            disabled: !adjustmentType || !showMessage,
            isLoading: isPending,
            onPress: onApplyPress,
            text: t('time_off.apply'),
          },
        }}
      />
    </>
  );
}

export default BalanceAdjustment;
