import { createRef, FC } from 'react';
import Head from 'next/head';
import HCaptcha from '@hcaptcha/react-hcaptcha';
import { FormValues, useFormValidation } from '../hooks/form/useFormValidation';
import { useMutation } from '@apollo/client';
import SignUpQuery from '../gql/mutations/SignUpQuery';
import { SignUpInput, SignUpType } from '../gql/generated/globalTypes';
import { buildSignUpType } from '../utils/SignUpUtils';
import nameValidator from '../utils/validators/nameValidator';
import emailValidator from '../utils/validators/emailValidator';
import domainValidator from '../utils/validators/domainValidator';
import newPasswordValidator from '../utils/validators/newPasswordValidator';
import confirmPasswordValidator from '../utils/validators/confirmPasswordValidator';
import requiredStringValidator from '../utils/validators/requiredStringValidator';
import SignUpForm from '../components/organisms/Forms/SignUpForm';
import LoggedOutSection from '../containers/global/LoggedOutSection';
import { SignUpFormProps, SignUpValues } from '../types/props/forms/SignUpFormProps';
import { logError } from '../utils/logUtils';
import { ComponentWithParams, ParamsLoader } from '../components/atoms/ParamsLoader';
import { clearAuthSession } from '../utils/authUtils';
import { SignUpUrlType } from '../types/props/SignUpTypes';
import LoggedOutSectionWithConfig from '../containers/global/LoggedOutSectionWithConfig';

type SignUpContentProps = {
    type?: string;
    email?: string;
    target?: string;
    inviteToken?: string;
};

const SignUpContent: FC<SignUpContentProps> = (props: SignUpContentProps) => {
    const { type, target, inviteToken, email: qsEmail } = props;

    const captcha = createRef<HCaptcha>();

    const [signup, { loading, data, error: gqlError }] = useMutation(SignUpQuery);

    const submitSignUp = async (signUpValues: SignUpValues) => {
        clearAuthSession();

        const email = qsEmail ?? signUpValues.email;

        const signUpType = buildSignUpType(type);

        const signUpInput: SignUpInput = {
            full_name: signUpValues.fullName,
            captcha_token: signUpValues.CAPTCHAToken,
            sign_up_type: signUpType,
            org_name: signUpType === SignUpType.INVITE ? target : signUpValues.orgName,
            ...(email !== undefined ? { email } : {}),
            ...(inviteToken !== undefined ? { invite_token: inviteToken } : {}),
            ...(signUpType === SignUpType.TAG_MANAGER ? { domain: signUpValues.domain } : {}),
            ...(signUpValues.newPassword !== '' ? { password: signUpValues.newPassword } : {}),
        };
        try {
            await signup({
                variables: { signUpInput },
            });
        } catch (error) {
            logError(error);
        }
    };

    const initialState = {
        newPassword: '',
        newPasswordConfirm: '',
        domain: '',
        orgName: '',
        fullName: '',
        email: '',
        CAPTCHAToken: '',
        agree: false,
    };

    const signupFormProps: SignUpFormProps = {
        ...useFormValidation<SignUpValues>(
            initialState,
            [
                {
                    field: 'fullName',
                    validator: nameValidator,
                    error: () => 'Name too short',
                },
                {
                    field: 'email',
                    validator: async <T extends FormValues>(
                        value: T[keyof T],
                    ): Promise<-1 | 0 | string> => {
                        if (value === '') return -1;
                        return emailValidator(value);
                    },
                    error: () => 'Invalid email address',
                },
                {
                    field: 'domain',
                    validator: async <T extends FormValues>(
                        value: T[keyof T],
                    ): Promise<-1 | 0 | string> => {
                        if (value === '') return -1;
                        return domainValidator(value);
                    },
                    error: () => 'Invalid domain',
                },
                {
                    field: 'orgName',
                    validator: async <T extends FormValues>(
                        value: T[keyof T],
                    ): Promise<-1 | 0 | string> => {
                        if (value === '') return -1;
                        return nameValidator(value);
                    },
                    error: () => 'Organization name too short',
                },
                {
                    field: 'agree',
                    validator: async <T extends FormValues>(
                        value: T[keyof T],
                    ): Promise<-1 | 0 | string> => {
                        return value ? -1 : 0;
                    },
                    error: () => 'You  must agree with the terms to create an account',
                },
                {
                    field: 'newPassword',
                    validator: async <T extends FormValues>(
                        value: T[keyof T],
                    ): Promise<-1 | 0 | string> => {
                        if (value === '') return -1;
                        return newPasswordValidator(value);
                    },
                    error: () => 'Password too short',
                },
                {
                    field: 'newPasswordConfirm',
                    validator: confirmPasswordValidator,
                    error: () => "Passwords don't Match",
                },
                {
                    field: 'CAPTCHAToken',
                    validator: requiredStringValidator,
                    error: () => 'Please prove that you are human',
                },
            ],
            submitSignUp,
            undefined,
            undefined,
            undefined,
            (values, setValues) => {
                if (captcha.current !== null) {
                    captcha.current.resetCaptcha();
                    setValues({
                        ...values,
                        CAPTCHAToken: '',
                    });
                }
            },
        ),
        gqlError,
        loading,
        submitText: 'Create Account',
        title: 'Sign Up',
        type: (type ?? 'tag-manager') as SignUpUrlType,
        target,
        qsEmail,
        captcha,
        success: data?.signUp !== undefined,
        email: data?.signUp.email,
        requestToken: data?.signUp.request_token,
        handleDialogClose: () => {
            // not in dialog
        },
    };

    return <SignUpForm {...signupFormProps} />;
};

const SignUp: ComponentWithParams = ({ params }) => {
    const { type, email, target, invite_token } = params;

    return (
        <>
            <Head>
                <title>Scale8 - Sign Up</title>
                <meta name="description" content="Scale8 - Sign Up page." />
            </Head>
            <LoggedOutSectionWithConfig>
                <SignUpContent
                    type={type}
                    email={email}
                    target={target}
                    inviteToken={invite_token}
                />
            </LoggedOutSectionWithConfig>
        </>
    );
};

const SignUpLoader = () => <ParamsLoader Child={SignUp} />;
export default SignUpLoader;
