import AsyncStorage from '@react-native-community/async-storage';
import {RouteProp} from '@react-navigation/native';
import {StackNavigationProp} from '@react-navigation/stack';
import React, {useEffect, useRef, useState} from 'react';
import {
  Alert,
  Image,
  KeyboardAvoidingView,
  Platform,
  StatusBar,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';
import SplashScreen from 'react-native-splash-screen';
import {useDispatch} from 'react-redux';
import {Background, SubmitButton, TaggInput} from '../../components';
import {
  LOGIN_ENDPOINT,
  TAGG_LIGHT_PURPLE,
  usernameRegex,
} from '../../constants';
import {
  ERROR_DOUBLE_CHECK_CONNECTION,
  ERROR_FAILED_LOGIN_INFO,
  ERROR_INVALID_LOGIN,
  ERROR_LOGIN_FAILED,
  ERROR_SOMETHING_WENT_WRONG_REFRESH,
} from '../../constants/strings';
import {OnboardingStackParams} from '../../routes/onboarding';
import {fcmService} from '../../services';
import {BackgroundGradientType, UserType} from '../../types';
import {userLogin} from '../../utils';

type VerificationScreenRouteProp = RouteProp<OnboardingStackParams, 'Login'>;
type VerificationScreenNavigationProp = StackNavigationProp<
  OnboardingStackParams,
  'Login'
>;
interface LoginProps {
  route: VerificationScreenRouteProp;
  navigation: VerificationScreenNavigationProp;
}
/**
 * Login screen.
 * @param navigation react-navigation navigation object.
 */
const Login: React.FC<LoginProps> = ({navigation}: LoginProps) => {
  // ref for focusing on input fields
  const inputRef = useRef();

  const NO_USER: UserType = {
    userId: '',
    username: '',
  };

  // login form state
  const [form, setForm] = React.useState({
    username: '',
    password: '',
    isValidUser: false,
    isValidPassword: false,
    attemptedSubmit: false,
    token: '',
  });
  const [user, setUser] = useState<UserType>(NO_USER);

  /**
   * Redux Store stuff
   * Get the dispatch reference
   */

  const dispatch = useDispatch();

  /**
   * Hide the SplashScreen after the timeout. This is done to wait for AsyncStorage to get us the user from disk
   */
  useEffect(() => {
    setTimeout(() => {
      SplashScreen.hide();
    }, 100);
  });

  /**
   * Updates the state of username. Also verifies the input of the username field by ensuring proper length and appropriate characters.
   */

  const handleUsernameUpdate = (val: string) => {
    val = val.trim();
    let validLength: boolean = val.length >= 3;
    let validChars: boolean = usernameRegex.test(val);

    if (validLength && validChars) {
      setForm({
        ...form,
        username: val,
        isValidUser: true,
      });
    } else {
      setForm({
        ...form,
        username: val,
        isValidUser: false,
      });
    }
  };

  /**
   * Updates the state of password. Also verifies the input of the password field by ensuring proper length.
   */
  const handlePasswordUpdate = (val: string) => {
    let validLength: boolean = val.trim().length >= 8;

    if (validLength) {
      setForm({
        ...form,
        password: val,
        isValidPassword: true,
      });
    } else {
      setForm({
        ...form,
        password: val,
        isValidPassword: false,
      });
    }
  };

  /*
   * Handles tap on username keyboard's "Next" button by focusing on password field.
   */
  const handleUsernameSubmit = () => {
    const passwordField: any = inputRef.current;
    if (passwordField) {
      passwordField.focus();
    }
  };

  /**
  * Handler for the Let's Start button or the Go button on the keyboard.
    Makes a POST request to the Django login API and presents Alerts based on the status codes that the backend returns.
  * Stores token received in the response, into client's AsynStorage
  */
  const handleLogin = async () => {
    if (!form.attemptedSubmit) {
      setForm({
        ...form,
        attemptedSubmit: true,
      });
    }
    try {
      if (form.isValidUser && form.isValidPassword) {
        const {username, password} = form;
        let response = await fetch(LOGIN_ENDPOINT, {
          method: 'POST',
          body: JSON.stringify({
            username,
            password,
          }),
        });

        let statusCode = response.status;
        let data = await response.json();

        if (statusCode === 200) {
          //Stores token received in the response into client's AsynStorage
          try {
            await AsyncStorage.setItem('token', data.token);
            await AsyncStorage.setItem('userId', data.UserID);
            await AsyncStorage.setItem('username', username);
            userLogin(dispatch, {userId: data.UserID, username});
            fcmService.sendFcmTokenToServer();
          } catch (err) {
            setUser(NO_USER);
            console.log(data);
            Alert.alert(ERROR_INVALID_LOGIN);
          }
        } else if (statusCode === 401) {
          Alert.alert(ERROR_FAILED_LOGIN_INFO);
        } else {
          Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH);
        }
      } else {
        setForm({...form, attemptedSubmit: false});
        setTimeout(() => setForm({...form, attemptedSubmit: true}));
      }
    } catch (error) {
      Alert.alert(ERROR_LOGIN_FAILED, ERROR_DOUBLE_CHECK_CONNECTION);
      return {
        name: 'Login error',
        description: error,
      };
    }
  };

  /*
   * Handles tap on "Get Started" text by resetting fields & navigating to the registration page.
   */
  const startRegistrationProcess = () => {
    navigation.navigate('WelcomeScreen');
    setForm({...form, attemptedSubmit: false});
  };

  /**
   * Login screen forgot password button.
   */
  const ForgotPassword = () => (
    <TouchableOpacity
      accessibilityLabel="Forgot password button"
      accessibilityHint="Select this if you forgot your tagg password"
      style={styles.forgotPassword}
      onPress={() => navigation.navigate('PasswordResetRequest')}>
      <Text style={styles.forgotPasswordText}>Forgot password</Text>
    </TouchableOpacity>
  );

  /**
   * Login screen login button.
   */
  const LoginButton = () => (
    <SubmitButton
      text="Let's Start!"
      color="#fff"
      style={styles.button}
      accessibilityLabel="Let's Start!"
      accessibilityHint="Select this after entering your tagg username and password"
      onPress={handleLogin}
    />
  );

  /**
   * Login screen registration prompt.
   */
  const RegistrationPrompt = () => (
    <View style={styles.newUserContainer}>
      <Text
        accessible={true}
        accessibilityLabel="New to tagg?"
        style={styles.newUser}>
        New to tagg?{' '}
      </Text>
      <TouchableOpacity
        accessibilityLabel="Get started."
        accessibilityHint="Select this if you do not have a tagg account">
        <Text
          accessible={true}
          accessibilityLabel="Get started"
          style={styles.getStarted}
          onPress={startRegistrationProcess}>
          Get started!
        </Text>
      </TouchableOpacity>
    </View>
  );

  return (
    <Background
      centered
      style={styles.container}
      gradientType={BackgroundGradientType.Light}>
      <StatusBar barStyle="light-content" />
      <KeyboardAvoidingView
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        style={styles.keyboardAvoidingView}>
        <Image
          source={require('../../assets/images/logo.png')}
          style={styles.logo}
        />
        <TaggInput
          accessibilityHint="Enter your tagg username here"
          accessibilityLabel="Username text entry box"
          placeholder="Username"
          autoCompleteType="username"
          textContentType="username"
          returnKeyType="next"
          autoCapitalize="none"
          onChangeText={handleUsernameUpdate}
          onSubmitEditing={handleUsernameSubmit}
          blurOnSubmit={false}
          valid={form.isValidUser}
          invalidWarning="Username must be at least 6 characters and can only contain letters, numbers, periods, and underscores."
          attemptedSubmit={form.attemptedSubmit}
        />

        <TaggInput
          accessibilityHint="Enter your tagg password here"
          accessibilityLabel="Password text entry box"
          placeholder="Password"
          autoCompleteType="password"
          textContentType="password"
          returnKeyType="go"
          autoCapitalize="none"
          secureTextEntry
          onChangeText={handlePasswordUpdate}
          onSubmitEditing={handleLogin}
          valid={form.isValidPassword}
          invalidWarning="Password must be at least 8 characters long."
          attemptedSubmit={form.attemptedSubmit}
          ref={inputRef}
        />
        <ForgotPassword />
        <LoginButton />
      </KeyboardAvoidingView>
      <RegistrationPrompt />
    </Background>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  keyboardAvoidingView: {
    alignItems: 'center',
  },
  logo: {
    width: 215,
    height: 149,
    marginBottom: '10%',
  },
  forgotPassword: {
    marginTop: 10,
    marginBottom: 15,
  },
  forgotPasswordText: {
    fontSize: 14,
    color: '#fff',
    textDecorationLine: 'underline',
  },
  start: {
    width: 144,
    height: 36,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
    borderRadius: 18,
    marginBottom: '15%',
  },
  startDisabled: {
    backgroundColor: '#ddd',
  },
  startText: {
    fontSize: 16,
    color: '#78a0ef',
    fontWeight: 'bold',
  },
  newUserContainer: {
    flexDirection: 'row',
    color: '#fff',
  },
  newUser: {
    fontSize: 14,
    color: TAGG_LIGHT_PURPLE,
  },
  getStarted: {
    fontSize: 14,
    color: '#fff',
    textDecorationLine: 'underline',
  },
  button: {
    marginVertical: '10%',
  },
});

export default Login;
