import { Student } from "@/data";
import { Transformer } from "@/serialization";
import React, { useMemo } from "react";
import { Field, Formik, useFormikContext } from "formik";
import api from "@/api";
import { Button, Grid, Typography } from "@material-ui/core";
import { TextField as TextFieldFormik } from "formik-material-ui";
import { useTranslation } from "react-i18next";
import { Actions } from "@/components";
import { Nullable } from "@/helpers";
import * as Yup from "yup";
import { StudentActions, useDispatch } from "@/state/actions";

interface StudentFormValues {
    firstName: string;
    lastName: string;
    email: string;
    albumNumber: number | "";
    semester: number | "";
}

type StudentFormProps = {
    student: Student;
}

const studentToFormValuesTransformer: Transformer<Nullable<Student>, StudentFormValues, { current: Student }> = {
    transform(subject: Nullable<Student>, context: { current: Student }): StudentFormValues {
        return {
            firstName: subject.name || "",
            lastName: subject.surname || "",
            albumNumber: subject.albumNumber || "",
            semester: subject.semester || "",
            email: subject.email || "",
        };
    },
    reverseTransform(subject: StudentFormValues, { current }: { current: Student }): Nullable<Student> {
        return {
            ...current,
            name: subject.firstName,
            surname: subject.lastName,
            albumNumber: subject.albumNumber ? subject.albumNumber : null,
            semester: subject.semester ? subject.semester : null,
            email: subject.email,
        };
    },
}

export const StudentForm = ({ student }: StudentFormProps) => {
    const { t } = useTranslation();
    const dispatch = useDispatch();

    const validationSchema = useMemo(() => Yup.object<StudentFormValues>({
        semester: Yup.number().required().min(1).max(10),
        albumNumber: Yup.number().required(),
        email: Yup.string().required(),
        firstName: Yup.string().required(),
        lastName: Yup.string().required(),
    }), []);

    const initialValues: StudentFormValues = useMemo(
        () => studentToFormValuesTransformer.transform(student, { current: student }),
        [ student ]
    )


    const handleFormSubmit = async (values: StudentFormValues) => {
        const update = studentToFormValuesTransformer.reverseTransform(values, { current: student }) as Student;
        const updated = await api.student.update(update);

        dispatch({
            type: StudentActions.Set,
            student: updated,
        })
    }


    const InnerForm = () => {
        const { handleSubmit } = useFormikContext();

        return <form onSubmit={ handleSubmit }>
            <Typography variant="subtitle1">{ t("forms.student.sections.personal") }</Typography>
            <Grid container>
                <Grid item md={ 6 }>
                    <Field component={ TextFieldFormik }
                           name="firstName"
                           label={ t("forms.student.fields.first-name") }
                           fullWidth
                    />
                </Grid>
                <Grid item md={ 6 }>
                    <Field component={ TextFieldFormik }
                           name="lastName"
                           label={ t("forms.student.fields.last-name") }
                           fullWidth
                    />
                </Grid>
                <Grid item>
                    <Field component={ TextFieldFormik }
                           name="email"
                           label={ t("forms.student.fields.email") }
                           fullWidth
                    />
                </Grid>
            </Grid>
            <Typography variant="subtitle1">{ t("forms.student.sections.studies")}</Typography>
            <Grid container>
                <Grid item md={ 6 }>
                    <Field component={ TextFieldFormik }
                           name="albumNumber"
                           label={ t("forms.student.fields.album-number") }
                           fullWidth
                    />
                </Grid>
                <Grid item md={ 6 }>
                    <Field component={ TextFieldFormik }
                           name="semester"
                           label={ t("forms.student.fields.semester") }
                           fullWidth
                    />
                </Grid>
            </Grid>
            <Actions>
                <Button variant="contained" type="submit" color="primary">{ t("save") }</Button>
            </Actions>
        </form>
    }

    return <Formik initialValues={ initialValues } onSubmit={ handleFormSubmit } validationSchema={ validationSchema }>
        <InnerForm />
    </Formik>
}

export default StudentForm;
