import React, { useRef, useCallback, useReducer, useEffect, FC } from 'react';
import { View, Text, TouchableOpacity, TextInput, StyleSheet, Keyboard, ScrollView, KeyboardAvoidingView, Platform } from 'react-native';
import { useTheme } from '../components/themes';
import loc, { formatBalance } from '../loc';
import { BitcoinUnit } from '../models/bitcoinUnits';
import { RouteProp, useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { SendDetailsStackParamList } from '../navigation/SendDetailsStackParamList';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { NetworkTransactionFeeType } from '../models/networkTransactionFees';

enum FeeScreenActions {
  SET_CUSTOM_FEE_VALUE = 'SET_CUSTOM_FEE_VALUE',
  SET_CUSTOM_FEE_FOCUSED = 'SET_CUSTOM_FEE_FOCUSED',
  SET_CUSTOM_FEE_BLURRED = 'SET_CUSTOM_FEE_BLURRED',
  CLEAR_CUSTOM_FEE = 'CLEAR_CUSTOM_FEE',
  SET_OPTIONS = 'SET_OPTIONS',
}

interface FeeOption {
  label: string;
  time: string;
  fee: number | null;
  rate: number;
  feeType: NetworkTransactionFeeType;
  active: boolean;
  disabled?: boolean;
}

interface FeeScreenState {
  customFeeValue: string;
  isCustomFeeFocused: boolean;
  options: FeeOption[];
  isCustomFeeSelected: boolean;
}

type FeeScreenAction =
  | { type: FeeScreenActions.SET_CUSTOM_FEE_VALUE; payload: string }
  | { type: FeeScreenActions.SET_CUSTOM_FEE_FOCUSED }
  | { type: FeeScreenActions.SET_CUSTOM_FEE_BLURRED }
  | { type: FeeScreenActions.CLEAR_CUSTOM_FEE }
  | { type: FeeScreenActions.SET_OPTIONS; payload: { options: FeeOption[]; currentFeeRate: number } };

const feeScreenReducer = (state: FeeScreenState, action: FeeScreenAction): FeeScreenState => {
  switch (action.type) {
    case FeeScreenActions.SET_CUSTOM_FEE_VALUE:
      return { ...state, customFeeValue: action.payload };
    case FeeScreenActions.SET_CUSTOM_FEE_FOCUSED:
      return {
        ...state,
        isCustomFeeFocused: true,
        isCustomFeeSelected: true,
        options: state.options.map(opt => ({ ...opt, active: false })),
      };
    case FeeScreenActions.SET_CUSTOM_FEE_BLURRED:
      return { ...state, isCustomFeeFocused: false };
    case FeeScreenActions.CLEAR_CUSTOM_FEE:
      return { ...state, customFeeValue: '' };
    case FeeScreenActions.SET_OPTIONS: {
      const { options, currentFeeRate } = action.payload;
      const matchesPresetOption = options.some(option => currentFeeRate === option.rate);
      const updatedOptions = options.map(option => ({
        ...option,
        active: !state.isCustomFeeFocused && currentFeeRate === option.rate,
      }));
      return {
        ...state,
        options: updatedOptions,
        isCustomFeeSelected: state.isCustomFeeFocused || !matchesPresetOption,
      };
    }
    default:
      return state;
  }
};

interface FeeOptionProps {
  label: string;
  time: string;
  fee: number | null;
  rate: number;
  active: boolean;
  disabled?: boolean;
  onPress: () => void;
  formatFee: (fee: number) => string;
  colors: any;
}

const FeeOption: FC<FeeOptionProps> = ({ label, time, fee, rate, active, disabled, onPress, formatFee, colors }) => {
  const stylesHook = StyleSheet.create({
    feeModalItemActiveBackground: {
      backgroundColor: colors.feeActive,
    },
    feeOptionText: {
      color: colors.successColor,
    },
    feeOptionTextDisabled: {
      color: colors.buttonDisabledTextColor,
    },
    feeTimeBackground: {
      backgroundColor: colors.successColor,
    },
    feeTimeBackgroundDisabled: {
      backgroundColor: colors.buttonDisabledBackgroundColor,
    },
    feeTimeText: {
      color: colors.background,
    },
  });

  return (
    <TouchableOpacity
      accessibilityRole="button"
      disabled={disabled}
      onPress={onPress}
      style={[styles.feeModalItem, active && styles.feeModalItemActive, active && !disabled && stylesHook.feeModalItemActiveBackground]}
    >
      <View style={styles.feeModalRow}>
        <Text style={[styles.feeModalLabel, disabled ? stylesHook.feeOptionTextDisabled : stylesHook.feeOptionText]}>{label}</Text>
        <View style={[styles.feeModalTime, disabled ? stylesHook.feeTimeBackgroundDisabled : stylesHook.feeTimeBackground]}>
          <Text style={stylesHook.feeTimeText}>~{time}</Text>
        </View>
      </View>
      <View style={styles.feeModalRow}>
        <Text style={disabled ? stylesHook.feeOptionTextDisabled : stylesHook.feeOptionText}>{fee && formatFee(fee)}</Text>
        <Text style={disabled ? stylesHook.feeOptionTextDisabled : stylesHook.feeOptionText}>
          {rate} {loc.units.sat_vbyte}
        </Text>
      </View>
    </TouchableOpacity>
  );
};

type SelectFeeScreenNavigationProp = NativeStackNavigationProp<SendDetailsStackParamList, 'SelectFee'>;
type SelectFeeScreenRouteProp = RouteProp<SendDetailsStackParamList, 'SelectFee'>;

const SelectFeeScreen = () => {
  const navigation = useNavigation<SelectFeeScreenNavigationProp>();
  const route = useRoute<SelectFeeScreenRouteProp>();
  const { colors } = useTheme();
  const insets = useSafeAreaInsets();

  const { networkTransactionFees, feePrecalc, feeRate, feeUnit = BitcoinUnit.BTC, walletID, customFee } = route.params;

  const [state, dispatch] = useReducer(feeScreenReducer, {
    customFeeValue: customFee || '',
    isCustomFeeFocused: false,
    options: [],
    isCustomFeeSelected: false,
  });

  const customFeeInputRef = useRef<TextInput>(null);
  const nf = networkTransactionFees;

  const stylesHook = StyleSheet.create({
    keyboardAvoidingRoot: {
      backgroundColor: colors.elevated,
    },
    scrollView: {
      backgroundColor: colors.elevated,
    },
    container: {
      backgroundColor: colors.elevated,
      paddingHorizontal: 16,
      paddingTop: 12,
      paddingBottom: Math.max(insets.bottom, 48) + 16,
    },
    feeModalItemActiveBackground: {
      backgroundColor: colors.feeActive,
    },
    customLabelColor: {
      color: colors.successColor,
    },
    satVbyteText: {
      color: colors.successColor,
    },
    customFeeInputColors: {
      color: colors.successColor,
      borderColor: colors.formBorder,
    },
    feeTimeBackground: {
      backgroundColor: colors.successColor,
    },
    feeTimeBackgroundDisabled: {
      backgroundColor: colors.buttonDisabledBackgroundColor,
    },
    feeTimeText: {
      color: colors.background,
    },
  });

  const formatFee = useCallback((fee: number) => formatBalance(fee, feeUnit, true), [feeUnit]);

  useEffect(() => {
    const options: FeeOption[] = [
      {
        label: loc.send.fee_fast,
        time: loc.send.fee_10m,
        fee: feePrecalc.fastestFee,
        rate: nf.fastestFee,
        feeType: NetworkTransactionFeeType.FAST,
        active: false,
      },
      {
        label: loc.send.fee_medium,
        time: loc.send.fee_3h,
        fee: feePrecalc.mediumFee,
        rate: nf.mediumFee,
        feeType: NetworkTransactionFeeType.MEDIUM,
        active: false,
        disabled: nf.mediumFee === nf.fastestFee,
      },
      {
        label: loc.send.fee_slow,
        time: loc.send.fee_1d,
        fee: feePrecalc.slowFee,
        rate: nf.slowFee,
        feeType: NetworkTransactionFeeType.SLOW,
        active: false,
        disabled: nf.slowFee === nf.mediumFee || nf.slowFee === nf.fastestFee,
      },
    ];
    dispatch({ type: FeeScreenActions.SET_OPTIONS, payload: { options, currentFeeRate: Number(feeRate) } });
  }, [feePrecalc, nf, feeRate]);

  const navigateWithFee = useCallback(
    (feeRateValue: string, feeType: NetworkTransactionFeeType) => {
      navigation.popTo('SendDetails', { walletID, selectedFeeRate: feeRateValue, selectedFeeType: feeType }, { merge: true });
    },
    [navigation, walletID],
  );

  const handleFeeOptionPress = useCallback(
    (rate: number, feeType: NetworkTransactionFeeType) => {
      navigateWithFee(rate.toString(), feeType);
    },
    [navigateWithFee],
  );

  const handleCustomFeeChange = useCallback((value: string) => {
    const cleanValue = value.replace(/[^\d.,]/g, '').replace(/([.,].*?)[.,]/g, '$1');
    dispatch({ type: FeeScreenActions.SET_CUSTOM_FEE_VALUE, payload: cleanValue });
  }, []);

  const handleCustomFeeSubmit = useCallback(() => {
    const numericValue = state.customFeeValue.replace(',', '.');
    if (numericValue && Number(numericValue) >= 0) {
      navigateWithFee(numericValue, NetworkTransactionFeeType.CUSTOM);
    }
  }, [state.customFeeValue, navigateWithFee]);

  const handleCustomFeeBlur = useCallback(() => {
    dispatch({ type: FeeScreenActions.SET_CUSTOM_FEE_BLURRED });
    const numericValue = Number(state.customFeeValue.replace(',', '.'));
    if (!state.customFeeValue || numericValue < 0) {
      dispatch({ type: FeeScreenActions.CLEAR_CUSTOM_FEE });
    }
  }, [state.customFeeValue]);

  const handleCustomFocus = useCallback(() => dispatch({ type: FeeScreenActions.SET_CUSTOM_FEE_FOCUSED }), []);
  const handleCustomPress = useCallback(() => {
    customFeeInputRef.current?.focus();
  }, []);

  useFocusEffect(
    useCallback(() => {
      return () => {
        Keyboard.dismiss();
      };
    }, []),
  );

  return (
    <KeyboardAvoidingView
      style={[styles.keyboardAvoidingRoot, stylesHook.keyboardAvoidingRoot]}
      behavior={Platform.OS === 'ios' ? 'padding' : undefined}
    >
      <View style={[styles.keyboardAvoidingRoot, stylesHook.keyboardAvoidingRoot]}>
        <ScrollView
          style={[styles.scrollView, stylesHook.scrollView]}
          contentContainerStyle={[stylesHook.container, styles.screenContainer]}
          keyboardShouldPersistTaps="handled"
          keyboardDismissMode="on-drag"
          contentInsetAdjustmentBehavior="never"
          showsVerticalScrollIndicator={false}
        >
          <View style={styles.contentContainer}>
            {state.options.map(({ label, time, fee, rate, active, disabled, feeType }) => (
              <FeeOption
                key={label}
                label={label}
                time={time}
                fee={fee}
                rate={rate}
                active={active}
                disabled={disabled}
                onPress={() => handleFeeOptionPress(rate, feeType)}
                formatFee={formatFee}
                colors={colors}
              />
            ))}
            <TouchableOpacity
              accessibilityRole="button"
              testID="feeCustomContainerButton"
              onPress={handleCustomPress}
              style={[
                styles.feeModalItem,
                styles.customFeeButton,
                state.isCustomFeeSelected && styles.feeModalItemActive,
                state.isCustomFeeSelected && stylesHook.feeModalItemActiveBackground,
              ]}
            >
              <View style={styles.feeModalRow}>
                <Text style={[styles.feeModalLabel, stylesHook.customLabelColor]}>{loc.send.fee_custom}</Text>
                <View style={styles.customFeeContainer}>
                  <TextInput
                    ref={customFeeInputRef}
                    style={[styles.customFeeInput, stylesHook.customFeeInputColors]}
                    keyboardType="numeric"
                    placeholder={loc.send.insert_custom_fee}
                    value={state.customFeeValue}
                    placeholderTextColor={colors.placeholderTextColor}
                    onChangeText={handleCustomFeeChange}
                    onSubmitEditing={handleCustomFeeSubmit}
                    onFocus={handleCustomFocus}
                    onBlur={handleCustomFeeBlur}
                    enablesReturnKeyAutomatically
                    returnKeyType="done"
                    accessibilityLabel={loc.send.create_fee}
                    testID="feeCustom"
                  />
                  {state.customFeeValue && /^\d+(\.\d+)?$/.test(state.customFeeValue) && Number(state.customFeeValue) > 0 && (
                    <Text style={stylesHook.satVbyteText}>{loc.units.sat_vbyte}</Text>
                  )}
                </View>
              </View>
            </TouchableOpacity>
          </View>
        </ScrollView>
      </View>
    </KeyboardAvoidingView>
  );
};

export default SelectFeeScreen;

const styles = StyleSheet.create({
  keyboardAvoidingRoot: {
    flex: 1,
  },
  scrollView: {
    flex: 1,
  },
  screenContainer: {
    flexGrow: 1,
    paddingBottom: 0,
  },
  contentContainer: {
    paddingTop: 0,
    paddingBottom: 8,
  },
  feeModalItem: {
    paddingHorizontal: 16,
    paddingVertical: 8,
    marginBottom: 10,
  },
  feeModalItemActive: {
    borderRadius: 8,
  },
  feeModalRow: {
    justifyContent: 'space-between',
    flexDirection: 'row',
    alignItems: 'center',
  },
  feeModalLabel: {
    fontSize: 22,
    fontWeight: '600',
  },
  customFeeInput: {
    fontSize: 16,
    height: 36,
    textAlign: 'right',
    padding: 0,
    width: 70,
    marginRight: 4,
  },
  customFeeContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'flex-end',
  },
  customFeeButton: {
    marginBottom: 0,
  },
  feeModalTime: {
    borderRadius: 5,
    paddingHorizontal: 6,
    paddingVertical: 3,
  },
});
