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

import {FormControlLabel, Checkbox, Stack, Radio, RadioGroup, Typography} from "@mui/material";
import NumberTextField from "./NumberTextField";
import {azim_int_settings} from "../client";
import {putConfigAzimIntMutation} from "../client/@tanstack/react-query.gen";
import _ from "lodash";
import FormControl from "@mui/material/FormControl";
import SettingsPanel from "./SettingsPanel";
import {useUpload} from "./useUpload";

type MyProps = {
    s?: azim_int_settings
};

const default_azim_int_settings : azim_int_settings = {
    solid_angle_corr: true,
    polarization_corr: true,
    high_q_recipA: 5,
    low_q_recipA: 0.1,
    q_spacing: 0.1,
    azimuthal_bins: 1,
    force_cpu: false
}

function AzIntSettings({s: serverS}: MyProps) {
    const [s, setS] = useState<azim_int_settings>(default_azim_int_settings);
    const [lastDownloadedS, setLastDownloadedS] = useState<azim_int_settings>(default_azim_int_settings);
    const [downloadCounter, setDownloadCounter] = useState(0);
    const [lowQError, setLowQError] = useState(false);
    const [highQError, setHighQError] = useState(false);
    const [qSpacingError, setQSpacingError] = useState(false);
    const [highQ, setHighQ] = useState(5);
    const { submit, pending, snackbar } = useUpload(putConfigAzimIntMutation());

    useEffect(() => {
        if ((serverS !== undefined) && !_.isEqual(serverS, lastDownloadedS)) {
            setS(serverS);
            setLastDownloadedS(serverS);
            setDownloadCounter(c => c + 1);
            setHighQ(serverS.high_q_recipA ?? highQ);
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [serverS]);

    const dirty = !_.isEqual(s, lastDownloadedS);

    return (
        <SettingsPanel title="Azimuthal integration" dirty={dirty}
                       onUpload={() => submit(s)}
                       uploadDisabled={pending || ((s.high_q_recipA !== undefined) && (s.high_q_recipA <= s.low_q_recipA))
                           || highQError || lowQError || qSpacingError}
                       snackbar={snackbar}>
            <Stack spacing={2} direction="row">
                <NumberTextField
                    default={1.0}
                    start_val={s.q_spacing}
                    label={"Q spacing"}
                    min={1e-5}
                    units={"A-1"}
                    float={true}
                    decimals={5}
                    counter={downloadCounter}
                    callback={(val: number, err: boolean) => {
                        setS(prev => ({...prev, q_spacing: val}));
                        setQSpacingError(err);
                    }}
                    fullWidth/>

                <NumberTextField
                    default={0.1}
                    start_val={s.low_q_recipA}
                    label={"Low Q"}
                    min={1e-5}
                    max={10.0}
                    units={"A-1"}
                    float={true}
                    decimals={5}
                    counter={downloadCounter}
                    callback={(val: number, err: boolean) => {
                        setS(prev => ({...prev, low_q_recipA: val}));
                        setLowQError(err);
                    }}
                    fullWidth/>

                <NumberTextField
                    default={5}
                    start_val={s.high_q_recipA ?? highQ}
                    label={"High Q"}
                    min={1e-5}
                    max={10.0}
                    units={"A-1"}
                    float={true}
                    decimals={5}
                    counter={downloadCounter}
                    disabled={s.high_q_recipA === undefined}
                    callback={(val: number, err: boolean) => {
                        setHighQ(val);
                        setS(prev => ({...prev, high_q_recipA: val}));
                        setHighQError(err);
                    }}
                    fullWidth/>
            </Stack>
            <FormControl>
            <FormControlLabel control={
                <Checkbox
                    checked={s.high_q_recipA === undefined}
                    onChange={
                        (event: ChangeEvent<HTMLInputElement>) => {
                            // No high Q means integrating out to the highest Q the detector reaches.
                            setS(prev => event.target.checked ? _.omit(prev, "high_q_recipA")
                                                             : {...prev, high_q_recipA: highQ});
                        }}
                />} label="High Q to detector edge"/>
            <FormControlLabel control={
                <Checkbox
                    checked={s.solid_angle_corr}
                    onChange={
                        (event: ChangeEvent<HTMLInputElement>) => {
                            setS(prev => ({...prev, solid_angle_corr: event.target.checked}));
                        }}
                />} label="Solid angle correction"/>
            <FormControlLabel control={
                <Checkbox
                    checked={s.polarization_corr}
                    onChange={
                        (event: ChangeEvent<HTMLInputElement>) => {
                            setS(prev => ({...prev, polarization_corr: event.target.checked}));
                        }}
                />} label="Polarization correction"/>
                <FormControlLabel control={
                    <Checkbox
                        checked={s.force_cpu ?? false}
                        onChange={
                            (event: ChangeEvent<HTMLInputElement>) => {
                                setS(prev => ({...prev, force_cpu: event.target.checked}));
                            }}
                    />} label="Force CPU calculation in FPGA workflow"/>
            </FormControl>
            <Typography>Azimuthal bins</Typography>
            <FormControl component="fieldset">
                <RadioGroup
                    row
                    value={s.azimuthal_bins}
                    onChange={(event: ChangeEvent<HTMLInputElement>) => {
                        setS(prev => ({...prev, azimuthal_bins: Number(event.target.value)}));
                    }}
                >
                    {[1, 2, 4, 8, 16, 32, 64, 128].map((value) => (
                        <FormControlLabel
                            key={value}
                            value={value}
                            control={<Radio/>}
                            label={value.toString()}
                        />
                    ))}
                </RadioGroup>
            </FormControl>

        </SettingsPanel>
    );
}

export default memo(AzIntSettings);
