import React from 'react';
import Media from 'react-media';
import { connect } from 'react-redux';
import { RouteComponentProps, withRouter } from 'react-router-dom';

import classNames from 'classnames';

import { AttackTypeEffectiveness } from 'app/models/Config';
import { League } from 'app/models/League';
import { CombatMoveStats, TypeEffectiveness } from 'app/models/Pokemon';

import * as ActionsPokemonApp from 'app/actions';
import * as ActionsPokemonExplorer from 'app/components/PokemonExplorer/actions';
import {
    CombatMoveSelectorsOpen,
    IndividualValueKey,
    IPokemonExplorerDispatch,
    IPokemonExplorerStore,
    SelectedCombatMoves,
    SubNavigation,
} from 'app/components/PokemonExplorer/types';
import { IRouterProps, Navigation as NavigationType } from 'app/types';

import { ExplorerLoading } from 'app/components/PokemonExplorer/ExplorerLoading';
import { LeagueIvExplorer } from 'app/components/PokemonExplorer/LeagueIvExplorer';
import { MovesExplorer } from 'app/components/PokemonExplorer/MovesExplorer';
import { Navigation } from 'app/components/PokemonExplorer/Navigation';
import { PokemonDisplay } from 'app/components/PokemonExplorer/PokemonDisplay';
import { EffectivenessMode, TypeEffectiveDisplay } from 'app/components/PokemonExplorer/TypeEffectiveDisplay';

import { appendQueryString } from 'app/utils/navigation';
import { calculateTypeCoverage } from 'app/utils/types';

import { MAX_MOBILE_WIDTH, MIN_TABLET_WIDTH } from 'common/models/constants';
import * as PVPogoProtos from 'common/models/PVPogoProtos';

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

interface IPokemonExplorerProps extends IRouterProps {
    isMenuOpen : boolean;
    isOverlaid : boolean;
    attackTypeEffectiveness : AttackTypeEffectiveness;
    combatMoves : CombatMoveStats;
    toggleInterruption : (isInterruption : boolean) => void;
}

interface IConnectedPokemonExplorerProps extends IPokemonExplorerStore, IPokemonExplorerDispatch, IPokemonExplorerProps {}

class PokemonExplorer extends React.Component<IConnectedPokemonExplorerProps> {

    public render() {
        const {
            isMenuOpen,
            isOverlaid,
            combatMoves,
            attackTypeEffectiveness,
        } = this.props;
        const {
            isLoading,
            league,
            individualValues,
            widgets,
            leaguePokemon,
            selectedCombatMoves,
            combatMoveSelectorsOpen,
        } = this.props.pokemonExplorerState;

        const isSelectingMove = combatMoveSelectorsOpen.quickMove || combatMoveSelectorsOpen.chargeMove1 || combatMoveSelectorsOpen.chargeMove2;
        const isOverlayShown = isOverlaid || isSelectingMove;

        const navWrapperCss = classNames(
            styles.navigationWrapper,
        );

        const displayWrapperCss = classNames(
            styles.displayWrapper,
        );

        const overLayCss = classNames(
            styles.overlay,
            {
                [styles.complete]: isSelectingMove
            }
        );

        // weaknesses are indicated by types that cause super effective damage on defense
        const pokemonTypeWeaknesses = leaguePokemon !== null ? this.getSuperEffectiveTypes(leaguePokemon.effectiveness) : [];
        // strengths are indicuated by types that do super effective damage on offense
        const moveTypeStrengths = this.getSuperEffectiveTypes(calculateTypeCoverage(selectedCombatMoves, combatMoves, attackTypeEffectiveness));

        return (
            <div className={ styles.body }>
                { (leaguePokemon === null || isLoading) &&
                    <ExplorerLoading />
                }
                { leaguePokemon !== null && !isLoading &&
                    <React.Fragment>
                        <div className={ navWrapperCss }>
                            <div className={ displayWrapperCss }>
                                { leaguePokemon !== null &&
                                    <PokemonDisplay
                                        leaguePokemon={ leaguePokemon }
                                        isHighlighted={ isOverlayShown }
                                    />
                                }
                                { widgets.types && leaguePokemon !== null &&
                                    <div className="nes-container with-title">
                                        <h3 className="title">Type Effectivess</h3>
                                        <TypeEffectiveDisplay
                                            mode={ EffectivenessMode.DEFENSE }
                                            effectiveness={ leaguePokemon.effectiveness }
                                            coverage={ moveTypeStrengths }
                                        />
                                    </div>
                                }
                                { widgets.moves && leaguePokemon !== null &&
                                    <MovesExplorer
                                        movesById={ combatMoves }
                                        quickMoves={ leaguePokemon.moves.quick }
                                        chargeMoves={ leaguePokemon.moves.cinematic }
                                        selectedMoves={ selectedCombatMoves }
                                        pokemonTypeWeaknesses={ pokemonTypeWeaknesses }
                                        attackTypeEffectiveness={ attackTypeEffectiveness }
                                        combatMoveSelectorsOpen={ combatMoveSelectorsOpen }
                                        handleToggleDropdownOpen={ this.handleToggleDropdownOpen }
                                        handleChangeSelectedMove={ this.handleChangeSelectedMove }
                                    />
                                }
                                { widgets.pvp && leaguePokemon !== null &&
                                    <LeagueIvExplorer
                                        activeLeague={ league }
                                        leaguePokemon={ leaguePokemon }
                                        individualValues={ individualValues }
                                        handleChangeIndividualValue={ this.handleChangeIndividualValue }
                                        handleMaximizeLevel={ this.handleMaximizeLevel }
                                        handleChangeLeague={ this.handleChangeLeague }
                                    />
                                }
                            </div>
                            <Media query={ { minWidth: MIN_TABLET_WIDTH } }>
                                <Navigation
                                    isMenu={ false }
                                    widgets={ widgets }
                                    handleNavigationClick={ this.handleNavigationClick }
                                />
                            </Media>
                            { isMenuOpen &&
                                <Media query={ { maxWidth: MAX_MOBILE_WIDTH } }>
                                    <Navigation
                                        isMenu={ true }
                                        widgets={ widgets }
                                        handleNavigationClick={ this.handleNavigationClick }
                                    />
                                </Media>
                            }
                        </div>
                        { isOverlayShown &&
                            <div className={ overLayCss } onClick={ this.handleOverlayClick } />
                        }
                    </React.Fragment>
                }
            </div>
        );
    }

    private readonly getSuperEffectiveTypes = (effectiveness : Map<PVPogoProtos.PokemonType, TypeEffectiveness>) => {
        const superEffectiveTypes : Array<PVPogoProtos.PokemonType> = [];
        Array.from(effectiveness).reduce((accumulator, currentValue) => {
            if (currentValue[1] > TypeEffectiveness.NEUTRAL) {
                accumulator.push(currentValue[0]);
            }
            return accumulator;
        }, superEffectiveTypes);
        return superEffectiveTypes;
    }

    private readonly handleToggleDropdownOpen = (menu : keyof CombatMoveSelectorsOpen, isOpen : boolean) => {
        const combatMoveSelectorsOpen : CombatMoveSelectorsOpen = {
            ...this.props.pokemonExplorerState.combatMoveSelectorsOpen,
            [menu]: isOpen, // 3/10/2019: TyepScript is not checking this!
        };
        this.props.dispatch(ActionsPokemonExplorer.setCombatMoveSelectorsOpen(combatMoveSelectorsOpen));
        this.props.toggleInterruption(isOpen);
    }

    private readonly handleOverlayClick = () => {
        this.props.dispatch(ActionsPokemonExplorer.setCombatMoveSelectorsOpen({
            quickMove: false,
            chargeMove1: false,
            chargeMove2: false,
        }));
        this.props.toggleInterruption(false);
    }

    private readonly handleNavigationClick = (widget : SubNavigation | NavigationType) => {
        if (widget === 'pokedex') {
            this.props.dispatch(ActionsPokemonApp.setIsInterruption(true));
            this.props.dispatch(ActionsPokemonApp.setNavigation('pokedex'));
        } else if (widget !== 'menu') {
            this.props.dispatch(ActionsPokemonExplorer.setSubNavigationWidgetIsShown(widget, !this.props.pokemonExplorerState.widgets[widget]));
        }
    }

    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 handleChangeSelectedMove = (moves : SelectedCombatMoves) => {
        this.props.dispatch(ActionsPokemonExplorer.setSelectedCombatMoves(moves));
    }

    // TODO: make this not overwrite other query parameters
    private readonly handleChangeLeagueNavigation = (league : League) => {
        const {
            history,
            location,
        } = this.props;

        history.push({
            search: appendQueryString(location, { league: league.toString() })
        });

        this.handleChangeLeague(league);
    }

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

const mapStateToProps = (state : IPokemonExplorerStore) : IPokemonExplorerStore => {
    return {
        ...state,
    };
};

const mapDispatchToProps = (dispatch : IPokemonExplorerDispatch['dispatch']) : IPokemonExplorerDispatch => {
    return {
        dispatch
    };
};

const mergeProps = (state : IPokemonExplorerStore, dispatchProps : IPokemonExplorerDispatch, ownProps : IPokemonExplorerProps) : IConnectedPokemonExplorerProps => {
    return {
        ...state,
        ...dispatchProps,
        ...ownProps,
    };
};

export const ConnectedPokemonExplorer = withRouter(connect(mapStateToProps, mapDispatchToProps, mergeProps)(PokemonExplorer));
