import POGOProtos from 'pogo-protos';

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

import classNames from 'classnames';

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

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

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

export interface IPokemonSelectListProps {
    isLoading : boolean;
    activePokemonId : POGOProtos.Enums.PokemonId | null;
    activePokemonForm : POGOProtos.Enums.Form | null;
    pokemonList : Array<IPokemon>;
    filterTerm : string;

    handleActivatePokemon : (pokemonId : POGOProtos.Enums.PokemonId, form : POGOProtos.Enums.Form) => 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 }>
                <div className={ styles.filterWrapper }>
                    <input
                        name="filter"
                        type="text"
                        className={ inputTextCss }
                        onChange={ this.handleChangeFilter }
                        value={ this.props.filterTerm }
                        placeholder="Search"
                    />
                    { this.props.filterTerm !== '' &&
                        <i
                            className="nes-icon close is-small"
                            onClick={ this.handleClickClearFilter }
                        />
                    }
                </div>
                <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 && this.props.filterTerm !== '' &&
                        <div className={ styles.emptyState }>
                            <i className="pokemon-missing-no" />
                            <h3>{ DEFAULT_POKEMON_NAME }</h3>
                        </div>
                    }
                </div>
            </div>
        );
    }

    private readonly getListItemKey = (index : number) => {
        const { pokemonList } = this.props;
        const pokemon = pokemonList[index];
        return `${index}-${pokemon.id}-${pokemon.form}`;
    }

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

    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 && this.props.activePokemonForm === pokemon.form
            }
        );
        const dexCss = classNames(
            'de-emphasize',
            styles.dex
        );
        const formCss = classNames(
            'de-emphasize',
            styles.form
        );
        const onClick = () => this.props.handleActivatePokemon(pokemon.id, pokemon.form);
        return (
            <a
                key={ this.getListItemKey(index) }
                style={ style }
                className={ anchorCss }
                onClick={ onClick }
            >
                <span>{ pokemon.name }</span>
                <span className={ dexCss }>#{ dex }</span>
                { pokemon.form !== POGOProtos.Enums.Form.FORM_UNSET &&
                    <span className={ formCss }>{ formatForm(pokemon.form) } Form</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);
            }
        });
    }

    private readonly handleClickClearFilter = () => {
        this.props.handleChangeFilter('')
        .then(() => {
            if (this.listRef.current !== null) {
                this.listRef.current.resetAfterIndex(0, true);
            }
        });
    }
}
