import React, {FC, ReactNode, useEffect} from "react";
import {MultiSelectSearch} from "./MultiSelectSearch";
import {NumericOptions} from "../tiers";
import {Field} from "../cards";
import {findKey, map} from "lodash";
import {NumberInput, NumberInputProps} from "./NumberInput";
import {__} from "../../globals";
import {lastChanged, NumberFieldType} from "./LastChanged";
import {ToolTip} from "../../ToolTip";
import classNames from "classnames";
import ReactDOM from "react-dom";

export type NumberProps = Pick<NumberInputProps, 'type' | 'input' | 'size'> & {
    id?: string,
    fieldMeta: {
        type?: Field,
        amount?: Field,
        range?: {
            minimum: Field,
            maxmimum: Field,
        },
    },
    hasAmountStructure?: boolean, // basically whether the field is field.amount or just field
    value: Omit<NumericOptions, 'type'> & { type?: NumericOptions['type'] } | number,
    onChange: (fieldId: string, value: any) => void,
    labels?: {
        top?: string,z
        input?: NumberInputProps['labels'],
        // may add more placements in the future
    },
    border?: boolean,
    bottomNoticesPortalRef?: React.MutableRefObject<HTMLDivElement | null>,
    showSingleOption?: boolean,
    persistDefaultOnMount?: boolean
}

export const Number: FC<NumberProps> = ({
                                            id,
                                            fieldMeta = {} as NumberProps['fieldMeta'],
                                            value,
                                            onChange,
                                            type,
                                            labels,
                                            input,
                                            size,
                                            hasAmountStructure = true,
                                            border = true,
                                            bottomNoticesPortalRef,
                                            showSingleOption = true,
                                            persistDefaultOnMount = false
                                        }) => {

    const options = map(fieldMeta?.type?.meta?._allowed, (one, two) => ({id: one, value: one, label: two}))
    const numberType = typeof value === 'object' && value !== null
        ? (value as Omit<NumericOptions, 'type'> & { type?: NumericOptions['type'] }).type
        : undefined

    const change: typeof onChange = (field, newValue) => {
        let fieldType: NumberFieldType

        fieldType = field || 'amount'  //range.minimum || range.maxmimum

        lastChanged.numberId = id
        lastChanged.fieldType = fieldType

        onChange(field, newValue)
    }

    const getNumberDefaultValue = (): number => {
        const rawDefaultValue = hasAmountStructure
            ? fieldMeta?.amount?.meta?._default
            : (fieldMeta as unknown as { meta?: { _default?: unknown } })?.meta?._default;

        if (rawDefaultValue === '' || rawDefaultValue === null || typeof rawDefaultValue === 'undefined') {
            return 1;
        }

        const parsedDefaultValue = globalThis.Number(rawDefaultValue);

        return globalThis.Number.isFinite(parsedDefaultValue) ? parsedDefaultValue : 1;
    }

    const numberDefaultValue = getNumberDefaultValue();
    const numberValue = hasAmountStructure
        ? (value as Omit<NumericOptions, 'type'> & { amount?: unknown })?.amount
        : value;
    const hasNumberValue = typeof numberValue === 'number' && !globalThis.Number.isNaN(numberValue);
    const renderedNumberValue = (persistDefaultOnMount && numberType !== 'range' && !hasNumberValue)
        ? numberDefaultValue
        : (numberValue as number);

    useEffect(() => {
        if (!persistDefaultOnMount || numberType === 'range' || hasNumberValue) {
            return;
        }

        change(hasAmountStructure ? 'amount' : '', numberDefaultValue);
    }, [persistDefaultOnMount, numberType, hasNumberValue, hasAmountStructure, numberDefaultValue]);

    const selectedType = typeof value === 'object' && value !== null
        ? (value as Omit<NumericOptions, 'type'> & { type?: NumericOptions['type'] }).type
        : undefined;
    const floatingSelector = true;

    return <div className={'relative flex flex-col gap-2 items-center'}>
        {labels?.top && <span className={`text-gray-500 text-base`}>{labels.top}</span>}
        <div className={classNames('', {
            'absolute -bottom-1 translate-y-full': floatingSelector
        })}>
            {fieldMeta?.type?.meta?._allowed && (options.length === 1? showSingleOption : true) && <MultiSelectSearch size={'extra-small'}
                                                                 style={options.length > 1 ? 'gray-lighter' : 'transparent-gray'}
                                                                 options={options}
                                                                 selectedValue={
                                                                     options.find(({id}) => id === selectedType)
                                                                 }
                                                                 onSelectedValue={({id}) => {
                                                                     onChange('type', id)
                                                                 }}></MultiSelectSearch>}
        </div>
        <div
            className={classNames('inline-flex flex-col space-y-1 items-center --min-w-36 rounded-1 --fbg-white bg-opacity-30', {
                'hover:ring-[4px] hover:ring-gray-150 hover:ring-opacity-40 hover:ring-offset-[1px] ---ring-offset-transparent border-gray-150 border-[2px] py-1 px-1': border === true
            })}>
            {numberType !== 'range' && <NumberInput numberId={id!}
                                                    fieldType={'amount'}
                                                    value={renderedNumberValue}
                                                    onChange={value => change(hasAmountStructure ? 'amount' : '', value)}
                                                    type={type}
                                                    labels={labels?.input}
                                                    input={input}
                                                    size={size}
            />
            }
            {numberType === 'range' && <div className="flex items-center space-x-2">
                <div className="flex flex-col items-center space-y-1">
                    <NumberInput key="min" numberId={id!} fieldType={'range.minimum'} value={value.range.minimum}
                                 onChange={value => change('range.minimum', value)} type={type} size={size}/>
                    <span className="text-gray-500 text-smaller-1">{__('Minimum')}</span>
                </div>
                <div className="flex flex-col items-center space-y-1">
                    <NumberInput key="max" numberId={id!} fieldType={'range.maxmimum'} value={value.range.maxmimum}
                                 onChange={value => change('range.maxmimum', value)} type={type} size={size}/>
                    <span className="text-gray-500 text-smaller-1">{__('Maximum')}</span>
                </div>
            </div>}
        </div>
        {bottomNoticesPortalRef?.current && ReactDOM.createPortal(<div>
            {(fieldMeta?.type?.meta?.notes?.[selectedType || ''] as unknown as string[]) && (
                <ToolTip id={'note'} title={findKey(fieldMeta?.type?.meta?._allowed || {}, (type, label) => (
                    type === selectedType
                )) || ''} content={(fieldMeta?.type?.meta?.notes?.[selectedType || ''] as unknown as string[])}
                         style={'light'} width={'full'} animate={false}
                />
            )}
            {(fieldMeta?.meta?.notes as unknown as string[]) && fieldMeta?.meta?.notes?.map(note => (
                <ToolTip id={'note'}
                         content={[note]}
                         style={'light'} width={'full'} animate={false}
                />
            ))}
        </div>, bottomNoticesPortalRef?.current)}
    </div>
};
