import AsyncStorage from '@react-native-community/async-storage';
import {useNavigation} from '@react-navigation/core';
import {RouteProp} from '@react-navigation/native';
import {StackNavigationProp} from '@react-navigation/stack';
import React, {useEffect, useState} from 'react';
import {
  Alert,
  KeyboardAvoidingView,
  Platform,
  StatusBar,
  StyleSheet,
  Text,
  TouchableOpacity,
} from 'react-native';
import {normalize} from 'react-native-elements';
import Animated, {EasingNode, useValue} from 'react-native-reanimated';
import {
  ArrowButton,
  Background,
  LoadingIndicator,
  TaggInput,
  TaggSquareButton,
  TermsConditions,
} from '../../components';
import {
  emailRegex,
  nameRegex,
  passwordRegex,
  phoneRegex,
  TAGG_LIGHT_BLUE_2,
  usernameRegex,
} from '../../constants';
import {
  ERROR_NEXT_PAGE,
  ERROR_PHONE_IN_USE,
  ERROR_REGISTRATION,
  ERROR_SOMETHING_WENT_WRONG_REFRESH,
  ERROR_TWILIO_SERVER_ERROR,
  ERROR_T_AND_C_NOT_ACCEPTED,
} from '../../constants/strings';
import {OnboardingStackParams} from '../../routes';
import {
  sendOtpStatusCode,
  sendRegister,
  verifyExistingInformation,
} from '../../services';
import {BackgroundGradientType} from '../../types';
import {HeaderHeight, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';

type BasicInfoOnboardingRouteProp = RouteProp<
  OnboardingStackParams,
  'BasicInfoOnboarding'
>;
type BasicInfoOnboardingNavigationProp = StackNavigationProp<
  OnboardingStackParams,
  'BasicInfoOnboarding'
>;
interface BasicInfoOnboardingProps {
  route: BasicInfoOnboardingRouteProp;
  navigation: BasicInfoOnboardingNavigationProp;
}

const BasicInfoOnboarding: React.FC<BasicInfoOnboardingProps> = ({route}) => {
  const {isPhoneVerified} = route.params;
  const navigation = useNavigation();
  const [attemptedSubmit, setAttemptedSubmit] = useState(false);
  const [valid, setValid] = useState(false);
  const [currentStep, setCurrentStep] = useState(0);
  const [tcAccepted, setTCAccepted] = useState(false);
  const [passVisibility, setPassVisibility] = useState(false);
  const [invalidWithError, setInvalidWithError] = useState(
    'Please enter a valid ',
  );
  const [autoCapitalize, setAutoCap] = useState<
    'none' | 'sentences' | 'words' | 'characters' | undefined
  >('none');
  const [fadeValue, setFadeValue] = useState<Animated.Value<number>>(
    new Animated.Value(0),
  );

  useEffect(() => {
    setValid(false);
  }, [invalidWithError]);

  const fadeButtonValue = useValue<number>(0);
  const [form, setForm] = useState({
    fname: '',
    lname: '',
    username: '',
    phone: '',
    email: '',
    password: '',
  });

  const fadeFormIn = () => {
    setFadeValue(new Animated.Value(0));
  };

  const fadeButtonTo = (target: number) => {
    Animated.timing(fadeButtonValue, {
      toValue: target,
      duration: 100,
      easing: EasingNode.linear,
    }).start();
  };

  useEffect(() => {
    const fade = async () => {
      Animated.timing(fadeValue, {
        toValue: 1,
        duration: 1000,
        easing: EasingNode.linear,
      }).start();
    };
    fade();
  }, [fadeValue]);

  useEffect(() => {
    if (valid) {
      fadeButtonTo(1);
    } else {
      fadeButtonTo(0);
    }
  }, [valid]);

  const goToPhoneVerification = async () => {
    if (!attemptedSubmit) {
      setAttemptedSubmit(true);
    }
    try {
      if (valid) {
        const {phone} = form;
        const code = await sendOtpStatusCode(phone);
        if (code) {
          switch (code) {
            case 200:
              const {fname, lname} = form;
              navigation.navigate('PhoneVerification', {
                firstName: fname,
                lastName: lname,
                phone,
              });
              break;
            case 409:
              Alert.alert(ERROR_PHONE_IN_USE);
              break;
            default:
              Alert.alert(ERROR_TWILIO_SERVER_ERROR);
          }
        } else {
          setAttemptedSubmit(false);
          setTimeout(() => {
            setAttemptedSubmit(true);
          });
        }
      }
    } catch (error) {
      Alert.alert(ERROR_NEXT_PAGE);
      return {
        name: 'Navigation error',
        description: error,
      };
    }
  };
  // 0 = first name, 1 = last name, 2 = username, 3 = phone #
  const handleNameUpdate = (name: string, nameType: number) => {
    name = name.trim();
    let isValidName: boolean = nameRegex.test(name);
    switch (nameType) {
      case 0:
        setForm({
          ...form,
          fname: name,
        });
        setAutoCap('words');
        setValid(isValidName);
        break;
      case 1:
        setForm({
          ...form,
          lname: name,
        });
        setAutoCap('words');
        setValid(isValidName);
        break;
      case 2:
        setForm({
          ...form,
          username: name,
        });
        setValid(usernameRegex.test(name));
        setAutoCap('none');
        break;
    }
  };
  const handlePhoneUpdate = (phone: string) => {
    phone = phone.trim();
    setForm({
      ...form,
      phone,
    });
    setAutoCap('none');
    setValid(phoneRegex.test(phone));
  };
  const handleEmailUpdate = (email: string) => {
    email = email.trim();
    setForm({
      ...form,
      email,
    });
    setAutoCap('none');
    setValid(emailRegex.test(email));
  };
  const handlePasswordUpdate = (password: string) => {
    setForm({
      ...form,
      password,
    });
    setAutoCap('none');
    setValid(passwordRegex.test(password));
  };
  const formSteps: {
    placeholder: string;
    onChangeText: (text: string) => void;
    value: string;
  }[] = [
    {
      placeholder: 'First Name',
      onChangeText: (text) => handleNameUpdate(text, 0),
      value: form.fname,
    },
    {
      placeholder: 'Last Name',
      onChangeText: (text) => handleNameUpdate(text, 1),
      value: form.lname,
    },
    {
      placeholder: 'Phone',
      onChangeText: handlePhoneUpdate,
      value: form.phone,
    },
    {
      placeholder: 'School Email',
      onChangeText: handleEmailUpdate,
      value: form.email,
    },
    {
      placeholder: 'Username',
      onChangeText: (text) => handleNameUpdate(text, 2),
      value: form.username,
    },
    {
      placeholder: 'Password',
      onChangeText: handlePasswordUpdate,
      value: form.password,
    },
  ];
  const resetForm = (formStep: String) => {
    setValid(false);
    switch (formStep) {
      case 'First Name':
        setForm({
          ...form,
          fname: '',
        });
        break;
      case 'Last Name':
        setForm({
          ...form,
          lname: '',
        });
        break;
      case 'Email':
        setForm({
          ...form,
          email: '',
        });
        break;
      case 'Password':
        setForm({
          ...form,
          password: '',
        });
        break;
      case 'School Email':
        setForm({
          ...form,
          email: '',
        });
        break;
      case 'Username':
        setForm({
          ...form,
          username: '',
        });
        break;
    }
  };
  const step = formSteps[currentStep];
  useEffect(() => {
    setInvalidWithError(
      'Please enter a valid ' + step.placeholder.toLowerCase(),
    );
  }, [currentStep]);
  const advance = async () => {
    setAttemptedSubmit(true);
    if (valid) {
      if (step.placeholder === 'School Email') {
        const verifiedInfo = await verifyExistingInformation(
          form.email,
          undefined,
        );
        if (!verifiedInfo) {
          setInvalidWithError('Email is taken');
          return;
        }
      } else if (step.placeholder === 'Username') {
        const verifiedInfo = await verifyExistingInformation(
          undefined,
          form.username,
        );
        if (!verifiedInfo) {
          setInvalidWithError('Username is taken');
          return;
        }
      }
      setCurrentStep(currentStep + 1);
      setAttemptedSubmit(false);
      setValid(false);
      fadeFormIn();
    }
  };
  const advanceRegistration = async () => {
    setAttemptedSubmit(true);
    if (!valid) {
      return;
    }
    if (!tcAccepted) {
      Alert.alert('Terms and conditions', ERROR_T_AND_C_NOT_ACCEPTED);
      return;
    }
    const {fname, lname, phone, email, username, password} = form;
    const response = await sendRegister(
      fname,
      lname,
      phone,
      email,
      username,
      password,
    );
    if (response) {
      const data = await response.json();
      const {token, UserID} = data;
      switch (response.status) {
        case 201:
          await AsyncStorage.setItem('token', token);
          navigation.navigate('ProfileInfoOnboarding', {
            userId: UserID,
            username: username,
          });
          break;
        case 400:
          Alert.alert(ERROR_REGISTRATION(data.toLowerCase()));
          break;
        default:
          Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH);
          break;
      }
    } else {
      Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH);
    }
  };

  useEffect(() => {
    if (isPhoneVerified) {
      advance();
    }
  }, [isPhoneVerified]);

  return (
    <Background
      style={styles.container}
      gradientType={BackgroundGradientType.Light}>
      <StatusBar barStyle="light-content" />
      <KeyboardAvoidingView
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        keyboardVerticalOffset={-(SCREEN_HEIGHT * 0.2)}
        style={styles.container}>
        {currentStep !== 0 && currentStep !== 3 && (
          <ArrowButton
            style={styles.backArrow}
            direction="backward"
            onboarding={true}
            onPress={() => {
              // if I go back do I want to reset the previous form?
              setCurrentStep(currentStep - 1);
              resetForm(step.placeholder);
              setAttemptedSubmit(false);
              setFadeValue(new Animated.Value(0));
            }}
          />
        )}
        {step.placeholder === 'Phone' && !isPhoneVerified ? (
          <>
            <Animated.Text style={[styles.formHeader, {opacity: fadeValue}]}>
              PHONE NUMBER
            </Animated.Text>
            <Animated.View style={[styles.formContainer, {opacity: fadeValue}]}>
              <TaggInput
                style={
                  attemptedSubmit && !valid
                    ? [styles.input, styles.invalidColor]
                    : styles.input
                }
                maxLength={10} // currently only support US phone numbers
                accessibilityHint="Enter your phone number."
                accessibilityLabel="Phone number input field."
                placeholder="Phone Number"
                autoCompleteType="tel"
                selectionColor="white"
                textContentType="telephoneNumber"
                externalStyles={{
                  warning: styles.passWarning,
                }}
                keyboardType="number-pad"
                onChangeText={handlePhoneUpdate}
                autoFocus={true}
                blurOnSubmit={false}
                valid={valid}
                invalidWarning={'Please enter a valid 10 digit number.'}
                attemptedSubmit={attemptedSubmit}
                onSubmitEditing={goToPhoneVerification}
              />
              <Animated.View style={{opacity: fadeButtonValue}}>
                <TaggSquareButton
                  onPress={goToPhoneVerification}
                  title={'Verify'}
                  buttonStyle={'normal'}
                  buttonColor={'white'}
                  labelColor={'blue'}
                />
              </Animated.View>
            </Animated.View>
          </>
        ) : (
          <>
            {step.placeholder !== 'Password' ? (
              <>
                <Text style={styles.formHeader}>SIGN UP</Text>
                <Animated.View
                  style={[styles.formContainer, {opacity: fadeValue}]}>
                  <TaggInput
                    key={step.placeholder}
                    style={
                      attemptedSubmit && !valid
                        ? [styles.input, styles.invalidColor]
                        : styles.input
                    }
                    accessibilityHint={`Enter your ${step.placeholder.toLowerCase()}`}
                    accessibilityLabel={`${step.placeholder} input field.`}
                    placeholder={step.placeholder}
                    autoCompleteType="name"
                    autoCapitalize={autoCapitalize}
                    textContentType="name"
                    returnKeyType="done"
                    selectionColor="white"
                    onChangeText={step.onChangeText}
                    value={step.value}
                    onSubmitEditing={advance}
                    autoFocus={true}
                    blurOnSubmit={false}
                    externalStyles={{
                      warning: styles.passWarning,
                    }}
                    valid={valid}
                    invalidWarning={invalidWithError}
                    attemptedSubmit={attemptedSubmit}
                  />
                  <Animated.View style={{opacity: fadeButtonValue}}>
                    <TaggSquareButton
                      onPress={advance}
                      title={'Next'}
                      buttonStyle={'normal'}
                      buttonColor={'white'}
                      labelColor={'blue'}
                    />
                  </Animated.View>
                </Animated.View>
              </>
            ) : (
              <>
                <Text style={styles.formHeader}>SIGN UP</Text>
                <Animated.View
                  style={[styles.formContainer, {opacity: fadeValue}]}>
                  <TaggInput
                    accessibilityHint="Enter a password."
                    accessibilityLabel="Password input field."
                    placeholder="Password"
                    autoCompleteType="password"
                    textContentType="oneTimeCode"
                    returnKeyType="done"
                    selectionColor="white"
                    onChangeText={handlePasswordUpdate}
                    onSubmitEditing={advanceRegistration}
                    blurOnSubmit={false}
                    autoFocus={true}
                    secureTextEntry={!passVisibility}
                    valid={valid}
                    externalStyles={{
                      warning: styles.passWarning,
                    }}
                    invalidWarning={
                      'Password must be at least 8 characters & contain at least one of a-z, A-Z, 0-9, and a special character.'
                    }
                    attemptedSubmit={attemptedSubmit}
                    style={
                      attemptedSubmit && !valid
                        ? [styles.input, styles.invalidColor]
                        : styles.input
                    }
                  />
                  <TouchableOpacity
                    accessibilityLabel="Show password button"
                    accessibilityHint="Select this if you want to display your tagg password"
                    style={styles.showPassContainer}
                    onPress={() => setPassVisibility(!passVisibility)}>
                    <Text style={styles.showPass}>Show Password</Text>
                  </TouchableOpacity>
                  <LoadingIndicator />
                  <TermsConditions
                    style={styles.tc}
                    accepted={tcAccepted}
                    onChange={setTCAccepted}
                  />
                  <Animated.View style={{opacity: fadeButtonValue}}>
                    <TaggSquareButton
                      onPress={advanceRegistration}
                      title={'Next'}
                      buttonStyle={'normal'}
                      buttonColor={'white'}
                      labelColor={'blue'}
                    />
                  </Animated.View>
                </Animated.View>
              </>
            )}
          </>
        )}
      </KeyboardAvoidingView>
    </Background>
  );
};

const styles = StyleSheet.create({
  container: {
    height: SCREEN_HEIGHT,
    width: SCREEN_WIDTH,
    alignItems: 'center',
    justifyContent: 'center',
  },
  formContainer: {
    marginTop: '20%',
    height: SCREEN_HEIGHT * 0.2,
    width: '80%',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  arrow: {
    color: TAGG_LIGHT_BLUE_2,
  },
  showPassContainer: {
    marginVertical: '1%',
    borderBottomWidth: 1,
    paddingBottom: '1%',
    alignSelf: 'flex-start',
    borderBottomColor: 'white',
    marginBottom: '8%',
  },
  showPass: {
    color: 'white',
  },
  passWarning: {
    fontSize: 14,
    marginTop: 5,
    color: '#FF8989',
    maxWidth: 350,
    alignSelf: 'flex-start',
  },
  input: {
    minWidth: '100%',
    height: 40,
    fontSize: 16,
    fontWeight: '600',
    color: '#fff',
    borderBottomWidth: 1,
    borderBottomColor: '#fff',
  },
  invalidColor: {
    color: '#FF8989',
  },
  errorInput: {
    minWidth: '60%',
    height: 40,
    fontSize: 16,
    fontWeight: '600',
    color: '#FF8989',
    borderBottomWidth: 1,
    borderBottomColor: '#fff',
  },
  button: {
    alignItems: 'center',
    width: 40,
    aspectRatio: 10,
  },
  formHeader: {
    color: '#fff',
    fontSize: 30,
    fontWeight: '600',
    position: 'absolute',
    top: SCREEN_HEIGHT * 0.15,
  },
  load: {
    top: '5%',
  },
  tc: {
    marginVertical: '5%',
  },
  backArrow: {
    width: normalize(29),
    height: normalize(25),
    position: 'absolute',
    top: HeaderHeight * 1.5,
    left: 20,
  },
});
export default BasicInfoOnboarding;
