import React, { memo, useState } from 'react';
import { ServerEggVariable } from '@definitions/user';
import TitledGreyBox from '@/components/elements/TitledGreyBox';
import { usePermissions } from '@/plugins/usePermissions';
import InputSpinner from '@/components/elements/InputSpinner';
import Input from '@/components/elements/Input';
import Switch from '@/components/elements/Switch';
import tw from 'twin.macro';
import { debounce } from 'debounce';
import { updateStartupVariable } from '@/api/server';
import useFlash from '@/plugins/useFlash';
import FlashMessageRender from '@/components/FlashMessageRender';
import getServerStartup from '@/api/swr/getServerStartup';
import Select from '@/components/elements/Select';
import isEqual from 'react-fast-compare';
import { ServerContext } from '@/state/server';

interface Props {
    variable: ServerEggVariable;
}

const VariableBox = ({ variable }: Props) => {
    const FLASH_KEY = `server:startup:${variable.envVariable}`;

    const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
    const [ loading, setLoading ] = useState(false);
    const [ canEdit ] = usePermissions([ 'startup.update' ]);
    const { clearFlashes, clearAndAddHttpError } = useFlash();
    const { mutate } = getServerStartup(uuid);

    const setVariableValue = debounce((value: string) => {
        setLoading(true);
        clearFlashes(FLASH_KEY);

        updateStartupVariable(uuid, variable.envVariable, value)
            .then(([ response, invocation ]) => mutate(data => ({
                ...data!,
                invocation,
                variables: (data!.variables || []).map(v => v.envVariable === response.envVariable ? response : v),
            }), false))
            .catch(error => {
                console.error(error);
                clearAndAddHttpError({ key: FLASH_KEY, error });
            })
            .then(() => setLoading(false));
    }, 500);

    const useSwitch = variable.rules.some(v => v === 'boolean' || v === 'in:0,1');
    const selectValues = variable.rules.find(v => v.startsWith('in:'))?.split(',') || [];

    return (
        <TitledGreyBox
            title={
                <p css={tw`text-sm uppercase`}>
                    {!variable.isEditable &&
                    <span css={tw`bg-neutral-700 text-xs py-1 px-2 rounded-full mr-2 mb-1`}>Read Only</span>
                    }
                    {variable.name}
                </p>
            }
        >
            <FlashMessageRender byKey={FLASH_KEY} css={tw`mb-2 md:mb-4`}/>
            <InputSpinner visible={loading}>
                {useSwitch ?
                    <>
                        <Switch
                            readOnly={!canEdit || !variable.isEditable}
                            name={variable.envVariable}
                            defaultChecked={variable.serverValue === '1'}
                            onChange={() => {
                                if (canEdit && variable.isEditable) {
                                    setVariableValue(variable.serverValue === '1' ? '0' : '1');
                                }
                            }}
                        />
                    </>
                    :
                    <>
                        {selectValues.length > 0 ?
                            <>
                                <Select
                                    onChange={e => setVariableValue(e.target.value)}
                                    name={variable.envVariable}
                                    defaultValue={variable.serverValue}
                                    disabled={!canEdit || !variable.isEditable}
                                >
                                    {selectValues.map(selectValue => (
                                        <option key={selectValue.replace('in:', '')} value={selectValue.replace('in:', '')}>{selectValue.replace('in:', '')}</option>
                                    ))}
                                </Select>

                            </>
                            :
                            <>
                                <Input
                                    onKeyUp={e => {
                                        if (canEdit && variable.isEditable) {
                                            setVariableValue(e.currentTarget.value);
                                        }
                                    }}
                                    readOnly={!canEdit || !variable.isEditable}
                                    name={variable.envVariable}
                                    defaultValue={variable.serverValue}
                                    placeholder={variable.defaultValue}
                                />
                            </>
                        }
                    </>
                }
            </InputSpinner>
            <p css={tw`mt-1 text-xs text-neutral-300`}>
                {variable.description}
            </p>
        </TitledGreyBox>
    );
};

export default memo(VariableBox, isEqual);
