import { Component, SyntheticEvent, ReactNode, FC } from 'react';

import { TableFilterCellProps, Checkbox } from '@servicetitan/design-system';

import {
    CustomColumnMenuFilterSingleOpts,
    renderCustomColumnMenuFilter,
} from '../column-menu-filters';

interface SelectorProps<T> {
    options: T[];
    value?: T[];
    onChange(value: T[] | undefined, event: SyntheticEvent<HTMLInputElement>): void;
    renderer?(item: T): ReactNode;
}

class Selector<T> extends Component<SelectorProps<T>> {
    handleChange = (option: T, checked: boolean, event: SyntheticEvent<HTMLInputElement>) => {
        const newValue = checked
            ? (this.props.value ?? []).concat(option)
            : (this.props.value ?? []).filter(v => v !== option);

        this.props.onChange(newValue.length ? newValue : undefined, event);
    };

    render() {
        const { options, value, renderer } = this.props;

        return options.map((option, index) => (
            // eslint-disable-next-line react/no-array-index-key
            <span key={index} className="k-widget m-b-1-i d-b">
                <Checkbox
                    value={option}
                    label={renderer ? renderer(option) : option}
                    checked={(value ?? []).includes(option)}
                    onChange={this.handleChange}
                />
            </span>
        ));
    }
}

export function multiSelectColumnMenuFilter<T>(
    data: T[],
    renderItem?: (item: T) => ReactNode,
    opts?: CustomColumnMenuFilterSingleOpts
) {
    const FilterCell: FC<TableFilterCellProps> = ({ value, onChange }) => {
        const handleChange = (value: T[] | undefined, event: SyntheticEvent<HTMLInputElement>) => {
            onChange({
                value: value ?? '',
                operator: value ? 'in' : '',
                syntheticEvent: event,
            });
        };

        return (
            <Selector
                options={data}
                value={value === '' ? undefined : value}
                onChange={handleChange}
                renderer={renderItem}
            />
        );
    };

    return renderCustomColumnMenuFilter(FilterCell, opts);
}

export function complexItemMultiSelectColumnMenuFilter<T>(
    data: T[],
    renderItem?: (item: T) => ReactNode,
    opts?: CustomColumnMenuFilterSingleOpts
) {
    class FilterCell extends Component<TableFilterCellProps> {
        contains = (item: any) => {
            const value: T[] = this.props.value || [];

            return value.some((v: T) => item[v] === true);
        };

        handleChange = (value: T[] | undefined, event: SyntheticEvent<HTMLInputElement>) => {
            this.props.onChange({
                value: value ?? '',
                operator: value ? this.contains : '',
                syntheticEvent: event,
            });
        };

        render() {
            const { value } = this.props;

            return (
                <Selector
                    options={data}
                    value={value === '' ? undefined : value}
                    onChange={this.handleChange}
                    renderer={renderItem}
                />
            );
        }
    }

    return renderCustomColumnMenuFilter(FilterCell, opts);
}

export function multiItemMultiSelectColumnMenuFilter<T>(
    data: T[],
    renderItem?: (item: T) => ReactNode,
    opts?: CustomColumnMenuFilterSingleOpts
) {
    class FilterCell extends Component<TableFilterCellProps> {
        contains = (item: any) => {
            const value: T[] = this.props.value || [];

            return value.some((v: T) => Array.isArray(item) && item.includes(v));
        };

        handleChange = (value: T[] | undefined, event: SyntheticEvent<HTMLInputElement>) => {
            this.props.onChange({
                value: value ?? '',
                operator: value ? this.contains : '',
                syntheticEvent: event,
            });
        };

        render() {
            const { value } = this.props;

            return (
                <Selector
                    options={data}
                    value={value === '' ? undefined : value}
                    onChange={this.handleChange}
                    renderer={renderItem}
                />
            );
        }
    }

    return renderCustomColumnMenuFilter(FilterCell, opts);
}
