import POGOProtos from 'pogo-protos';

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

import classNames from 'classnames';

import { Grade, IStats } from 'app/models/Pokemon';
import { IIndividualValues } from './types';

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

export interface ILeagueStatsListProps {
    activePokemonId : POGOProtos.Enums.PokemonId;
    activePokemonForm : POGOProtos.Enums.Form | null;
    activeIndividualValues : IIndividualValues;
    leagueStatsList : Array<IStats>;

    handleActivateLeagueStats : (stats : IStats) => void;
}

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

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

export class LeagueStatsList extends React.Component<ILeagueStatsListProps, IState> {
    private listRef : React.RefObject<FixedSizeList>;

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

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

        this.listRef = React.createRef();
    }

    public componentWillReceiveProps(nextProps : ILeagueStatsListProps) {
        const activeIvs = nextProps.activeIndividualValues;
        if (nextProps.activePokemonId !== this.props.activePokemonId || nextProps.activePokemonForm !== this.props.activePokemonForm) {
            this.setState({ activeIndex: -1 });
            if (this.listRef.current !== null) {
                this.listRef.current.scrollToItem(0);
            }
        } else if (activeIvs.level !== null && activeIvs.hp !== null && activeIvs.atk !== null && activeIvs.def !== null) {
            let activeIndex = this.state.activeIndex;
            if (activeIndex === -1) {
                // there is no current index, wich means the user is entering in the IVs by hand
                // now we will look through the list to see if we can find a match
                this.props.leagueStatsList.some((stats, index) => {
                    if (activeIvs.hp === stats.ivHp &&
                        activeIvs.atk === stats.ivAtk &&
                        activeIvs.def === stats.ivDef
                    ) {
                        this.setState({ activeIndex: index });
                        activeIndex = index;
                        return true;
                    }
                    return false;
                });
            }

            if (activeIndex > -1) {
                const stateStats = this.props.leagueStatsList[activeIndex];
                if (activeIvs.hp === stateStats.ivHp && activeIvs.atk === stateStats.ivAtk && activeIvs.def === stateStats.ivDef) {
                    // the current IVs belong to the stats at the active index, so scroll to active stats
                    if (this.listRef.current !== null) {
                        this.listRef.current.scrollToItem(activeIndex, 'center');
                    }
                } else {
                    // the current IVs have changed since we last scrolled to the active stats, so unset the active index
                    this.setState({ activeIndex: -1 });
                }
            }
        } else {
            this.setState({ activeIndex: -1 });
        }
    }

    public render() {
        const { width, height } = this.state.dimensions;
        const onResize = (contentRect : ContentRect) => {
            if (typeof contentRect.bounds !== 'undefined') {
                this.setState({ dimensions: contentRect.bounds });
            }
        };

        return (
            <div className={ styles.selectList }>
                <Measure
                    bounds={ true }
                    onResize={ onResize }
                >
                    {
                        ({ measureRef }) => (
                            <div ref={ measureRef }>
                                <FixedSizeList
                                    ref={ this.listRef }
                                    height={ height }
                                    itemCount={ this.props.leagueStatsList.length }
                                    itemSize={ 35 }
                                    width={ width }
                                >
                                    { this.rowFactory.bind(this) }
                                </FixedSizeList>
                            </div>
                        )
                    }
                </Measure>
            </div>
        );
    }

    private padString(value : string, length : number) {
        let output = value;
        for (let i = length - value.length; i > 0; i--) {
            output += String.fromCharCode(160);
        }
        return output;
    }

    private rowFactory({ index, style } : IRowFactory) {
        const activeIvs = this.props.activeIndividualValues;
        const stats = this.props.leagueStatsList[index];
        const css = classNames(
            'list-item', // global style
            styles.listItem,
            {
                active: activeIvs.level === stats.level &&
                    activeIvs.hp === stats.ivHp &&
                    activeIvs.atk === stats.ivAtk &&
                    activeIvs.def === stats.ivDef,
                highlight: this.state.activeIndex === index,
            }
        );
        const onClick = () => {
            this.props.handleActivateLeagueStats(stats);
            this.setState({ activeIndex: index });
        };

        return (
            <a
                key={ index }
                style={ style }
                className={ css }
                onClick={ onClick }
            >
                <span>{ Grade[stats.speciesGrade] }</span>
                <span>{ this.padString(stats.cp.toString(), 4) }</span>
                <span>{ this.padString(stats.level.toString(), 4) }</span>
                <span>{ this.padString(stats.ivHp.toString(), 2) }</span>
                <span>{ this.padString(stats.ivAtk.toString(), 2) }</span>
                <span>{ this.padString(stats.ivDef.toString(), 2) }</span>
            </a>
        );
    }
}
