import PropTypes from 'prop-types';

import {highlight} from '../utils';
import {CommonList} from '../common/CommonList';
import {LocalStorage} from '../../../data/LocalStorage';

import {Store} from '../../../data/Store';

export type ListProps<R> = {
    isBlocked?: boolean;
    noResultsText?: string;
    blockedText?: string;
    store: Store<R>;
} & Partial<ListDefaultProps>;

export type ListDefaultProps = {
    isBlocked: boolean;
    noResultsText: string;
    blockedText: string;
};

export type ListState<R> = {
    rows: R[];
};

export abstract class List<
    P extends ListProps<R>,
    S extends ListState<R>,
    R = any
> extends CommonList<P, S> {
    static childContextTypes = {
        listStore: PropTypes.object,
        localStorage: PropTypes.instanceOf(LocalStorage)
    };

    static propTypes = {
        ...CommonList.propTypes,
        store: PropTypes.object.isRequired
    };

    constructor(props, context) {
        super(props, context);

        this.renderItem = this.renderItem.bind(this);
        this.onStoreChange = this.onStoreChange.bind(this);

        this.state = {
            rows: this.props.store.getData()
        } as any;

        this._context = {
            listStore: this.props.store,
            localStorage: new LocalStorage(this.props.store.stateName || 'List')
        };
    }

    _context: any;
    unmounted: any;

    getChildContext() {
        return this._context;
    }

    componentDidMount() {
        this.props.store.onChange(this.onStoreChange);
    }

    componentWillUnmount() {
        this.unmounted = true;
        this.props.store.off('change', this.onStoreChange);
    }

    onStoreChange(data) {
        if (this.unmounted) {
            return;
        }
        this.setState({rows: data});
    }

    highlight(text) {
        return highlight(this.props.store.textFilterPattern, text);
    }

    getDetails() {
        return {
            sortingDirection: this.props.store.getSortingDirection(),
            highlight: this.highlight.bind(this)
        };
    }

    hasItems() {
        return this.props.store.getFilteredCount() > 0;
    }

    isEmptyList() {
        return (
            this.props.store.isLoaded() &&
            !this.props.store.hasFilters() &&
            !this.props.store.getTotalCount()
        );
    }

    isEmptyListMessageVisible() {
        return this.props.store.isLoaded() && !this.hasItems();
    }

    renderItems() {
        return this.state.rows.map(this.renderItem);
    }
}
