import {ChangeEvent, memo, useState} from 'react';

import Paper from '@mui/material/Paper';
import {Stack, TextField, Radio, RadioGroup, FormControlLabel, FormControl, Checkbox} from "@mui/material";
import NumberTextField from "./NumberTextField";
import {dataset_settings, grid_scan, rotation_axis} from "../client";
import ButtonWithSnackbar from "./ButtonWithSnackbar";

type MyProps = {
    frame_time_us: number
};

function DataCollection({frame_time_us}: MyProps) {
    const [s, setS] = useState<dataset_settings>(() => ({
        beam_x_pxl: 0,
        beam_y_pxl: 0,
        detector_distance_mm: 100,
        incident_energy_keV: 12.398,
        images_per_trigger: 1,
        image_time_us: frame_time_us,
        ntrigger: 1,
        images_per_file: 1000
    }));
    const [goniometer, setGoniometer] = useState<rotation_axis>({
        start: 0,
        step: 0.1,
        name: "omega",
        vector: [0,1,0]
    });
    const [grid, setGrid] = useState<grid_scan>({
        n_fast: 10,
        step_x_um: 10.0,
        step_y_um: 10.0,
        vertical: false,
        snake: false
    });
    const [beamXPxlErr, setBeamXPxlErr] = useState(false);
    const [beamYPxlErr, setBeamYPxlErr] = useState(false);
    const [detectorDistanceMmErr, setDetectorDistanceMmErr] = useState(false);
    const [incidentEnergyKevErr, setIncidentEnergyKevErr] = useState(false);
    const [imagesPerTriggerErr, setImagesPerTriggerErr] = useState(false);
    const [imageTimeUsErr, setImageTimeUsErr] = useState(false);
    const [ntriggerErr, setNtriggerErr] = useState(false);
    const [imagesPerFileErr, setImagesPerFileErr] = useState(false);
    const [mode, setMode] = useState<'still' | 'rotation' | 'grid'>('still');

    const error = () : boolean =>
        beamXPxlErr
        || beamYPxlErr
        || detectorDistanceMmErr
        || incidentEnergyKevErr
        || imageTimeUsErr
        || imagesPerTriggerErr
        || imagesPerFileErr
        || ntriggerErr;

    const getDatasetSettings = () : dataset_settings => {
        let d = {...s};
        if (mode === 'rotation')
            d.goniometer = goniometer;
        else if (mode === 'grid')
            d.grid_scan = grid;
        return d;
    };

    return <Paper style={{textAlign: 'center'}} sx={{ width: '100%'}}>
        <br/>
        <Stack spacing={5} sx={{
            justifyContent: "center",
            alignItems: "center",
        }}>
            <TextField label={"File prefix"}
                       variant="outlined"
                       onChange={
                           (event: ChangeEvent<HTMLInputElement>) => {
                               setS(prev => ({...prev, file_prefix: event.target.value}));
                           }
                       }
                       value={s.file_prefix}
                       sx={{width:"90%"}}
            />
            <Stack direction="row" spacing={2} sx={{width: '90%'}}>
                <NumberTextField
                    label={"Number of images per trigger"}
                    callback={(val: number, err: boolean) => {
                        setS(prev => ({...prev, images_per_trigger: val}));
                        setImagesPerTriggerErr(err);
                    }}
                    min={1}
                    default={s.images_per_trigger}
                />
                <NumberTextField
                    label={"Number of triggers"}
                    callback={(val: number, err: boolean) => {
                        setS(prev => ({...prev, ntrigger: val}));
                        setNtriggerErr(err);
                    }}
                    min={1}
                    default={s.ntrigger}
                />
                <NumberTextField
                    label={"Image time"}
                    callback={(val: number, err: boolean) => {
                        let image_time_us = Math.round(val * 1000.0);
                        setS(prev => ({...prev, image_time_us: image_time_us}));
                        setImageTimeUsErr(err);
                    }}
                    units={"ms"}
                    float={true}
                    min={0.01}
                    default={(s.image_time_us ?? 500) / 1000.0}
                />

                <NumberTextField
                    label={"Images per file"}
                    callback={(val: number, err: boolean) => {
                        setS(prev => ({...prev, images_per_file: val}));
                        setImagesPerFileErr(err);
                    }}
                    float={false}
                    min={1}
                    default={s.images_per_file}
                />
            </Stack>
            <Stack direction="row" spacing={2} sx={{width: '90%'}}>
                <NumberTextField
                    label={"Beam X [pxl]"}
                    callback={(val: number, err: boolean) => {
                        setS(prev => ({...prev, beam_x_pxl: val}));
                        setBeamXPxlErr(err);
                    }}
                    units={"pxl"}
                    float={true}
                    default={s.beam_x_pxl}
                />
                <NumberTextField
                    label={"Beam Y"}
                    callback={(val: number, err: boolean) => {
                        setS(prev => ({...prev, beam_y_pxl: val}));
                        setBeamYPxlErr(err);
                    }}
                    units={"pxl"}
                    float={true}
                    default={s.beam_y_pxl}
                />
                <NumberTextField
                    label={"Detector distance"}
                    callback={(val: number, err: boolean) => {
                        setS(prev => ({...prev, detector_distance_mm: val}));
                        setDetectorDistanceMmErr(err);
                    }}
                    units={"mm"}
                    min={0.1}
                    float={true}
                    default={s.detector_distance_mm}
                />
                <NumberTextField
                    label={"Energy"}
                    callback={(val: number, err: boolean) => {
                        setS(prev => ({...prev, incident_energy_keV: val}));
                        setIncidentEnergyKevErr(err);
                    }}
                    min={0.1}
                    max={500.0}
                    units={"keV"}
                    float={true}
                    default={s.incident_energy_keV}
                />



            </Stack>
            <FormControl sx={{width: '90%'}}>
                <RadioGroup
                    row
                    value={mode}
                    onChange={(event) => setMode(event.target.value as 'still' | 'rotation' | 'grid')}>
                    <FormControlLabel value="still" control={<Radio/>} label="Still"/>
                    <FormControlLabel value="rotation" control={<Radio/>} label="Rotation"/>
                    <FormControlLabel value="grid" control={<Radio/>} label="Grid scan"/>
                </RadioGroup>
            </FormControl>
            {mode === 'rotation' && (
                <Stack direction="row" spacing={2} sx={{width: '90%'}}>
                    <NumberTextField
                        label="Start angle"
                        callback={(val: number) => setGoniometer(prev => ({...prev, start: val}))}
                        units="°"
                        float={true}
                        default={goniometer.start}
                    />
                    <NumberTextField
                        label="Step"
                        callback={(val: number) => setGoniometer(prev => ({...prev, step: val}))}
                        units="°"
                        float={true}
                        min={0.001}
                        default={goniometer.step}
                    />
                    <TextField
                        label="Axis name"
                        value={goniometer.name}
                        onChange={(e) => setGoniometer(prev => ({...prev, name: e.target.value}))}
                    />
                </Stack>
            )}
            {mode === 'grid' && (
                <Stack direction="row" spacing={2} sx={{width: '90%'}}>
                    <NumberTextField
                        label="Grid elements (fast dim.)"
                        callback={(val: number) => setGrid(prev => ({...prev, n_fast: val}))}
                        min={1}
                        default={grid.n_fast}
                    />
                    <NumberTextField
                        label="X step"
                        callback={(val: number) => setGrid(prev => ({...prev, step_x_um: val}))}
                        units="μm"
                        float={true}
                        default={grid.step_x_um}
                    />
                    <NumberTextField
                        label="Y step"
                        callback={(val: number) => setGrid(prev => ({...prev, step_y_um: val}))}
                        units="μm"
                        float={true}
                        default={grid.step_y_um}
                    />
                    <FormControlLabel
                        control={
                            <Checkbox
                                checked={grid.snake}
                                onChange={(e) => setGrid(prev => ({...prev, snake: e.target.checked}))}
                            />
                        }
                        label="Snake scan"
                    />
                    <FormControlLabel
                        control={
                            <Checkbox
                                checked={grid.vertical}
                                onChange={(e) => setGrid(prev => ({...prev, vertical: e.target.checked}))}
                            />
                        }
                        label="Vertical scan"
                    />
                </Stack>
            )}

            <Stack direction="row" spacing={2}>
                <ButtonWithSnackbar
                    path={"/start"}
                    text={"start"}
                    disabled={error()}
                    input={JSON.stringify(getDatasetSettings())}
                    color={"primary"}
                />
                <ButtonWithSnackbar
                    path={"/trigger"}
                    text={"soft trigger"}
                    disabled={error()}
                    color={"primary"}
                />
            </Stack>
        </Stack>
        <br/>
    </Paper>
}

export default memo(DataCollection);
