import React from 'react';

import classNames from 'classnames';

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

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

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;
}

interface IState {
    form : {
        level : string;
    };
}

export class PokemonExplorer extends React.Component<IPokemonExplorerProps, IState> {
    private readonly MIN_LEVEL = 1;
    private readonly MAX_LEVEL = 40;
    private readonly MIN_IV = 0;
    private readonly MAX_IV = 15;

    private handleChangeHp : (event : React.ChangeEvent<HTMLInputElement>) => void;
    private handleChangeAtk : (event : React.ChangeEvent<HTMLInputElement>) => void;
    private handleChangeDef : (event : React.ChangeEvent<HTMLInputElement>) => void;

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

        this.state = {
            form: {
                level: '',
            }
        };

        this.handleChangeHp = this.handleChangeIvFactory('hp');
        this.handleChangeAtk = this.handleChangeIvFactory('atk');
        this.handleChangeDef = this.handleChangeIvFactory('def');
    }

    public render() {
        const {
            activeLeague,
            individualValues,
            leaguePokemon
        } = this.props;
        const league = 'great'; // TODO: this should be a prop

        let rankedPokemon : IStats | null = null;
        let placeholderLevel = '';
        let placeholderHp = '';
        let placeholderAtk = '';
        let placeholderDef = '';

        const dex = formatDexNumber(leaguePokemon.dex);
        const individualValueLevel = this.state.form.level !== '' ? this.state.form.level : individualValues.level;

        // default to first pokemon (should be S tier)
        if (individualValueLevel === null &&
            individualValues.hp === null &&
            individualValues.atk === null &&
            individualValues.def === null
        ) {
            rankedPokemon = leaguePokemon.pvp[league][0];
            placeholderLevel = '' + rankedPokemon.level;
            placeholderHp = '' + rankedPokemon.ivHp;
            placeholderAtk = '' + rankedPokemon.ivAtk;
            placeholderDef = '' + rankedPokemon.ivDef;

        // a full spec'd pokemon has been entered
        } else if (individualValueLevel !== null && typeof individualValueLevel === 'number' &&
            individualValues.hp !== null &&
            individualValues.atk !== null &&
            individualValues.def !== null
        ) {
            leaguePokemon.pvp[league].some((stats) => {
                if (individualValueLevel === stats.level &&
                    individualValues.hp === stats.ivHp &&
                    individualValues.atk === stats.ivAtk &&
                    individualValues.def === 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, individualValueLevel, individualValues.hp, individualValues.atk, individualValues.def),
                    level: individualValueLevel,
                    ivHp: individualValues.hp,
                    ivAtk: individualValues.atk,
                    ivDef: individualValues.def,
                    hp: calculateStatAtLevel(individualValueLevel, leaguePokemon.stats.baseStamina, individualValues.hp),
                    atk: calculateStatAtLevel(individualValueLevel, leaguePokemon.stats.baseAttack, individualValues.atk),
                    def: calculateStatAtLevel(individualValueLevel, leaguePokemon.stats.baseDefense, individualValues.def),
                    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 = rankedPokemon !== null ? rankedPokemon.hp : 0;
        const rankedAtk = rankedPokemon !== null ? rankedPokemon.atk : 0;
        const rankedDef = rankedPokemon !== null ? rankedPokemon.def : 0;

        const idIvLevelInput = 'iv-level-input';
        const idIvHpInput = 'iv-hp-input';
        const idIvAtkInput = 'iv-atk-input';
        const idIvDefInput = 'iv-def-input';
        const containerCss = classNames(
            'nes-container',
            'with-title'
        );
        const containerRoundCss = classNames(
            containerCss,
            'is-rounded'
        );
        const pokemonType = classNames(
            containerRoundCss,
            styles.pokemonType
        );
        const containerTitleCss = classNames(
            'title'
        );
        const baseStatsCss = classNames(
            styles.pokemonBaseStats,
            containerCss
        );
        const formContainerCss = classNames(
            containerCss,
            'form'
        );
        const fieldCss = classNames(
            'nes-field'
        );
        const inlineFieldCss = classNames(
            fieldCss,
            'is-inline',
            styles.fieldRow
        );
        const inputTextCss = classNames(
            'nes-input',
            styles.ivInput
        );
        const inputTextLevelCss = classNames(
            inputTextCss,
            styles.levelInput
        );
        const leaugeRankCss = classNames(
            styles.leaguePokemonRank,
            containerCss,
            {
                'with-title': false
            }
        );
        const maxButtonCss = classNames(
            'nes-btn',
            {
                'is-primary': individualValues.hp !== null && individualValues.atk !== null && individualValues.def !== null,
                'is-disabled': individualValues.hp === null || individualValues.atk === null || individualValues.def === null,
            }
        );

        const pokemonIconCss = classNames(
            `pokemon-${dex}`,
            {
                alola: leaguePokemon.form === 'ALOLA'
            }
        );

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

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

        return (
            <div className={ styles.wrapper }>
                <div>
                    <div className={ styles.pokemonInfoWrapper }>
                        <div className={ styles.pokemonInfoLeftColumn }>
                            <i className={ pokemonIconCss } />
                            <h4 className={ styles.dexHeader }>No.{ dex }</h4>
                            { leaguePokemon.form &&
                                <h6 className={ styles.formHeader }>{ leaguePokemon.form.toLowerCase().replace('_', ' ') } Form</h6>
                            }
                            <div className={ styles.pokemonTypeWrapper }>
                                { type1 }
                                { type2 }
                            </div>
                        </div>
                        <div className={ styles.pokemonInfoRightColumn }>
                            <h2 className={ styles.pokemonName }>{ leaguePokemon.name }</h2>
                            <h5>{ leaguePokemon.category }</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={ containerTitleCss }>IVs</h5>
                        <div className={ inlineFieldCss }>
                            <label htmlFor={ idIvHpInput }>HP</label>
                            <input
                                name="hp"
                                type="number"
                                id={ idIvHpInput }
                                className={ inputTextCss }
                                min={ this.MIN_IV }
                                max={ this.MAX_IV }
                                maxLength={ 2 }
                                onChange={ this.handleChangeHp }
                                value={ individualValues.hp !== null ? individualValues.hp : '' }
                                placeholder={ placeholderHp }
                            />
                            <label htmlFor={ idIvAtkInput }>ATK</label>
                            <input
                                name="atk"
                                type="number"
                                id={ idIvAtkInput }
                                className={ inputTextCss }
                                min={ this.MIN_IV }
                                max={ this.MAX_IV }
                                maxLength={ 2 }
                                onChange={ this.handleChangeAtk }
                                value={ individualValues.atk !== null ? individualValues.atk : '' }
                                placeholder={ placeholderAtk }
                            />
                            <label htmlFor={ idIvDefInput }>DEF</label>
                            <input
                                name="def"
                                type="number"
                                id={ idIvDefInput }
                                className={ inputTextCss }
                                min={ this.MIN_IV }
                                max={ this.MAX_IV }
                                maxLength={ 2 }
                                onChange={ this.handleChangeDef }
                                value={ individualValues.def !== null ? individualValues.def : '' }
                                placeholder={ placeholderDef }
                            />
                        </div>
                        <div className={ inlineFieldCss }>
                            <div className={ inlineFieldCss }>
                                <label htmlFor={ idIvLevelInput }>Lv</label>
                                <input
                                    name="level"
                                    type="number"
                                    id={ idIvLevelInput }
                                    className={ inputTextLevelCss }
                                    min={ this.MIN_LEVEL }
                                    max={ this.MAX_LEVEL }
                                    step={ 0.5 }
                                    onChange={ this.handleChangeLevel }
                                    value={ individualValueLevel !== null ? individualValueLevel : '' }
                                    placeholder={ placeholderLevel }
                                />
                            </div>
                            <button
                                type="button"
                                className={ maxButtonCss }
                                onClick={ this.handleClickMaximizeLevel }
                            >
                                MAX LEAGUE Lv
                            </button>
                        </div>
                    </section>
                    <section className={ leaugeRankCss }>
                        <h5 className={ containerTitleCss }>Rank</h5>
                        <div className={ styles.pokemonInfoWraper }>
                            <div className={ styles.pokemonInfoLeftColumn }>
                                <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={ leaguePokemon.statsRank.staminaRank }
                                />
                                <StatDisplay
                                    statLabel="ATK"
                                    statValue={ rankedAtk }
                                    statRank={ leaguePokemon.statsRank.attackRank }
                                />
                                <StatDisplay
                                    statLabel="DEF"
                                    statValue={ rankedDef }
                                    statRank={ leaguePokemon.statsRank.defenseRank }
                                />
                            </div>
                        </div>
                    </section>
                </div>
                <LeagueStatsList
                    activePokemonId={ leaguePokemon.id }
                    activeIndividualValues={ individualValues }
                    leagueStatsList={ leaguePokemon.pvp[league] }
                    handleActivateLeagueStats={ this.handleActivateLeagueStats }
                />
            </div>
        );
    }

    private readonly handleChangeLevel = (event : React.ChangeEvent<HTMLInputElement>) => {
        const raw = event.currentTarget.value;
        const value = parseFloat(raw);

        this.setState({ form: { level: '' } });
        if (raw === '' + value && value >= this.MIN_LEVEL && value <= this.MAX_LEVEL && value % 0.5 === 0) {
            this.props.handleChangeIndividualValue('level', value);
        } else if (raw === '') {
            this.props.handleChangeIndividualValue('level', null);
        } else if (raw.charAt(raw.length) === '.') {
            this.setState({ form: { level: raw } });
        }
    }

    private readonly handleClickMaximizeLevel = () => {
        this.props.handleMaximizeLevel();
    }

    private readonly handleChangeIvFactory = (type : IndividualValueKey) => {
        return (event : React.ChangeEvent<HTMLInputElement>) => {
            const raw = event.currentTarget.value;
            const value = parseInt(raw, 10);
            if (raw === '' + value && value >= this.MIN_IV && value <= this.MAX_IV) {
                this.props.handleChangeIndividualValue(type, value);
            } else if (raw === '') {
                this.props.handleChangeIndividualValue(type, null);
            }
        };
    }

    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);
    }
}
