import React from 'react';
import { get } from '@theorchard/suite-utils';
import cx from 'classnames';
import { CLASS_NAME_OPTION, CLASS_NAME_OPTION_ICON, CLASS_NAME_OPTION_LABEL } from './constants';
import type { DropdownOption } from './types';
import type {
    OptionsOrGroups,
    GroupBase,
    OnChangeValue,
    PropsValue,
    MultiValue,
    SingleValue,
} from 'react-select';

export const defaultOptionLabelFormatter = (
    optionsOrGroups: OptionsOrGroups<DropdownOption, GroupBase<DropdownOption>> = []
) => {
    const hasGroups = optionsOrGroups.some((group) => get(group, 'options') !== undefined);
    const options = !hasGroups
        ? (optionsOrGroups as DropdownOption[])
        : optionsOrGroups.flatMap((group) => {
              if (typeof group === 'object' && 'options' in group) return group.options;
              return [group];
          });

    const DropdownOptionContent = (option: DropdownOption) => {
        const originalOption = options.find((item) => item.value === option.value);
        const { icon: Icon, label } = originalOption ?? option;

        if (Icon)
            return (
                <div className={cx(CLASS_NAME_OPTION, option.className)}>
                    <div className={CLASS_NAME_OPTION_ICON}>
                        {typeof Icon === 'function' ? <Icon /> : Icon}
                    </div>
                    <div className={CLASS_NAME_OPTION_LABEL}>{label}</div>
                </div>
            );

        return (
            <div className={cx(CLASS_NAME_OPTION, CLASS_NAME_OPTION_LABEL, option.className)}>
                {label ?? option.value}
            </div>
        );
    };

    return DropdownOptionContent;
};

export function getSelectedOptions<T extends DropdownOption>(
    selectedValue: string | string[] | undefined,
    options: OptionsOrGroups<T, GroupBase<T>> | undefined
): PropsValue<T> | undefined {
    if (!selectedValue || !options) return undefined;

    const selectedValues = Array.isArray(selectedValue) ? selectedValue : [selectedValue];

    const selectedOptions = selectedValues.reduce<T[]>((result, val) => {
        const match = options?.find((option) => 'value' in option && option.value === val);
        if (match && 'value' in match) return [...result, match];
        return result;
    }, []);

    return selectedOptions;
}

export function getNewValue<T extends DropdownOption, M extends boolean>(
    newValue: OnChangeValue<T, M>
): (M extends true ? string[] : string) | undefined {
    if (!newValue) return undefined;
    if ('value' in newValue) return newValue.value as M extends true ? string[] : string;
    return newValue.map((item) => item.value) as M extends true ? string[] : string;
}

export function getNewValueOption<T extends DropdownOption, M extends boolean>(
    newValue: OnChangeValue<T, M>
): (M extends true ? T[] : T) | undefined {
    if (!newValue) return undefined;
    if ('value' in newValue) return newValue as M extends true ? T[] : T;
    return newValue as M extends true ? T[] : T;
}

export function defaultHeaderLabelFormatter<T extends DropdownOption, M extends boolean>(
    value: M extends true ? MultiValue<T> : SingleValue<T>
) {
    return (!Array.isArray(value) ? [value] : value)[0].label;
}
