/**
 * Author : Ashm Walia
 * Purpose : Add a new screen to allow the user to enter first and last name
 */

import React, {useState, useRef} from 'react';
import {RouteProp} from '@react-navigation/native';
import {StackNavigationProp} from '@react-navigation/stack';
import {
  View,
  Text,
  StyleSheet,
  StatusBar,
  Alert,
  Platform,
  TouchableOpacity,
  KeyboardAvoidingView,
  ActivityIndicator,
} from 'react-native';

import {OnboardingStackParams} from '../../routes';
import {
  ArrowButton,
  RegistrationWizard,
  TaggInput,
  TermsConditions,
  Background,
  LoadingIndicator,
} from '../../components';
import {passwordRegex, usernameRegex, REGISTER_ENDPOINT} from '../../constants';
import AsyncStorage from '@react-native-community/async-storage';

type RegistrationScreenThreeRouteProp = RouteProp<
  OnboardingStackParams,
  'RegistrationThree'
>;
type RegistrationScreenThreeNavigationProp = StackNavigationProp<
  OnboardingStackParams,
  'RegistrationThree'
>;
interface RegistrationThreeProps {
  route: RegistrationScreenThreeRouteProp;
  navigation: RegistrationScreenThreeNavigationProp;
}
/**
 * Registration screen 3 for username, password, and terms and conditions
 * @param navigation react-navigation navigation object
 */
const RegistrationThree: React.FC<RegistrationThreeProps> = ({
  route,
  navigation,
}) => {
  // refs for changing focus
  const usernameRef = useRef();
  const passwordRef = useRef();
  const confirmRef = useRef();

  const registrationName = route.params;
  const fname: string = registrationName!.firstName;
  const lname: string = registrationName!.lastName;
  const phone: string = registrationName!.phone;
  const email: string = registrationName!.email;

  /**
   * Handles focus change to the next input field.
   * @param field key for field to move focus onto
   */
  const handleFocusChange = (field: string): void => {
    switch (field) {
      case 'username':
        const usernameField: any = usernameRef.current;
        usernameField.focus();
        break;
      case 'password':
        const passwordField: any = passwordRef.current;
        passwordField.focus();
        break;
      case 'confirm':
        const confirmField: any = confirmRef.current;
        confirmField.focus();
        break;
      default:
        return;
    }
  };

  // registration form state
  const [form, setForm] = useState({
    phone: '',
    username: '',
    password: '',
    confirm: '',
    isValidPhone: false,
    isValidUsername: false,
    isValidPassword: false,
    passwordsMatch: false,
    tcAccepted: false,
    attemptedSubmit: false,
  });

  /*
   * Handles changes to the username field value and verifies the input by updating state and running a validation function.
   */
  const handleUsernameUpdate = (username: string) => {
    let isValidUsername: boolean = usernameRegex.test(username);
    setForm({
      ...form,
      username,
      isValidUsername,
    });
  };
  /*
   * Handles changes to the password field value and verifies the input by updating state and running a validation function.
   */
  const handlePasswordUpdate = (password: string) => {
    let isValidPassword: boolean = passwordRegex.test(password);
    let passwordsMatch: boolean = form.password === form.confirm;
    setForm({
      ...form,
      password,
      isValidPassword,
      passwordsMatch,
    });
  };

  /*
   * Handles changes to the confirm password field value and verifies the input by updating state and running a validation function.
   */
  const handleConfirmUpdate = (confirm: string) => {
    let passwordsMatch: boolean = form.password === confirm;
    setForm({
      ...form,
      confirm,
      passwordsMatch,
    });
  };

  /**
   * Handles changes to the terms and conditions accepted boolean.
   * @param tcAccepted the boolean to set the terms and conditions value to
   */
  const handleTcUpdate = (tcAccepted: boolean) => {
    setForm({
      ...form,
      tcAccepted,
    });
  };

  /**
   * Handles a click on the "next" arrow button by sending an API request to the backend and displaying the appropriate response.
   */
  const handleRegister = async () => {
    if (!form.attemptedSubmit) {
      setForm({
        ...form,
        attemptedSubmit: true,
      });
    }
    try {
      if (form.isValidUsername && form.isValidPassword && form.passwordsMatch) {
        if (form.tcAccepted) {
          let registerResponse = await fetch(REGISTER_ENDPOINT, {
            method: 'POST',
            body: JSON.stringify({
              first_name: fname,
              last_name: lname,
              email: email,
              phone_number: phone,
              username: form.username,
              password: form.password,
            }),
          });
          let statusCode = registerResponse.status;
          let data = await registerResponse.json();
          const userId: string = data.UserID;
          if (statusCode === 201) {
            try {
              await AsyncStorage.setItem('token', data.token);
              /*
               * Skipping navigation to Checkpoint for alpha
               * navigation.navigate('Checkpoint', { userId: userId, username: form.username });
               */
              navigation.navigate('ProfileOnboarding', {
                userId: userId,
                username: form.username,
              });
            } catch (err) {
              console.log(err);
            }
          } else if (statusCode === 409) {
            Alert.alert('Registration failed 😔', `${data}`);
          } else {
            Alert.alert(
              'Something went wrong! 😭',
              "Would you believe me if I told you that I don't know what happened?",
            );
          }
        } else {
          Alert.alert(
            'Terms and conditions',
            'You must first agree to the terms and conditions.',
          );
        }
      } else {
        setForm({...form, attemptedSubmit: false});
        setTimeout(() => setForm({...form, attemptedSubmit: true}));
      }
    } catch (error) {
      Alert.alert(
        'Registration failed 😓',
        'Please double-check your network connection and retry.',
      );
      return {
        name: 'Registration error',
        description: error,
      };
    }
  };

  const Footer = () => (
    <View style={styles.footer}>
      <ArrowButton
        direction="backward"
        onPress={() => navigation.navigate('RegistrationTwo', {phone: phone})}
      />
      <TouchableOpacity onPress={handleRegister}>
        <ArrowButton
          direction="forward"
          disabled={
            !(
              form.isValidUsername &&
              form.isValidPassword &&
              form.passwordsMatch &&
              form.tcAccepted
            )
          }
          onPress={handleRegister}
        />
      </TouchableOpacity>
    </View>
  );

  return (
    <Background style={styles.container}>
      <StatusBar barStyle="light-content" />
      <RegistrationWizard style={styles.wizard} step="five" />
      <KeyboardAvoidingView
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        style={styles.container}>
        <View>
          <Text style={styles.formHeader}>SIGN UP</Text>
        </View>
        <TaggInput
          accessibilityHint="Enter a username."
          accessibilityLabel="Username input field."
          placeholder="Username"
          autoCompleteType="username"
          textContentType="username"
          autoCapitalize="none"
          returnKeyType="next"
          onChangeText={handleUsernameUpdate}
          onSubmitEditing={() => handleFocusChange('password')}
          blurOnSubmit={false}
          ref={usernameRef}
          valid={form.isValidUsername}
          invalidWarning={
            'Username must be at least 6 characters and contain only alphanumerics.'
          }
          attemptedSubmit={form.attemptedSubmit}
          width={280}
        />
        <TaggInput
          accessibilityHint="Enter a password."
          accessibilityLabel="Password input field."
          placeholder="Password"
          autoCompleteType="password"
          textContentType="newPassword"
          returnKeyType="next"
          onChangeText={handlePasswordUpdate}
          onSubmitEditing={() => handleFocusChange('confirm')}
          blurOnSubmit={false}
          secureTextEntry
          ref={passwordRef}
          valid={form.isValidPassword}
          invalidWarning={
            'Password must be at least 8 characters & contain at least one of a-z, A-Z, 0-9, and a special character.'
          }
          attemptedSubmit={form.attemptedSubmit}
          width={280}
        />
        <TaggInput
          accessibilityHint={'Re-enter your password.'}
          accessibilityLabel={'Password confirmation input field.'}
          placeholder={'Confirm Password'}
          autoCompleteType="password"
          textContentType="password"
          returnKeyType={form.tcAccepted ? 'go' : 'default'}
          onChangeText={handleConfirmUpdate}
          onSubmitEditing={handleRegister}
          secureTextEntry
          ref={confirmRef}
          valid={form.passwordsMatch}
          invalidWarning={'Passwords must match.'}
          attemptedSubmit={form.attemptedSubmit}
          width={280}
        />
        <LoadingIndicator />
        <TermsConditions
          style={styles.tc}
          accepted={form.tcAccepted}
          onChange={handleTcUpdate}
        />
      </KeyboardAvoidingView>
      <Footer />
    </Background>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  wizard: {
    ...Platform.select({
      ios: {
        top: 50,
      },
      android: {
        bottom: 40,
      },
    }),
  },
  formHeader: {
    color: '#fff',
    fontSize: 30,
    fontWeight: '600',
    marginBottom: '16%',
  },
  tc: {
    marginVertical: '5%',
    top: '8%',
  },
  load: {
    top: '5%',
  },
  footer: {
    width: '100%',
    flexDirection: 'row',
    justifyContent: 'space-around',
    ...Platform.select({
      ios: {
        bottom: '20%',
      },
      android: {
        bottom: '10%',
      },
    }),
  },
});

export default RegistrationThree;
