import { Autocomplete, CircularProgress, Grid, TextField, Typography } from '@mui/material';
import debounce from 'lodash/debounce';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { fetchOrgCombo, getOrgOptionLabel } from 'utils/OrgComboUtils';
import { renderOrgOption } from 'components/OrgOptionLabel';

const SEARCH_DEBOUNCE_MS = 300;

export default function OrgComboAutocomplete({
    value,
    onChange,
    register,
    initialOrgId,
    initialOrgName,
    label = 'Organisation',
    size = 'small',
    sx,
    clearText,
    closeText,
    openText,
    noOptionsText,
}) {
    const [options, setOptions] = useState([]);
    const [inputValue, setInputValue] = useState('');
    const [loading, setLoading] = useState(false);
    const requestIdRef = useRef(0);
    const restoredRef = useRef(false);

    const runFetch = useCallback((query, id, onComplete) => {
        const requestId = ++requestIdRef.current;
        setLoading(true);

        fetchOrgCombo({
            query,
            id,
            onSuccess: (data) => {
                if (requestId !== requestIdRef.current) return;
                setOptions(data);
                onComplete?.(data);
            },
            onFinally: () => {
                if (requestId === requestIdRef.current) {
                    setLoading(false);
                }
            },
        });
    }, []);

    const debouncedSearch = useMemo(
        () => debounce((query) => runFetch(query), SEARCH_DEBOUNCE_MS),
        [runFetch]
    );

    useEffect(() => () => debouncedSearch.cancel(), [debouncedSearch]);

    useEffect(() => {
        setInputValue(value ? getOrgOptionLabel(value) : '');
    }, [value]);

    const onChangeRef = useRef(onChange);
    onChangeRef.current = onChange;

    useEffect(() => {
        if (restoredRef.current) return;
        if (!initialOrgId && !initialOrgName) return;

        restoredRef.current = true;

        if (initialOrgId) {
            runFetch(null, initialOrgId, (data) => {
                const org = data?.[0];
                if (org) {
                    onChangeRef.current(org);
                }
            });
        } else if (initialOrgName) {
            runFetch(initialOrgName, null, (data) => {
                const org = data?.find((item) => item.name === initialOrgName) ?? data?.[0];
                if (org) {
                    onChangeRef.current(org);
                }
            });
        }
    }, [initialOrgId, initialOrgName, runFetch]);

    const handleInputChange = (event, newInputValue, reason) => {
        setInputValue(newInputValue);

        if (reason === 'reset') {
            return;
        }

        debouncedSearch.cancel();

        if (!newInputValue.trim()) {
            requestIdRef.current += 1;
            setOptions([]);
            setLoading(false);
            return;
        }

        debouncedSearch(newInputValue);
    };

    return (
        <Autocomplete
            {...(register ? register('orgId') : {})}
            disablePortal
            id="orgId"
            options={options}
            groupBy={(option) => option.groupType}
            size={size}
            value={value ?? null}
            getOptionLabel={getOrgOptionLabel}
            filterOptions={(opts) => opts}
            renderOption={renderOrgOption}
            loading={loading}
            inputValue={inputValue}
            onInputChange={handleInputChange}
            onOpen={() => {
                if (inputValue.trim() && options.length === 0) {
                    runFetch(inputValue);
                }
            }}
            onChange={(event, newValue) => {
                onChange(newValue);
            }}
            sx={{
                '& .MuiInputBase-root': { alignItems: 'center' },
                '& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
                '& .MuiOutlinedInput-root': { height: 40 },
                ...sx,
            }}
            renderInput={(params) => (
                <TextField
                    {...params}
                    label={label}
                    InputLabelProps={{
                        shrink: true,
                    }}
                    InputProps={{
                        ...params.InputProps,
                        endAdornment: (
                            <>
                                {loading ? <CircularProgress color="inherit" size={18} /> : null}
                                {params.InputProps.endAdornment}
                            </>
                        ),
                    }}
                />
            )}
            renderGroup={(params) => (
                <Grid item key={params.key}>
                    <Typography fontSize={20} fontStyle="italic" p={1}>
                        {params.group}
                    </Typography>
                    {params.children}
                </Grid>
            )}
            clearText={clearText}
            closeText={closeText}
            openText={openText}
            noOptionsText={noOptionsText}
        />
    );
}
