import React from "react";
import { emptyReport, sampleReportSchema } from "@/provider/dummy/report";
import {
    Button,
    FormControl,
    FormLabel,
    Grid,
    Typography,
    FormGroup,
    FormControlLabel,
    Checkbox,
    Radio,
    InputLabel,
    Select,
    MenuItem
} from "@material-ui/core";
import { Actions } from "@/components";
import { Link as RouterLink } from "react-router-dom";
import { route } from "@/routing";
import { useTranslation } from "react-i18next";
import { MultiChoiceFieldDefinition, Report, ReportFieldDefinition, ReportFieldValues, SingleChoiceFieldDefinition } from "@/data/report";
import { TextField as TextFieldFormik } from "formik-material-ui";
import { Field, Form, Formik, useFormik, useFormikContext } from "formik";
import { Multilingual } from "@/data";
import { Transformer } from "@/serialization";
import api from "@/api";

export type ReportFieldProps<TField = ReportFieldDefinition> = {
    field: TField;
}

export const name = ({ id }: ReportFieldDefinition) => `field_${id}`;

export const CustomField = ({ field, ...props }: ReportFieldProps) => {
    switch (field.type) {
        case "short-text":
        case "long-text":
            return <CustomField.Text {...props} field={ field } />
        case "checkbox":
        case "radio":
            return <CustomField.Choice {...props} field={ field }/>
        case "select":
            return <CustomField.Select {...props} field={ field }/>
    }
}

CustomField.Text = ({ field }: ReportFieldProps) => {
    return <>
        <Field label={ field.label.pl } name={ name(field) }
               fullWidth
               rows={ field.type == "long-text" ? 4 : 1 }
               multiline={ field.type == "long-text" }
               component={ TextFieldFormik }
        />
        <Typography variant="caption" color="textSecondary" dangerouslySetInnerHTML={{ __html: field.description.pl }}/>
    </>
}

CustomField.Select = ({ field }: ReportFieldProps<SingleChoiceFieldDefinition>) => {
    const { t } = useTranslation();
    const id = `custom-field-${field.id}`;
    const { values, setFieldValue } = useFormikContext<any>();

    const value = values[name(field)];

    return <FormControl variant="outlined">
        <InputLabel htmlFor={id}>{ field.label.pl }</InputLabel>
        <Select label={ field.label.pl } name={ name(field) } id={id} value={ value } onChange={ ({ target }) => setFieldValue(name(field), target.value, false) }>
            { field.choices.map(choice => <MenuItem value={ choice as any }>{ choice.pl }</MenuItem>) }
        </Select>
        <Typography variant="caption" color="textSecondary" dangerouslySetInnerHTML={{ __html: field.description.pl }}/>
    </FormControl>
}

CustomField.Choice = ({ field }: ReportFieldProps<SingleChoiceFieldDefinition | MultiChoiceFieldDefinition>) => {
    const { t } = useTranslation();
    const { values, setFieldValue } = useFormikContext<any>();

    const value = values[name(field)];

    const isSelected = field.type == 'radio'
        ? (checked: Multilingual<string>) => value == checked
        : (checked: Multilingual<string>) => (value || []).includes(checked)

    const handleChange = field.type == 'radio'
        ? (choice: Multilingual<string>) => () => setFieldValue(name(field), choice, false)
        : (choice: Multilingual<string>) => () => {
            const current = value || [];
            setFieldValue(name(field), !current.includes(choice) ? [ ...current, choice ] : current.filter((c: Multilingual<string>) => c != choice), false);
        }

    const Component = field.type == 'radio' ? Radio : Checkbox;

    return <FormControl component="fieldset">
        <FormLabel component="legend">{ field.label.pl }</FormLabel>
        <FormGroup>
            { field.choices.map(choice => <FormControlLabel
                control={ <Component checked={ isSelected(choice) } onChange={ handleChange(choice) }/> }
                label={ choice.pl }
            />) }
        </FormGroup>
        <Typography variant="caption" color="textSecondary" dangerouslySetInnerHTML={{ __html: field.description.pl }}/>
    </FormControl>
}

export type ReportFormValues = ReportFieldValues;

const reportFormValuesTransformer: Transformer<Report, ReportFormValues, { report: Report }> = {
    reverseTransform(subject: ReportFormValues, context: { report: Report }): Report {
        return { ...context.report, fields: subject };
    },
    transform(subject: Report, context: undefined): ReportFormValues {
        return subject.fields;
    }
}

export default function ReportForm() {
    const report = emptyReport;
    const schema = sampleReportSchema;
    const { t } = useTranslation();

    const handleSubmit = async (values: ReportFormValues) => {
        const result = reportFormValuesTransformer.reverseTransform(values);
        await api.report.save(result);
    };

    return <Formik initialValues={ reportFormValuesTransformer.transform(report) } onSubmit={ handleSubmit }>
        { ({ submitForm }) => <Form>
            <Grid container>
                <Grid item xs={12}>
                    <Typography variant="body1" component="p">{ t('forms.report.instructions') }</Typography>
                </Grid>
                { schema.map(field => <Grid item xs={12}><CustomField field={ field }/></Grid>) }
                <Grid item xs={12}>
                    <Actions>
                        <Button variant="contained" color="primary" onClick={ submitForm }>
                            { t('confirm') }
                        </Button>

                        <Button component={ RouterLink } to={ route("home") }>
                            { t('go-back') }
                        </Button>
                    </Actions>
                </Grid>
            </Grid>
        </Form> }
    </Formik>
}

