import {RegisterProcess, ThemeMode} from '@caj/configs/appVar';
import {appVarActions} from '@caj/configs/appVarReducer';
import {defaultHeaderStyle} from '@caj/configs/colors';
import {SlideFromLeftView} from '@caj/helper/animations';
import {saveVarChanges} from '@caj/helper/appData';
import {apiBackendRequest, makeRequest} from '@caj/helper/request';
import {
  accountNameOptions,
  EMail,
  emailOptions,
  passwordOptions,
  userNameOptions,
  XToken,
} from '@caj/configs/types';
import {RootScreenNavigationProp, WebBackButtonOptions} from '@caj/Navigation';
import {RootState, store} from '@caj/redux/store';
import {useNavigation} from '@react-navigation/native';
import {
  createNativeStackNavigator,
  NativeStackNavigationProp,
} from '@react-navigation/native-stack';
import {
  Box,
  Button,
  Center,
  Container,
  FormControl,
  IconButton,
  Input,
  ScrollView,
  Text,
  useColorModeValue,
  useTheme,
  useToast,
  VStack,
  WarningOutlineIcon,
  Progress,
} from 'native-base';

import MaterialIcons from 'react-native-vector-icons/MaterialIcons';

import {useEffect, useRef, useState} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import reactStringReplace from 'react-string-replace';
import ConfirmationCodeField from './ConfirmationCodeField';
import NameDisplay from './NameDisplay';
import showToast from './Toast';
import {NativeSyntheticEvent, TextInputFocusEventData} from 'react-native';

import PasswordQualityCalculator from '@caj/helper/password-quality-calculator/PasswordQualityCalculator';

// [ optional ] list of about 10000 most common passwords, 86kb (gzip 32kb)
import MostPopularPasswords from '@caj/helper/password-quality-calculator/MostPopularPasswords';
import MyUserManager from '@caj/user/MyUserManager';

import {Buffer} from 'buffer';

// Load the popular passwords list
PasswordQualityCalculator.PopularPasswords.load(MostPopularPasswords);

const validateEmail = (email: EMail) => {
  return emailOptions.isAllowed(email);
};

export default function NotLoggedIn() {
  const currentUser = useSelector(
    (state: RootState) => state.appVariables.preferences.selectedAccount,
  );

  const lang = useSelector((state: RootState) => state.appVariables.lang);
  const theme = useSelector(
    (state: RootState) => state.appVariables.preferences.theme,
  );

  const navigation = useNavigation<RootScreenNavigationProp>();

  if (currentUser !== 'none') {
    return null;
  }

  return (
    <Box alignItems="center" mt={5}>
      <Text color="primary.400">{lang.appName}</Text>
      <Text color="white.600">{lang.appNameDesc}</Text>
      <VStack mt={5} space={4} alignItems="center">
        <Button
          w="72"
          colorScheme="primary"
          rounded="xl"
          _text={{fontSize: 'xl'}}
          onPress={() => {
            navigation.navigate('Register', {screen: 'RegStepOne'});
          }}>
          Sign up
        </Button>
        <Button
          w="72"
          colorScheme="black"
          variant={theme === ThemeMode.Darkest ? 'outline' : 'subtle'}
          rounded="xl"
          _text={{fontSize: 'xl', color: 'white.900'}}
          onPress={() => {
            navigation.navigate('Register', {screen: 'Login'});
          }}>
          Log in
        </Button>
      </VStack>
    </Box>
  );
}

export function RegisterScreenAnim(props: any) {
  return (
    <SlideFromLeftView>
      <RegisterScreen {...props} />
    </SlideFromLeftView>
  );
}

export type LoginStackNavigatorParamList = {
  RegStepOne: undefined;
  RegStepTwo: undefined;
  RegStepFinal: undefined;
  Login: undefined;
};

const LoginStack = createNativeStackNavigator<LoginStackNavigatorParamList>();

export type LoginScreenNavigationProp =
  NativeStackNavigationProp<LoginStackNavigatorParamList>;

function RegisterScreen() {
  const lang = useSelector((state: RootState) => state.appVariables.lang);
  const theme = useSelector(
    (state: RootState) => state.appVariables.preferences.theme,
  );

  const navigation = useNavigation<LoginScreenNavigationProp>();

  return (
    <LoginStack.Navigator
      screenOptions={{
        ...WebBackButtonOptions(navigation, theme, 'registration'),
        headerShown: true,
        ...defaultHeaderStyle(theme, 'registration'),
      }}>
      <LoginStack.Screen
        name="RegStepOne"
        options={{
          animation: 'slide_from_left',
          title: lang.account.registration.registration,
        }}
        component={StepOne}
      />
      <LoginStack.Screen
        name="RegStepTwo"
        options={{
          animation: 'slide_from_right',
          title: lang.account.registration.registration,
        }}
        component={StepTwo}
      />
      <LoginStack.Screen
        name="RegStepFinal"
        options={{
          animation: 'slide_from_right',
          title: lang.account.registration.registration,
        }}
        component={StepFinal}
      />
      <LoginStack.Screen
        name="Login"
        options={{
          animation: 'slide_from_right',
          title: lang.account.login.title,
        }}
        component={Login}
      />
    </LoginStack.Navigator>
  );
}

function Agreement() {
  const toast = useToast();
  const lang = useSelector((state: RootState) => state.appVariables.lang);

  const textColor = useColorModeValue('blue.700', 'cyan.400');

  let replacedText = reactStringReplace(
    lang.account.registration.info,
    '${TermsOfUse}',
    (match, i) => (
      <Text
        key={match + i}
        color={textColor}
        bold
        onPress={() => {
          showToast(toast, {
            title: lang.account.registration.termsOfUse,
            variant: 'solid',
            status: 'info',
            description: undefined,
            isClosable: true,
            rest: {colorScheme: 'primary'},
          });
        }}>
        {lang.account.registration.termsOfUse}
      </Text>
    ),
  );

  replacedText = reactStringReplace(
    replacedText,
    '${privacyPolicy}',
    (match, i) => (
      <Text
        key={match + i}
        color={textColor}
        bold
        onPress={() => {
          showToast(toast, {
            title: lang.account.registration.privacyPolicy,
            variant: 'solid',
            status: 'info',
            description: undefined,
            isClosable: true,
            rest: {colorScheme: 'primary'},
          });
        }}>
        {lang.account.registration.privacyPolicy}
      </Text>
    ),
  );

  return (
    <Text textAlign={'justify'} color={'white.900'}>
      {replacedText}
    </Text>
  );
}

function resendMail(email: EMail, toast: any): Promise<XToken> {
  return new Promise<XToken>((resolve, reject) => {
    makeRequest({
      path: apiBackendRequest.REGISTER_RESEND_MAIL,
      requestHeader: {
        'X-Token':
          store.getState().appVariables.preferences.RegisterProcess.XToken,
      },
      request: {
        Email: email,
      },
      response: {
        XToken: undefined,
      },
    })
      .then(resp => {
        let token =
          store.getState().appVariables.preferences.RegisterProcess.XToken;
        if (token === undefined) token = '';

        if (resp.response.XToken !== undefined || token !== undefined) {
          if (resp.response.XToken !== undefined) {
            token = resp.response.XToken;

            let regPro = {
              ...store.getState().appVariables.preferences.RegisterProcess,
            };
            regPro.XToken = token;
            store.dispatch(appVarActions.setRegisterProcess(regPro));

            saveVarChanges();
          }

          showToast(toast, {
            title: store.getState().appVariables.lang.info,
            variant: 'solid',
            status: 'info',
            description:
              store.getState().appVariables.lang.account.registration.stepTwo
                .resend[2],
            isClosable: true,
            rest: {},
          });

          resolve(token);
        } else {
          reject(500);
          showToast(toast, {
            title: store.getState().appVariables.lang.error,
            variant: 'solid',
            status: 'error',
            description: 'XToken is undefined',
            isClosable: true,
            rest: {},
          });
        }
      })
      .catch(resp => {
        let text = 'Error ' + resp.status;
        if (resp.status !== undefined) {
          const _text =
            store.getState().appVariables.lang.account.registration.stepTwo
              .resendError[resp.status as number];
          if (_text !== undefined) text = _text;
        }

        showToast(toast, {
          title: store.getState().appVariables.lang.error,
          variant: 'solid',
          status: 'error',
          description: text,
          isClosable: true,
          rest: {},
        });

        reject(resp.status);
      });
  });
}

function StepOne() {
  const lang = useSelector((state: RootState) => state.appVariables.lang);
  const regPro = useSelector(
    (state: RootState) => state.appVariables.preferences.RegisterProcess,
  );

  const dispatch = useDispatch();
  const toast = useToast();

  const navigation = useNavigation<RootScreenNavigationProp>();

  const initNoErrors = {
    wrongFormat: false,
    alreadyExists: false,
    noEntered: false,
    unknown: undefined,
  };

  const [errors, setErrors] = useState(initNoErrors);

  const isError =
    errors.wrongFormat ||
    errors.alreadyExists ||
    errors.noEntered ||
    errors.unknown !== undefined;

  const errorText = () => {
    if (errors.wrongFormat) {
      return lang.account.registration.stepOne.addressInvalid;
    }
    if (errors.alreadyExists) {
      return lang.account.registration.stepOne.addressExists;
    }
    if (errors.noEntered) {
      return lang.account.registration.stepOne.noMailEntered;
    }
    if (errors.unknown !== undefined) {
      return errors.unknown;
    }
  };

  const [isLoading, setLoading] = useState(false);

  const [values, setValues] = useState({email: regPro.EMail});

  useEffect(() => {
    if (regPro.isRegistering === 'stepTwo') {
      setLoading(true);
      setErrors(initNoErrors);

      setTimeout(nextStep, 500);
    } else if (regPro.isRegistering === 'stepFinal') {
      setLoading(true);
      setErrors(initNoErrors);

      setTimeout(nextStep, 500);
    }
  }, []);

  const nextStep = () => {
    setLoading(true);
    setErrors(initNoErrors);

    let rp = {...regPro};

    if (rp.EMail !== values.email) {
      rp.XToken = undefined;
    }

    makeRequest({
      path: apiBackendRequest.REGISTER_STEP_1,
      requestHeader: {},
      request: {
        Email: values.email,
      },
      response: {
        XToken: undefined,
      },
    })
      .then(resp => {
        rp.isRegistering = 'stepTwo';
        rp.EMail = values.email;
        rp.XToken = resp.response.XToken;

        dispatch(appVarActions.setRegisterProcess(rp));
        saveVarChanges();

        showToast(toast, {
          title: lang.account.registration.stepOne.success,
          variant: 'solid',
          status: 'success',
          description: undefined,
          isClosable: true,
          rest: {colorScheme: 'primary'},
        });

        navigation.navigate('Register', {screen: 'RegStepTwo'});
        setLoading(false);
      })
      .catch(resp => {
        if (resp.status === 401 || resp.status === 204) {
          if (regPro.XToken !== undefined) {
            if (resp.status === 401) {
              rp.isRegistering = 'stepTwo';
              rp.EMail = values.email;

              dispatch(appVarActions.setRegisterProcess(rp));
              saveVarChanges();

              navigation.navigate('Register', {screen: 'RegStepTwo'});
            } else if (resp.status === 204) {
              rp.isRegistering = 'stepFinal';
              rp.EMail = values.email;

              dispatch(appVarActions.setRegisterProcess(rp));
              saveVarChanges();

              navigation.navigate('Register', {screen: 'RegStepFinal'});
            }

            setLoading(false);
          } else {
            resendMail(values.email, toast)
              .then(() => {
                navigation.navigate('Register', {screen: 'RegStepTwo'});
                setLoading(false);
              })
              .catch(() => {
                setLoading(false);
              });
          }
          return;
        } else if (resp.status === 422) {
          showToast(toast, {
            title: lang.error,
            variant: 'solid',
            status: 'error',
            description: lang.account.registration.stepOne.addressExists,
            isClosable: true,
            rest: {colorScheme: 'primary'},
          });
        } else {
          showToast(toast, {
            title: lang.error,
            variant: 'solid',
            status: 'error',
            description: resp.status,
            isClosable: true,
            rest: {colorScheme: 'primary'},
          });
        }
        setLoading(false);
      });
  };

  const onButtonPress = () => {
    if (values.email === '') {
      let err = errors;
      err.noEntered = true;
      setErrors({...err});
    } else if (validateEmail(values.email)) {
      nextStep();
    } else {
      let err = errors;
      err.wrongFormat = true;
      setErrors({...err});
    }
  };

  return (
    <ScrollView keyboardShouldPersistTaps="handled">
      <Box alignItems="center" mt={5}>
        <FormControl
          w="75%"
          maxW="350px"
          isRequired
          isDisabled={isLoading}
          isInvalid={isError}>
          <FormControl.Label>
            {lang.account.registration.stepOne.title}
          </FormControl.Label>
          <Input
            autoFocus
            autoComplete="email"
            placeholder={lang.account.registration.stepOne.title}
            value={values.email}
            onSubmitEditing={onButtonPress}
            autoCapitalize={'none'}
            maxLength={emailOptions.maxLength}
            keyboardType={'email-address'}
            onChangeText={text => {
              const mail = text.replaceAll(' ', '');
              setValues({email: mail});

              if (errors.noEntered && mail !== '') {
                let err = errors;
                err.noEntered = false;
                setErrors({...err});
              }
              if (errors.wrongFormat && validateEmail(mail)) {
                let err = errors;
                err.wrongFormat = false;
                setErrors({...err});
              }
              if (errors.alreadyExists) {
                let err = errors;
                err.alreadyExists = false;
                setErrors({...err});
              }
            }}
          />

          <FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
            {errorText()}
          </FormControl.ErrorMessage>
        </FormControl>
        <Container marginY={5}>
          <Agreement />
        </Container>
        <Button
          w="75%"
          maxW="350px"
          colorScheme="primary"
          rounded="xl"
          _text={{fontSize: 'xl'}}
          isLoading={isLoading}
          onPress={onButtonPress}>
          {lang.account.registration.stepOne.button}
        </Button>
      </Box>
    </ScrollView>
  );
}

function StepTwo() {
  const lang = useSelector((state: RootState) => state.appVariables.lang);
  const regPro = useSelector(
    (state: RootState) => state.appVariables.preferences.RegisterProcess,
  );

  const dispatch = useDispatch();

  const cellCount = 6;
  const {colors} = useTheme();

  const toast = useToast();

  const navigation = useNavigation<RootScreenNavigationProp>();

  const initNoErrors = {
    noEntered: false,
  };

  const [errors, setErrors] = useState(initNoErrors);

  const [isLoading, setLoading] = useState(false);

  const [values, setValues] = useState({code: ''});

  const headerText = () => {
    return reactStringReplace(
      lang.account.registration.stepTwo.title,
      '${EMail}',
      (match, i) => (
        <Text key={match + i} color={'primary.400'}>
          {regPro.EMail}
        </Text>
      ),
    );
  };

  const resendText = () => {
    return reactStringReplace(
      lang.account.registration.stepTwo.resend[0],
      '${resend}',
      (match, i) => (
        <Text
          key={match + i}
          color={'primary.400'}
          onPress={() => {
            setLoading(true);
            resendMail(
              store.getState().appVariables.preferences.RegisterProcess.EMail,
              toast,
            )
              .then(() => {
                setLoading(false);
              })
              .catch(() => {
                setLoading(false);
              });
          }}>
          {lang.account.registration.stepTwo.resend[1]}
        </Text>
      ),
    );
  };

  const validate = (text: string) => {
    setLoading(true);
    setTimeout(() => {
      makeRequest({
        path: apiBackendRequest.REGISTER_STEP_2,

        requestHeader: {},
        requestGET: {':verifyId': text, ':xToken': regPro.XToken || ''},
      })
        .then(resp => {
          let rp = {...regPro};
          rp.isRegistering = 'stepFinal';

          dispatch(appVarActions.setRegisterProcess(rp));
          saveVarChanges();

          showToast(toast, {
            title: lang.account.registration.stepTwo.success,
            variant: 'solid',
            status: 'success',
            description: undefined,
            isClosable: true,
            rest: {colorScheme: 'primary'},
          });

          navigation.navigate('Register', {screen: 'RegStepFinal'});
          setLoading(false);
        })
        .catch(resp => {
          let text = 'Error ' + resp.status;
          if (resp.status !== undefined) {
            const _text =
              lang.account.registration.stepTwo.verificationError[
                resp.status as number
              ];
            if (_text !== undefined) text = _text;
          }

          showToast(toast, {
            title: lang.error,
            variant: 'solid',
            status: 'error',
            description: text,
            isClosable: true,
            rest: {},
          });

          setLoading(false);
          if (resp.status === 422) {
            let rp = {...regPro};
            rp.isRegistering = false;

            dispatch(appVarActions.setRegisterProcess(rp));
            saveVarChanges();
            navigation.navigate('Register', {screen: 'RegStepOne'});
          }
        });
    }, 500);
  };

  return (
    <ScrollView keyboardShouldPersistTaps="handled">
      <Box alignItems="center" mt={5}>
        <Center w="75%" maxW="1000px">
          <Text>{headerText()}</Text>
          <Box>
            <FormControl isDisabled={isLoading} isInvalid={errors.noEntered}>
              <ConfirmationCodeField
                cellCount={cellCount}
                charType="number"
                disabled={isLoading}
                rest={{mt: 5}}
                onChange={(text: string) => {
                  setValues({code: text});
                  setErrors(initNoErrors);
                }}
                onFinish={(text: string) => validate(text)}
              />

              <FormControl.ErrorMessage
                leftIcon={<WarningOutlineIcon size="xs" />}>
                {lang.account.registration.stepTwo.noCodeEntered}
              </FormControl.ErrorMessage>
            </FormControl>
          </Box>
        </Center>
        <Container marginY={5}>
          <Agreement />
        </Container>
        <Button
          w="75%"
          maxW="350px"
          colorScheme="primary"
          rounded="xl"
          _text={{fontSize: 'xl'}}
          isLoading={isLoading}
          onPress={() => {
            if (values.code.length === cellCount) {
              validate(values.code);
            } else {
              let err = {...errors};
              err.noEntered = true;
              setErrors(err);
            }
          }}>
          {lang.account.registration.stepTwo.button}
        </Button>
        <Container marginY={5}>
          <Text textAlign={'justify'} color={'white.900'}>
            {resendText()}
          </Text>
        </Container>
      </Box>
    </ScrollView>
  );
}
function StepFinal() {
  const lang = useSelector((state: RootState) => state.appVariables.lang);
  const regPro = useSelector(
    (state: RootState) => state.appVariables.preferences.RegisterProcess,
  );

  const dispatch = useDispatch();

  const {colors} = useTheme();

  const toast = useToast();

  const navigation = useNavigation<RootScreenNavigationProp>();

  const [isLoading, setLoading] = useState(false);
  const [showPassword, setShowPassword] = useState(false);

  interface inputElementType {
    label: string;
    input: string;
    autoCapitalize: 'none' | 'words';
    errorIndex: 'none' | string;
    errorTextObject: any;
    isPassword: boolean | 'passwordRepeat';
    minLength: number;
    maxLength: number;
    onTextChange: any;
    textChangeTimeout: number;
    isAllowed: any;
    autoComplete?: 'name' | 'username-new' | 'password-new';
  }

  const accountNameRef = useRef(setTimeout(() => {}));
  const accountNameFetchRef = useRef(setTimeout(() => {}));

  const accountName = {
    label: lang.account.registration.stepFinal.accountName,
    input: '',
    autoComplete: 'username-new',
    errorIndex: 'none',
    errorTextObject: lang.account.registration.stepFinal.accountNameError,
    minLength: accountNameOptions.minLength,
    maxLength: accountNameOptions.maxLength,
    isAllowed: accountNameOptions.isAllowed,
    isPassword: false,
    onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
      let text = e.nativeEvent.text;
      let self = accountName;

      clearTimeout(accountNameRef.current);

      let obj = {...valuesAccountName};
      accountNameRef.current = setTimeout(() => {
        obj.input = text;

        if (text.length < self.minLength) obj.errorIndex = 'tooShort';
        else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
        else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
        else obj.errorIndex = 'none';

        setValuesAccountName(obj);

        accountNameFetchRef.current = setTimeout(() => {
          if (obj.errorIndex === 'none') {
            makeRequest({
              path: apiBackendRequest.REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK,
              request: {AccountName: obj.input},
            })
              .then(resp => {})
              .catch(resp => {
                if (resp.status !== undefined) {
                  obj.errorIndex = resp.status;
                  setValuesAccountName({...obj});
                }
              });
          }
        }, 750);
      }, 50);

      clearTimeout(accountNameFetchRef.current);
    },
  } as inputElementType;
  const [valuesAccountName, setValuesAccountName] = useState(accountName);

  const userNameRef = useRef(setTimeout(() => {}));

  const userName = {
    label: lang.account.registration.stepFinal.userName,
    input: '',
    autoComplete: 'name',
    errorIndex: 'none',
    errorTextObject: lang.account.registration.stepFinal.userNameError,
    minLength: userNameOptions.minLength,
    maxLength: userNameOptions.maxLength,
    isAllowed: userNameOptions.isAllowed,
    isPassword: false,
    onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
      let text = e.nativeEvent.text;
      let self = userName;

      clearTimeout(userNameRef.current);

      userNameRef.current = setTimeout(() => {
        let obj = {...valuesUserName};
        obj.input = text;

        if (text.length < self.minLength) obj.errorIndex = 'tooShort';
        else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
        else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
        else obj.errorIndex = 'none';

        setValuesUserName(obj);
      }, 50);
    },
  } as inputElementType;
  const [valuesUserName, setValuesUserName] = useState(userName);

  const passwordRef = useRef(setTimeout(() => {}));

  const password = {
    label: lang.account.registration.stepFinal.password,
    input: '',
    autoComplete: 'password-new',
    errorIndex: 'none',
    errorTextObject: lang.account.registration.stepFinal.passwordError,
    minLength: passwordOptions.minLength,
    maxLength: passwordOptions.maxLength,
    isAllowed: passwordOptions.isAllowed,
    isPassword: true,
    onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
      let text = e.nativeEvent.text;
      let self = password;

      clearTimeout(passwordRef.current);

      passwordRef.current = setTimeout(() => {
        let obj = {...valuesPassword};
        obj.input = text;

        let PasswordQuality = PasswordQualityCalculator(text);
        setPasswordQuality(PasswordQuality);

        if (text.length < self.minLength) obj.errorIndex = 'tooShort';
        else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
        else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
        else if (passwordOptions.minBits >= PasswordQuality)
          obj.errorIndex = 'weak';
        else obj.errorIndex = 'none';

        setValuesPassword(obj);

        let objRe = {...valuesPasswordRe};
        if (valuesPasswordRe.input !== '') {
          if (text !== valuesPasswordRe.input) objRe.errorIndex = 'noMatch';
          else objRe.errorIndex = 'none';

          setValuesPasswordRe(objRe);
        }
      }, 50);
    },
  } as inputElementType;
  const [valuesPassword, setValuesPassword] = useState(password);
  const [passwordQuality, setPasswordQuality] = useState(0);

  let passwordQualityIndex = 0;
  if (passwordQuality >= 128) passwordQualityIndex = 4;
  else if (passwordQuality >= 100) passwordQualityIndex = 3;
  else if (passwordQuality >= 80) passwordQualityIndex = 2;
  else if (passwordQuality >= 50) passwordQualityIndex = 1;
  let passwordQualityPercent = (passwordQuality / 128.0) * 100;
  passwordQualityPercent =
    passwordQualityPercent >= 100.0 ? 100 : passwordQualityPercent;

  const passwordQualityColor = 'hsl(' + passwordQualityPercent + ', 100%, 50%)';

  const passwordQualityText =
    lang.account.registration.stepFinal.passwordQuality.replace(
      '${quality}',
      lang.account.registration.stepFinal.passwordQualityList[
        passwordQualityIndex
      ],
    );

  const passwordReRef = useRef(setTimeout(() => {}));

  const passwordRe = {
    label: lang.account.registration.stepFinal.passwordRepeat,
    input: '',
    autoComplete: 'password-new',
    errorIndex: 'none',
    errorTextObject: lang.account.registration.stepFinal.passwordError,
    minLength: passwordOptions.minLength,
    maxLength: passwordOptions.maxLength,
    isAllowed: passwordOptions.isAllowed,
    isPassword: 'passwordRepeat',
    onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
      let text = e.nativeEvent.text;
      let self = passwordRe;

      clearTimeout(passwordReRef.current);

      passwordReRef.current = setTimeout(() => {
        let obj = {...valuesPasswordRe};
        obj.input = text;

        if (text !== valuesPassword.input) obj.errorIndex = 'noMatch';
        else obj.errorIndex = 'none';

        setValuesPasswordRe(obj);
      }, 50);
    },
  } as inputElementType;
  const [valuesPasswordRe, setValuesPasswordRe] = useState(passwordRe);

  const inputElement = (
    val: inputElementType,
    set: React.Dispatch<React.SetStateAction<inputElementType>>,
    valConst: inputElementType,
    autofocus?: boolean,
  ) => {
    const isPassword =
      val.isPassword === true || val.isPassword === 'passwordRepeat';

    return (
      <FormControl
        w="75%"
        maxW={350}
        isRequired
        isDisabled={isLoading}
        isInvalid={val.errorIndex !== 'none'}>
        <FormControl.Label>{val.label}</FormControl.Label>
        <Input
          autoComplete={val.autoComplete}
          autoFocus={autofocus}
          type={isPassword && showPassword === false ? 'password' : 'text'}
          placeholder={''}
          keyboardType={'default'}
          onChange={valConst.onTextChange}
          InputRightElement={
            isPassword ? (
              <IconButton
                mr="2"
                focusable={false}
                onPress={() => setShowPassword(!showPassword)}
                icon={
                  <MaterialIcons
                    size={20}
                    color={colors.white[200]}
                    name={showPassword ? 'visibility' : 'visibility-off'}
                  />
                }
                borderRadius="full"
              />
            ) : undefined
          }
        />

        <FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
          {val.errorTextObject[val.errorIndex] !== undefined
            ? val.errorTextObject[val.errorIndex]
                .replaceAll('${minLength}', val.minLength)
                .replaceAll('${maxLength}', val.maxLength)
            : val.errorTextObject[val.errorIndex] !== 'none'
            ? lang.error
            : null}
        </FormControl.ErrorMessage>
      </FormControl>
    );
  };

  return (
    <ScrollView keyboardShouldPersistTaps="handled">
      <VStack space={3} alignItems="center" mt={5}>
        <Container maxWidth={'100%'} alignItems={'center'}>
          <Center>
            <Text>{lang.account.registration.stepFinal.displayName}</Text>
            <NameDisplay
              UserName={
                valuesUserName.input !== ''
                  ? valuesUserName.input
                  : lang.account.registration.stepFinal.userName
              }
              AccountName={
                valuesAccountName.input !== ''
                  ? valuesAccountName.input
                  : lang.account.registration.stepFinal.accountName
              }
            />
          </Center>
        </Container>
        {inputElement(valuesUserName, setValuesUserName, userName)}
        {inputElement(valuesAccountName, setValuesAccountName, accountName)}
        {inputElement(valuesPassword, setValuesPassword, password)}

        <Box w="75%" maxW={350}>
          <Text mx={4} mb={1} fontSize={13} color="light.400">
            {passwordQualityText}
          </Text>
          <Progress
            value={passwordQualityPercent}
            mx={4}
            _filledTrack={{
              bg: passwordQualityColor,
            }}
          />
        </Box>

        {inputElement(valuesPasswordRe, setValuesPasswordRe, passwordRe)}
      </VStack>
      <Center>
        <Container mt={5}>
          <Agreement />
        </Container>
        <Button
          marginY={5}
          w="75%"
          maxW="350px"
          colorScheme="primary"
          rounded="xl"
          _text={{fontSize: 'xl'}}
          isLoading={isLoading}
          onPress={() => {
            function showToastNow(text: string) {
              showToast(toast, {
                title: text,
                variant: 'solid',
                status: 'error',
                description: undefined,
                isClosable: true,
                rest: {},
              });
            }

            valuesUserName.onTextChange({
              nativeEvent: {text: valuesUserName.input},
            });

            valuesAccountName.onTextChange({
              nativeEvent: {text: valuesAccountName.input},
            });

            valuesPassword.onTextChange({
              nativeEvent: {text: valuesPassword.input},
            });

            let obj = {...valuesPasswordRe};
            if (obj.input !== valuesPassword.input) obj.errorIndex = 'noMatch';
            else obj.errorIndex = 'none';
            setValuesPasswordRe(obj);

            setLoading(true);

            setTimeout(() => {
              if (
                valuesAccountName.input === '' ||
                valuesUserName.input === '' ||
                valuesPassword.input === '' ||
                valuesPasswordRe.input === '' ||
                valuesUserName.errorIndex !== 'none' ||
                valuesAccountName.errorIndex !== 'none' ||
                valuesPassword.errorIndex !== 'none' ||
                valuesPasswordRe.errorIndex !== 'none'
              ) {
                /*showToastNow(
                  lang.account.registration.stepFinal.noAllFieldsEntered,
                );*/
                setLoading(false);
                return;
              }

              let base64PW = Buffer.from(valuesPassword.input).toString(
                'base64',
              );

              let xToken =
                store.getState().appVariables.preferences.RegisterProcess
                  .XToken;

              if (xToken === undefined) xToken = '';

              makeRequest({
                path: apiBackendRequest.REGISTER_STEP_FINAL,
                requestHeader: {
                  'X-Token': xToken,
                },
                request: {
                  AccountName: valuesAccountName.input,
                  Username: valuesUserName.input,
                  Password: base64PW,
                },
                response: {
                  XAuthorization: '',
                  UserId: '',
                  WebSocketSessionId: '',
                },
              })
                .then(resp => {
                  if (
                    resp.response.XAuthorization !== '' &&
                    resp.response.UserId !== '' &&
                    resp.response.WebSocketSessionId !== ''
                  ) {
                    let regPro = {
                      ...store.getState().appVariables.preferences
                        .RegisterProcess,
                    };
                    regPro.isRegistering = false;
                    store.dispatch(appVarActions.setRegisterProcess(regPro));

                    MyUserManager.createNewMyUser(
                      resp.response.UserId,
                      valuesAccountName.input,
                      valuesUserName.input,
                      store.getState().appVariables.preferences.RegisterProcess
                        .EMail,
                      resp.response.XAuthorization,
                      resp.response.WebSocketSessionId,
                    );
                    navigation.popToTop();
                    navigation.goBack();
                  }

                  setLoading(false);
                })
                .catch(resp => {
                  let errorText =
                    lang.account.registration.stepFinal.registerError[
                      resp.status
                    ] || 'Error ' + resp.status;
                  showToastNow(errorText);
                  setLoading(false);
                });
            }, 300);
          }}>
          {lang.account.registration.stepFinal.button}
        </Button>
      </Center>
    </ScrollView>
  );
}

function Login() {
  const lang = useSelector((state: RootState) => state.appVariables.lang);
  const regPro = useSelector(
    (state: RootState) => state.appVariables.preferences.RegisterProcess,
  );

  const {colors} = useTheme();
  const dispatch = useDispatch();
  const toast = useToast();

  const navigation = useNavigation<RootScreenNavigationProp>();

  const initNoErrors = {
    wrongFormat: false,
    alreadyExists: false,
    noEntered: false,
    unknown: undefined,
  };

  const [errorsMail, setErrorsMail] = useState(initNoErrors);
  const [errorsPassword, setErrorsPassword] = useState(initNoErrors);
  const [showPassword, setShowPassword] = useState(false);

  const isErrorMail =
    errorsMail.wrongFormat || errorsMail.alreadyExists || errorsMail.noEntered;

  const isErrorPassword = errorsPassword.noEntered;

  const errorTextMail = () => {
    if (errorsMail.wrongFormat) {
      return lang.account.registration.stepOne.addressInvalid;
    }
    if (errorsMail.noEntered) {
      return lang.account.registration.stepOne.noMailEntered;
    }
    if (errorsMail.unknown !== undefined) {
      return errorsMail.unknown;
    }
  };

  const errorTextPassword = () => {
    if (errorsPassword.noEntered) {
      return lang.account.registration.stepFinal.passwordError.required;
    }
    if (errorsPassword.unknown !== undefined) {
      return errorsPassword.unknown;
    }
  };

  const [isLoading, setLoading] = useState(false);

  const [values, setValues] = useState({email: regPro.EMail, password: ''});

  const onButtonPress = () => {
    if (values.email === '') {
      let err = {...errorsMail};
      err.noEntered = true;
      setErrorsMail({...err});
    }
    if (values.password === '') {
      let err = {...errorsPassword};
      err.noEntered = true;
      setErrorsPassword({...err});
    } else if (validateEmail(values.email)) {
      setLoading(true);

      if (values.password.length < passwordOptions.minLength) {
        setTimeout(() => {
          setLoading(false);

          showToast(toast, {
            title: lang.account.login.wrongEmPw,
            variant: 'solid',
            status: 'error',
            description: undefined,
            isClosable: true,
            rest: {},
          });
        }, 1000);
        return;
      }

      let base64PW = Buffer.from(values.password).toString('base64');

      makeRequest({
        path: apiBackendRequest.LOGIN,
        requestHeader: {},
        request: {
          Email: values.email,
          Password: base64PW,
        },
        response: {
          XAuthorization: '',
          UserId: '',
          WebSocketSessionId: '',
        },
      })
        .then(resp => {
          setLoading(false);

          let accName = 'ga';
          let userName = 'ga';
          MyUserManager.createNewMyUser(
            resp.response.UserId,
            accName,
            userName,
            values.email,
            resp.response.XAuthorization,
            resp.response.WebSocketSessionId,
          )
            .then(() => {
              showToast(toast, {
                title: lang.account.login.success,
                variant: 'solid',
                status: 'success',
                description: undefined,
                isClosable: true,
                rest: {},
              });

              setLoading(false);
              navigation.goBack();
            })
            .catch(() => {
              setLoading(false);
              showToast(toast, {
                title: lang.account.login.failed,
                variant: 'solid',
                status: 'error',
                description: undefined,
                isClosable: true,
                rest: {},
              });
            });
        })
        .catch(resp => {
          setLoading(false);

          if (resp.status === 422) {
            showToast(toast, {
              title: lang.account.login.wrongEmPw,
              variant: 'solid',
              status: 'error',
              description: undefined,
              isClosable: true,
              rest: {},
            });
          } else {
            showToast(toast, {
              title: lang.error + ' ' + resp.status,
              variant: 'solid',
              status: 'error',
              description: undefined,
              isClosable: true,
              rest: {},
            });
          }
        });
    } else {
      let err = {...errorsMail};
      err.wrongFormat = true;
      setErrorsMail({...err});
    }
  };

  return (
    <ScrollView keyboardShouldPersistTaps="handled">
      <Box alignItems="center" mt={5}>
        <FormControl
          w="75%"
          maxW="350px"
          isRequired
          isDisabled={isLoading}
          isInvalid={isErrorMail}>
          <FormControl.Label>
            {lang.account.registration.stepOne.title}
          </FormControl.Label>
          <Input
            autoFocus
            autoComplete="email"
            placeholder={lang.account.registration.stepOne.title}
            value={values.email}
            onSubmitEditing={onButtonPress}
            autoCapitalize={'none'}
            maxLength={emailOptions.maxLength}
            keyboardType={'email-address'}
            onChangeText={text => {
              const mail = text.replaceAll(' ', '');
              let val = {...values};
              val.email = mail;
              setValues(val);

              if (errorsMail.noEntered && mail !== '') {
                let err = errorsMail;
                err.noEntered = false;
                setErrorsMail({...err});
              }
              if (errorsMail.wrongFormat && validateEmail(mail)) {
                let err = errorsMail;
                err.wrongFormat = false;
                setErrorsMail({...err});
              }
            }}
          />

          <FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
            {errorTextMail()}
          </FormControl.ErrorMessage>
        </FormControl>
        <FormControl
          marginBottom={5}
          w="75%"
          maxW="350px"
          isRequired
          isDisabled={isLoading}
          isInvalid={isErrorPassword}>
          <FormControl.Label>
            {lang.account.registration.stepFinal.password}
          </FormControl.Label>
          <Input
            autoFocus
            autoComplete="password"
            placeholder={lang.account.registration.stepFinal.password}
            value={values.password}
            onSubmitEditing={onButtonPress}
            autoCapitalize={'none'}
            maxLength={emailOptions.maxLength}
            type={showPassword === false ? 'password' : 'text'}
            keyboardType={
              showPassword === true ? 'visible-password' : undefined
            }
            InputRightElement={
              <IconButton
                mr="2"
                focusable={false}
                onPress={() => setShowPassword(!showPassword)}
                icon={
                  <MaterialIcons
                    size={20}
                    color={colors.white[200]}
                    name={showPassword ? 'visibility' : 'visibility-off'}
                  />
                }
                borderRadius="full"
              />
            }
            onChangeText={password => {
              let val = {...values};
              val.password = password;
              setValues(val);

              if (errorsPassword.noEntered && password !== '') {
                let err = errorsPassword;
                err.noEntered = false;
                setErrorsMail({...err});
              }
            }}
          />

          <FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
            {errorTextPassword()}
          </FormControl.ErrorMessage>
        </FormControl>
        <Button
          w="75%"
          maxW="350px"
          colorScheme="primary"
          rounded="xl"
          _text={{fontSize: 'xl'}}
          isLoading={isLoading}
          onPress={onButtonPress}>
          {lang.account.login.title}
        </Button>
      </Box>
    </ScrollView>
  );
}
