import React, {useState} from "react";
import './GenericForm.css';
import {useNavigate} from 'react-router-dom'
import {ErrorMessage, Field, Form, Formik, FormikValues} from "formik";
import {Step, UserInput, FormData} from './formInterfaces';
import * as Yup from "yup";

const GenericForm = (formData: FormData) => {
    const steps: Step[] = formData.steps;
    const backend: string = formData.backend;
    const userInput: UserInput = formData.userInput;
    const spec: Yup.Schema<any> = formData.spec;

    const navigate = useNavigate();

    const [currentStep, setCurrentStep] = useState<number>(0);

    const handleSubmit = async (formikValues: FormikValues) => {
        try {
            const response = await fetch(backend, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(formikValues)
            })
            if (!response.ok) {
                let json: string = JSON.stringify(formikValues);
                const blob = new Blob([json], {type: "application/json"});
                const url = URL.createObjectURL(blob);

                const link = document.createElement('a');
                link.href = url;
                link.download = 'your_form_data.json';
                link.click();
                URL.revokeObjectURL(url);
                //TODO clean up
                alert("Your form submission was denied by the server, or the server was unable to process it, if you didn't mess with the data please contact the administrator at admin@alttd.com");
            } else {
                navigate('/verify-email', {
                    state: {
                        email: formikValues['email']
                    }
                });
            }
        } catch (e) {
            alert("Your form submission was denied by the server, if you didn't mess with the data please contact the administrator at admin@alttd.com")
        }
    };

    const next = () => {
        setCurrentStep(current => current + 1)
    }

    const prev = () => {
        setCurrentStep(current => Math.max(current - 1, 0))
    }

    const [prevLength, setPrevLength] = useState(0);
    return (
        <div className="container">
            <div>
                <h1>{formData.title}</h1>
            </div>
            <div>
                <Formik
                    initialValues={userInput}
                    validationSchema={spec}
                    onSubmit={(values: FormikValues) => {
                        handleSubmit(values);
                    }}
                >
                    {({
                          touched,
                          errors,
                          isValid,
                          handleChange,
                          values,
                          setFieldTouched
                      }) => (

                        <Form>
                            <div>
                                <label>
                                    {steps[currentStep].label}
                                    <Field
                                        type={steps[currentStep].type}
                                        name={steps[currentStep].name}
                                        required={steps[currentStep].required}
                                        min={steps[currentStep].min_length}
                                        max={steps[currentStep].max_length}
                                        as={(steps[currentStep].type === "textarea") ? "textarea" : "input"}
                                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                                            handleChange(e);
                                            if (prevLength !== values[steps[currentStep].name].length) {
                                                setFieldTouched(steps[currentStep].name);
                                                setPrevLength(values[steps[currentStep].name].length);
                                            }
                                        }}
                                    />
                                    <ErrorMessage name={steps[currentStep].name} component="div"/>
                                </label>
                            </div>
                            <button type="button" onClick={prev} disabled={currentStep === 0}>
                                Previous
                            </button>
                            <button type="button" onClick={next}
                                    hidden={currentStep === (steps.length - 1)}
                                    disabled={(!touched[steps[currentStep].name] || !!errors[steps[currentStep].name]) || currentStep === (steps.length - 1)}>
                                Next
                            </button>
                            <input type="submit" value="Submit"
                                   hidden={currentStep !== (steps.length - 1)}
                                   disabled={!isValid || currentStep !== (steps.length - 1)}
                            />
                        </Form>
                    )}
                </Formik>
            </div>
        </div>
    );
};

export default GenericForm;