import POGOProtos from 'pogo-protos';

import React from 'react';

import classNames from 'classnames';

import { IBestWorstStats, ILeaguePokemon, League, MaxCpByLeague } from 'app/models/League';
import { Grade, IStats, } from 'app/models/Pokemon';
import { calculateCp, calculateStatAtLevel } from 'app/utils/calculator';
import { formatDexNumber, formatForm, formatType, Forms } from 'app/utils/formatter';

import { IIndividualValues, IndividualValueKey } from './types';

import { IvForm } from './IvForm';
import { LeagueSelector } from './LeagueSelector';
import { LeagueStatsList } from './LeagueStatsList';
import { StatDisplay } from './StatDisplay';

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

export interface IPokemonExplorerProps {
    isLoading : boolean;
    activeLeague : League;
    leaguePokemon : ILeaguePokemon;
    individualValues : IIndividualValues;

    handleChangeIndividualValue : (stat : IndividualValueKey, value : number | null) => void;
    handleMaximizeLevel : () => void;
    handleChangeLeague : (league : League) => void;
}

enum IvDisplayMode {
    MANUAL = 'manual',
    LIST = 'list',
}
interface IState {
    ivDisplayMode : IvDisplayMode;
}

export class PokemonExplorer extends React.Component<IPokemonExplorerProps, IState> {

    private static calculateStatRanks(rankedPokemon : IStats | null, stats : IBestWorstStats) {
        const rankedHp = rankedPokemon !== null ? rankedPokemon.hp : 0;
        const rankedAtk = rankedPokemon !== null ? rankedPokemon.atk : 0;
        const rankedDef = rankedPokemon !== null ? rankedPokemon.def : 0;

        const maxStamina = stats.stamina;
        const staminaStatRank = Math.floor(((rankedHp - maxStamina.worst) / (maxStamina.best - maxStamina.worst)) * 100);
        const maxAttack = stats.attack;
        const attackStatRank = Math.floor(((rankedAtk - maxAttack.worst) / (maxAttack.best - maxAttack.worst)) * 100);
        const maxDefense = stats.defense;
        const defenseStatRank = Math.floor(((rankedDef - maxDefense.worst) / (maxDefense.best - maxDefense.worst)) * 100);

        return {
            rankedHp,
            rankedAtk,
            rankedDef,
            staminaStatRank,
            attackStatRank,
            defenseStatRank,
        };
    }

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

        this.state = {
            ivDisplayMode: IvDisplayMode.MANUAL,
        };
    }

    public render() {
        const {
            activeLeague,
            individualValues,
            leaguePokemon,
            handleChangeIndividualValue,
            handleMaximizeLevel,
        } = this.props;

        const {
            ivDisplayMode,
        } = this.state;

        let rankedPokemon : IStats | null = null;

        const dex = formatDexNumber(leaguePokemon.dex);

        // default to first pokemon (should be S tier)
        if (individualValues.level === null &&
            individualValues.ivHp === null &&
            individualValues.ivAtk === null &&
            individualValues.ivDef === null
        ) {
            rankedPokemon = leaguePokemon.pvp[activeLeague][0];

        // a full spec'd pokemon has been entered
        } else if (individualValues.level !== null &&
            individualValues.ivHp !== null &&
            individualValues.ivAtk !== null &&
            individualValues.ivDef !== null
        ) {
            leaguePokemon.pvp[activeLeague].some((stats) => {
                if (individualValues.level === stats.level &&
                    individualValues.ivHp === stats.ivHp &&
                    individualValues.ivAtk === stats.ivAtk &&
                    individualValues.ivDef === stats.ivDef
                ) {
                    rankedPokemon = stats;
                    return true;
                }
                return false;
            });

            // we don't have the data for this terrible mon
            if (rankedPokemon === null) {
                rankedPokemon = {
                    cp: calculateCp(leaguePokemon.stats, individualValues.level, individualValues.ivHp, individualValues.ivAtk, individualValues.ivDef),
                    level: individualValues.level,
                    ivHp: individualValues.ivHp,
                    ivAtk: individualValues.ivAtk,
                    ivDef: individualValues.ivDef,
                    hp: calculateStatAtLevel(individualValues.level, leaguePokemon.stats.baseStamina, individualValues.ivHp),
                    atk: calculateStatAtLevel(individualValues.level, leaguePokemon.stats.baseAttack, individualValues.ivAtk),
                    def: calculateStatAtLevel(individualValues.level, leaguePokemon.stats.baseDefense, individualValues.ivDef),
                    total: 0,
                    speciesGrade: Grade.F,
                    metaGrade: Grade.F,
                };
                rankedPokemon.total = rankedPokemon.hp + rankedPokemon.atk + rankedPokemon.def;
            }
        }

        const rankedGrade = rankedPokemon !== null ? Grade[rankedPokemon.speciesGrade] : '-';
        const rankedCp = rankedPokemon !== null ? rankedPokemon.cp : '-';
        const {
            rankedHp,
            rankedAtk,
            rankedDef,
            staminaStatRank,
            attackStatRank,
            defenseStatRank,
        } = PokemonExplorer.calculateStatRanks(rankedPokemon, leaguePokemon.statMax[activeLeague]);

        const containerCss = classNames(
            'nes-container',
            'with-title',
        );
        const containerRoundCss = classNames(
            containerCss,
            'is-rounded',
        );
        const pokemonType = classNames(
            containerRoundCss,
            styles.pokemonType,
        );
        const containerTitleCss = classNames(
            'title',
        );
        const ivContainerTitleCss = classNames(
            containerTitleCss,
            styles.ivContainerTitle
        );
        const baseStatsCss = classNames(
            styles.pokemonBaseStats,
            containerCss,
        );
        const formContainerCss = classNames(
            containerCss,
            styles.ivsContainer,
            'form',
            {
                [ styles.diplayingIvList ]: ivDisplayMode === IvDisplayMode.LIST,
            }
        );
        const leaugeRankCss = classNames(
            styles.leaguePokemonRank,
            containerCss,
            {
                'with-title': false
            },
        );

        const pokemonIconCss = classNames(
            `pokemon-${dex}`,
            {
                normal: Forms.normal.indexOf(leaguePokemon.form) > -1,
                alola: Forms.alola.indexOf(leaguePokemon.form) > -1,
                plant: Forms.plant.indexOf(leaguePokemon.form) > -1,
                sandy: Forms.sandy.indexOf(leaguePokemon.form) > -1,
                trash: Forms.trash.indexOf(leaguePokemon.form) > -1,
                'west-sea': Forms.westSea.indexOf(leaguePokemon.form) > -1,
                'east-sea': Forms.eastSea.indexOf(leaguePokemon.form) > -1,
                frost: Forms.frost.indexOf(leaguePokemon.form) > -1,
                fan: Forms.fan.indexOf(leaguePokemon.form) > -1,
                mow: Forms.mow.indexOf(leaguePokemon.form) > -1,
                wash: Forms.wash.indexOf(leaguePokemon.form) > -1,
                heat: Forms.heat.indexOf(leaguePokemon.form) > -1,
                sky: Forms.sky.indexOf(leaguePokemon.form) > -1,
                land: Forms.land.indexOf(leaguePokemon.form) > -1,
                overcast: Forms.overcast.indexOf(leaguePokemon.form) > -1,
                sunny: Forms.sunny.indexOf(leaguePokemon.form) > -1,
                rainy: Forms.rainy.indexOf(leaguePokemon.form) > -1,
                snowy: Forms.snowy.indexOf(leaguePokemon.form) > -1,
                attack: Forms.attack.indexOf(leaguePokemon.form) > -1,
                defense: Forms.defense.indexOf(leaguePokemon.form) > -1,
                speed: Forms.speed.indexOf(leaguePokemon.form) > -1,
                altered: Forms.altered.indexOf(leaguePokemon.form) > -1,
                origin: Forms.origin.indexOf(leaguePokemon.form) > -1,
                fighting: Forms.fighting.indexOf(leaguePokemon.form) > -1,
                flying: Forms.flying.indexOf(leaguePokemon.form) > -1,
                poison: Forms.poison.indexOf(leaguePokemon.form) > -1,
                ground: Forms.ground.indexOf(leaguePokemon.form) > -1,
                rock: Forms.rock.indexOf(leaguePokemon.form) > -1,
                bug: Forms.bug.indexOf(leaguePokemon.form) > -1,
                ghost: Forms.ghost.indexOf(leaguePokemon.form) > -1,
                steel: Forms.steel.indexOf(leaguePokemon.form) > -1,
                fire: Forms.fire.indexOf(leaguePokemon.form) > -1,
                water: Forms.water.indexOf(leaguePokemon.form) > -1,
                grass: Forms.grass.indexOf(leaguePokemon.form) > -1,
                electric: Forms.electric.indexOf(leaguePokemon.form) > -1,
                psychic: Forms.psychic.indexOf(leaguePokemon.form) > -1,
                ice: Forms.ice.indexOf(leaguePokemon.form) > -1,
                dragon: Forms.dragon.indexOf(leaguePokemon.form) > -1,
                dark: Forms.dark.indexOf(leaguePokemon.form) > -1,
                fairy: Forms.fairy.indexOf(leaguePokemon.form) > -1,
            },
        );

        const type1 : JSX.Element = <div className={ `${pokemonType} ${formatType(leaguePokemon.types.type1)}` }>{ formatType(leaguePokemon.types.type1) }</div>;
        let type2 : JSX.Element | null = null;
        if (leaguePokemon.types.type2) {
            type2 = <div className={ `${pokemonType} ${formatType(leaguePokemon.types.type2)}` }>{ formatType(leaguePokemon.types.type2) }</div>;
        }

        return (
            <div className={ styles.wrapper }>
                <div className={ styles.pokemonInfoWrapper }>
                    <div className={ styles.pokemonInfoLeftColumn }>
                        <i className={ pokemonIconCss } />
                        <h4 className={ styles.dexHeader }>No.{ dex }</h4>
                        <div className={ styles.pokemonTypeWrapper }>
                            { type1 }
                            { type2 }
                        </div>
                        { leaguePokemon.form !== POGOProtos.Enums.Form.FORM_UNSET &&
                            <h6 className={ styles.formHeader }>{ formatForm(leaguePokemon.form) } Form</h6>
                        }
                    </div>
                    <div className={ styles.pokemonInfoRightColumn }>
                        <h2 className={ styles.pokemonName }>{ leaguePokemon.name }</h2>
                        <h5>{ leaguePokemon.genus }</h5>
                        <section className={ baseStatsCss }>
                            <h3 className={ containerTitleCss }>Base Stats</h3>
                            <StatDisplay
                                statLabel={ `HP${ String.fromCharCode(160) }` }
                                statValue={ leaguePokemon.stats.baseStamina }
                                statRank={ leaguePokemon.statsRank.staminaRank }
                            />
                            <StatDisplay
                                statLabel="ATK"
                                statValue={ leaguePokemon.stats.baseAttack }
                                statRank={ leaguePokemon.statsRank.attackRank }
                            />
                            <StatDisplay
                                statLabel="DEF"
                                statValue={ leaguePokemon.stats.baseDefense }
                                statRank={ leaguePokemon.statsRank.defenseRank }
                            />
                        </section>
                    </div>
                </div>
                <LeagueSelector
                    activeLeague={ activeLeague }
                    handleLeagueSelect={ this.handleLeagueSelect }
                />
                <section className={ formContainerCss }>
                    <h5 className={ ivContainerTitleCss }>
                        <span>IVs</span>
                        <label>
                            <input
                                className="nes-radio"
                                type="radio"
                                value="manual"
                                checked={ ivDisplayMode === IvDisplayMode.MANUAL }
                                onChange={ this.handleIvDisplayModeManual }
                            /> <span>Manual</span>
                        </label>
                        <label>
                            <input
                                className="nes-radio"
                                type="radio"
                                value="list"
                                checked={ ivDisplayMode === IvDisplayMode.LIST }
                                onChange={ this.handleIvDisplayModeList }
                            /> <span>List</span>
                        </label>
                    </h5>
                    { ivDisplayMode === IvDisplayMode.MANUAL &&
                        <IvForm
                            ivs={ individualValues }
                            placeholder={ leaguePokemon.pvp[activeLeague][0] }
                            handleChangeIndividualValue={ handleChangeIndividualValue }
                            handleMaximizeLevel={ handleMaximizeLevel }
                        />
                    }
                    { ivDisplayMode === IvDisplayMode.LIST &&
                        <LeagueStatsList
                            activePokemonId={ leaguePokemon.id }
                            activePokemonForm={ leaguePokemon.form }
                            activeIndividualValues={ individualValues }
                            leagueStatsList={ leaguePokemon.pvp[activeLeague] }
                            handleActivateLeagueStats={ this.handleActivateLeagueStats }
                        />
                    }
                </section>
                <section className={ leaugeRankCss }>
                    <h5 className={ containerTitleCss }>Rank</h5>
                    <div className={ styles.pokemonInfoWraper }>
                        <div className={ styles.pokemonInfoLeftColumn }>
                            { rankedPokemon === null || rankedPokemon.cp > MaxCpByLeague[activeLeague] &&
                                <div><h1 className={ styles.pokemonRankValue }>N/A</h1></div>
                            }
                            { rankedPokemon !== null && rankedPokemon.cp <= MaxCpByLeague[activeLeague] &&
                                <div><h1 className={ styles.pokemonRankValue }>{ rankedGrade }</h1> Rank</div>
                            }
                            <div>CP <h1 className={ styles.pokemonRankValue }>{ rankedCp }</h1></div>
                        </div>
                        <div className={ styles.pokemonInfoRightColumn }>
                            <StatDisplay
                                statLabel={ `HP${ String.fromCharCode(160) }` }
                                statValue={ rankedHp }
                                statRank={ staminaStatRank }
                            />
                            <StatDisplay
                                statLabel="ATK"
                                statValue={ rankedAtk }
                                statRank={ attackStatRank }
                            />
                            <StatDisplay
                                statLabel="DEF"
                                statValue={ rankedDef }
                                statRank={ defenseStatRank }
                            />
                        </div>
                    </div>
                </section>
            </div>
        );
    }

    private readonly handleActivateLeagueStats = (stats : IStats) => {
        const { handleChangeIndividualValue } = this.props;

        handleChangeIndividualValue('level', stats.level);
        handleChangeIndividualValue('hp', stats.ivHp);
        handleChangeIndividualValue('atk', stats.ivAtk);
        handleChangeIndividualValue('def', stats.ivDef);
    }

    private readonly handleLeagueSelect = (league : League) => {
        this.props.handleChangeLeague(league);
    }

    private readonly handleIvDisplayModeManual = () => {
        this.setState({ ivDisplayMode: IvDisplayMode.MANUAL });
    }

    private readonly handleIvDisplayModeList = () => {
        this.setState({ ivDisplayMode: IvDisplayMode.LIST });
    }
}
