import React from 'react';
import { ContentRect, default as Measure } from 'react-measure';
import { VariableSizeList } from 'react-window';

import classNames from 'classnames';

import { formatDexNumber } from 'app/utils/formatter';

import { IPokemon } from 'app/models/Pokemon';

import * as styles from './styles/PokemonSelectList.scss';

export interface IPokemonSelectListProps {
    isLoading : boolean;
    activePokemonId : string | null;
    pokemonList : Array<IPokemon>;
    filterTerm : string;

    handleActivatePokemon : (pokemonId : string) => void;
    handleChangeFilter : (filterTerm : string) => Promise<void>;
}

interface IState {
    dimensions : {
        width : number;
        height : number;
    };
}

interface IRowFactory {
    index : number;
    style : React.CSSProperties;
}

export class PokemonSelectList extends React.Component<IPokemonSelectListProps, IState> {
    private listRef : React.RefObject<VariableSizeList>;

    constructor(props : IPokemonSelectListProps) {
        super(props);

        this.state = {
            dimensions: {
                width: -1,
                height: -1,
            }
        };

        this.listRef = React.createRef();
    }

    public render() {
        const { width, height } = this.state.dimensions;
        const listLength = this.props.pokemonList.length;

        const onResize = (contentRect : ContentRect) => {
            if (typeof contentRect.bounds !== 'undefined') {
                this.setState({ dimensions: contentRect.bounds });
            }
        };
        const wrapperCss = classNames(
            styles.leftPanel,
            {
                loading: this.props.isLoading,
            }
        );
        const listWrapperCss = classNames(
            'nes-container',
            styles.listWrapper,
            {
                [ styles.emptyList ]: listLength === 0
            }
        );
        const inputTextCss = classNames(
            'nes-input',
            styles.filterInput
        );

        return (
            <div id="pokemon-select-list" className={ wrapperCss }>
                <input
                    name="filter"
                    type="text"
                    className={ inputTextCss }
                    onChange={ this.handleChangeFilter }
                    value={ this.props.filterTerm }
                    placeholder="Pokemon Name"
                />
                <div className={ listWrapperCss }>
                    { listLength > 0 &&
                        <Measure
                            bounds={ true }
                            onResize={ onResize }
                        >
                            {
                                ({ measureRef }) => (
                                    <div ref={ measureRef }>
                                        <VariableSizeList
                                            ref={ this.listRef }
                                            height={ height }
                                            itemKey={ this.getListItemKey }
                                            itemCount={ listLength }
                                            estimatedItemSize={ 25 }
                                            itemSize={ this.calculateRowHeight }
                                            width={ width }
                                        >
                                            { this.rowFactory.bind(this) }
                                        </VariableSizeList>
                                    </div>
                                )
                            }
                        </Measure>
                    }
                    { listLength === 0 &&
                        <div className={ styles.emptyState }>
                            <i className="pokemon-missing-no" />
                            <h3>MissingNo.</h3>
                        </div>
                    }
                </div>
            </div>
        );
    }

    private readonly getListItemKey = (index : number) => {
        return index + this.props.pokemonList[index].id;
    }

    private readonly calculateRowHeight = (index : number) => {
        return this.props.pokemonList[index].form !== null ? 40 : 25;
    }

    private rowFactory({ index, style } : IRowFactory) {
        const pokemon = this.props.pokemonList[index];
        const dex = formatDexNumber(pokemon.dex);
        const anchorCss = classNames(
            'list-item',
            {
                active: this.props.activePokemonId === pokemon.id
            }
        );
        const dexCss = classNames(
            'de-emphasize',
            styles.dex
        );
        const formCss = classNames(
            'de-emphasize',
            styles.form
        );
        const onClick = () => this.props.handleActivatePokemon(pokemon.id);
        return (
            <a
                key={ index + pokemon.id }
                style={ style }
                className={ anchorCss }
                onClick={ onClick }
            >
                <span>{ pokemon.name }</span>
                <span className={ dexCss }>#{ dex }</span>
                { pokemon.form &&
                    <span className={ formCss }>{ pokemon.form.toLowerCase().replace('_', ' ') } Forme</span>
                }
            </a>
        );
    }

    private readonly handleChangeFilter = (event : React.ChangeEvent<HTMLInputElement>) => {
        this.props.handleChangeFilter(event.currentTarget.value)
        .then(() => {
            if (this.listRef.current !== null) {
                this.listRef.current.resetAfterIndex(0, true);
            }
        });
    }
}
