import POGOProtos from 'pogo-protos';

import React from 'react';
import { connect } from 'react-redux';

import { League } from 'app/models/League';

import { appReducers } from './index';

import * as ActionsPokemonExplorer from './components/PokemonExplorer/actions';
import * as ActionsPokemonSelectList from './components/PokemonSelectList/actions';
import { ThunkDispatchPokemonSelectList } from './types';

import { IndividualValueKey } from './components/PokemonExplorer/types';

import { PokemonExplorer } from './components/PokemonExplorer/PokemonExplorer';
import { PokemonSelectList } from './components/PokemonSelectList/PokemonSelectList';

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

type PokemonAppProps = ReturnType<typeof appReducers>;

interface IConnectedPokemonAppProps extends PokemonAppProps {
    dispatch : ThunkDispatchPokemonSelectList;
}

class PokemonApp extends React.Component<IConnectedPokemonAppProps> {
    constructor(props : IConnectedPokemonAppProps) {
        super(props);
    }

    public async componentWillMount() {
        const { dispatch } = this.props;

        await Promise.all([
            dispatch(ActionsPokemonExplorer.fetchConfig()),
            dispatch(ActionsPokemonSelectList.fetchPokemonList())
        ]);
        dispatch(ActionsPokemonSelectList.setIsLoading(false));
    }

    public render() {
        const {
            activePokemonId,
            activePokemonForm,
            pokemonList,
            pokemonListFiltered,
            filterTerm,
        } = this.props.pokemonSelectListState;
        const {
            league,
            individualValues,
            leaguePokemon,
        } = this.props.pokemonExplorerState;

        return (
            <div className={ styles.wrapper }>
                <PokemonSelectList
                    isLoading={ this.props.pokemonSelectListState.isLoading }
                    activePokemonId={ activePokemonId }
                    activePokemonForm={ activePokemonForm }
                    pokemonList={ filterTerm === '' ? pokemonList : pokemonListFiltered }
                    filterTerm={ this.props.pokemonSelectListState.filterTerm }
                    handleActivatePokemon={ this.handleActivatePokemon }
                    handleChangeFilter={ this.handleChangeFilter }
                />
                { leaguePokemon !== null &&
                    <PokemonExplorer
                        isLoading={ this.props.pokemonExplorerState.isLoading }
                        activeLeague={ league }
                        leaguePokemon={ leaguePokemon }
                        individualValues={ individualValues }
                        handleChangeIndividualValue={ this.handleChangeIndividualValue }
                        handleMaximizeLevel={ this.handleMaximizeLevel }
                        handleChangeLeague={ this.handleChangeLeague }
                    />
                }
            </div>
        );
    }

    private readonly handleActivatePokemon = (pokemonId : POGOProtos.Enums.PokemonId, form : POGOProtos.Enums.Form) => {
        const { dispatch } = this.props;

        dispatch(ActionsPokemonSelectList.fetchPokemonLeagueStats(pokemonId, form))
        .then((leaguePokemon) => {
            dispatch(ActionsPokemonSelectList.setActivePokemonId(pokemonId, form));
            dispatch(ActionsPokemonExplorer.setIvLevel(null));
            dispatch(ActionsPokemonExplorer.setIvHp(null));
            dispatch(ActionsPokemonExplorer.setIvAtk(null));
            dispatch(ActionsPokemonExplorer.setIvDef(null));
            dispatch(ActionsPokemonExplorer.setLeaguePokemon(leaguePokemon));
        })
        .catch((error) => {
            // tslint:disable-next-line:no-console
            console.error(error);
            dispatch(ActionsPokemonExplorer.setLeaguePokemon(null));
        })
        .then(() => dispatch(ActionsPokemonExplorer.setIsLoading(false)));
    }

    private readonly handleChangeFilter = (filterTerm : string) => {
        return this.props.dispatch(ActionsPokemonSelectList.filterPokemonList(filterTerm));
    }

    private readonly handleChangeIndividualValue = (stat : IndividualValueKey, value : number | null) => {
        const { dispatch } = this.props;

        switch (stat) {
            case 'level':
                dispatch(ActionsPokemonExplorer.setIvLevel(value));
                break;
            case 'hp':
                dispatch(ActionsPokemonExplorer.setIvHp(value));
                break;
            case 'atk':
                dispatch(ActionsPokemonExplorer.setIvAtk(value));
                break;
            case 'def':
                dispatch(ActionsPokemonExplorer.setIvDef(value));
                break;
            default:
                break;
        }
    }

    private readonly handleMaximizeLevel = () => {
        this.props.dispatch(ActionsPokemonExplorer.maximizeLevel());
    }

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

const mapStateToProps = (state : ReturnType<typeof appReducers>) : PokemonAppProps => {
    return {
        pokemonExplorerState: state.pokemonExplorerState,
        pokemonSelectListState: state.pokemonSelectListState,
    };
};

export const ConnectedPokemonApp = connect(mapStateToProps)(PokemonApp);
