import * as Actions from "../actions";

import { ILearner } from "../models/learner";
import { ILevel } from "../models/level";
import { IUser } from "../models/user";
import { IVocab, IReviewCard } from "../models/vocab";
import { IReviewMetadata } from "../models/review";

interface IState {
    drawer: boolean;
    scorePopoverOpen: boolean;
    drawerButton: boolean;
    authenticated: boolean;
    didLogin: boolean;

    // TODO: Rework this
    user: IUser | {},

    // All available levels
    levels: ILevel[];

    login: {
        loading: boolean;
        snackMsg: string;
        snackOpen: boolean;
    };

    level: {
        currentVocab: IVocab;
        lookedAt: number[];
        vocab: IVocab[];
        loading: boolean;
    };

    levelList: {
        loading: boolean;
        snackbar: boolean;
    };

    dashboard: {
        loading: boolean;
    };

    review: {
        current: IReviewCard;

        dialogOpen: boolean;
        loading: boolean;
        vocab: IVocab[];
        metadata: IReviewMetadata;
        popoverOpen: boolean;
        popoverText: string;
        popoverColor: string;
        popoverTextColor: string;
        showHelp: boolean;
    };

    register: {
        loading: boolean;
        snackMsg: string;
        snackOpen: boolean;
    };

    topTen: ILearner[];

    nextLevel: ILevel;
    lastReview: any;
};

const initialState: IState = {
    // Show the drawer?
    drawer: false,
    // Should we show the button to open the drawer?
    drawerButton: true,
    scorePopoverOpen: false,
    didLogin: false,

    // Is the user authenticated?
    authenticated: false,

    user: {
        score: 0,
    },

    login: {
        loading: false,
        snackMsg: "",
        snackOpen: false,
    },

    levels: [],

    level: {
        currentVocab: {} as IVocab,
        lookedAt: [0],
        vocab: [],
        loading: true,
    },

    levelList: {
        loading: true,
        snackbar: false,
    },

    dashboard: {
        loading: true,
    },

    review: {
        current: {} as IReviewCard,

        dialogOpen: false,
        loading: true,
        vocab: [],
        metadata: {} as IReviewMetadata,
        popoverOpen: false,
        popoverText: "",
        popoverColor: "",
        popoverTextColor: "",
        showHelp: false,
    },

    register: {
        loading: false,
        snackOpen: false,
        snackMsg: "",
    },

    nextLevel: {} as ILevel,
    lastReview: {
        correct: 0,
        wrong: 0,
    },

    // The top ten
    topTen: [],
};

export function LateinicusApp(state: IState = initialState, action: any) {
    switch (action.type) {
        case Actions.SET_DRAWER:
            return Object.assign({}, state, {
                drawer: action.show,
            });
        case Actions.SET_DRAWER_BUTTON:
            return Object.assign({}, state, {
                drawerButton: action.show,
            });
        case Actions.LOGIN_SET_SNACKBAR:
            return Object.assign({}, state, {
                login: {
                    loading: state.login.loading,
                    snackMsg: action.msg,
                    snackOpen: action.show,
                },
            });
        case Actions.LOGIN_SET_LOADING:
            return Object.assign({}, state, {
                login: {
                    loading: action.show,
                    snackMsg: state.login.snackMsg,
                    snackOpen: state.login.snackOpen,
                },
            });
        case Actions.SET_AUTHENTICATED:
            return Object.assign({}, state, {
                authenticated: action.status,
            });
        case Actions.SET_USER:
            return Object.assign({}, state, {
                user: action.user,
            });
        case Actions.LEVEL_SET_LOOKEDAT:
            return Object.assign({}, state, {
                level: Object.assign({}, state.level, {
                    lookedAt: action.lookedAt,
                }),
            });
        case Actions.LEVEL_SET_CUR_VOCAB:
            return Object.assign({}, state, {
                level: Object.assign({}, state.level, {
                    currentVocab: action.vocab,
                }),
            });
        case Actions.LEVEL_SET_VOCAB:
            return Object.assign({}, state, {
                level: Object.assign({}, state.level, {
                    vocab: action.vocab,
                }),
            });
        case Actions.LEVEL_SET_LOADING:
            return Object.assign({}, state, {
                level: Object.assign({}, state.level, {
                    loading: action.state,
                }),
            });
        case Actions.SET_LEVELS:
            return Object.assign({}, state, {
                levels: action.levels,
            });
        case Actions.REVIEW_SET_POPOVER:
            return Object.assign({}, state, {
                review: Object.assign({}, state.review, {
                    popoverText: action.text,
                    popoverOpen: action.state,
                    popoverColor: action.color,
                    popoverTextColor: action.textColor,
                }),
            });
        case Actions.SET_REVIEW:
            return Object.assign({}, state, {
                review: Object.assign({}, state.review, {
                    current: action.current,
                    metadata: action.meta,
                }),
            });
        case Actions.SET_LAST_REVIEW:
            return Object.assign({}, state, {
                lastReview: action.metadata,
            });
        case Actions.SET_USER_SCORE_DELTA:
            return Object.assign({}, state, {
                user: Object.assign({}, state.user, {
                    score: state.user.score + action.delta,
                }),
            });
        case Actions.REVIEW_SET_LOADING:
            return Object.assign({}, state, {
                review: Object.assign({}, state.review, {
                    loading: action.state,
                }),
            });
        case Actions.LEVELLIST_SET_LOADING:
            return Object.assign({}, state, {
                levelList: Object.assign({}, state.levelList, {
                    loading: action.state,
                }),
            });
        case Actions.SET_SCORE_POPOVER:
            return Object.assign({}, state, {
                scorePopoverOpen: action.state,
            });
        case Actions.SET_NEXT_LEVEL:
            return Object.assign({}, state, {
                nextLevel: action.level,
            });
        case Actions.SET_TOP_TEN:
            return Object.assign({}, state, {
                topTen: action.topTen,
            });
        case Actions.SET_DID_LOGIN:
            return Object.assign({}, state, {
                didLogin: state,
            });
        case Actions.REVIEW_SET_DIALOG:
            return Object.assign({}, state, {
                review: Object.assign({}, state.review, {
                    dialogOpen: action.state,
                }),
            });
        case Actions.DASHBOARD_SET_LOADING:
            return Object.assign({}, state, {
                review: Object.assign({}, state.review, {
                    loading: action.state,
                }),
            });
        case Actions.LEVELLIST_SET_SNACKBAR:
            return Object.assign({}, state, {
                levelList: Object.assign({}, state.levelList, {
                    snackbar: action.state,
                }),
            });
        case Actions.REVIEW_SET_HELP:
            return Object.assign({}, state, {
                review: Object.assign({}, state.review, {
                    showHelp: action.state,
                }),
            });
        case Actions.REGISTER_SET_SNACKBAR:
            return Object.assign({}, state, {
                register: Object.assign({}, state.register, {
                    snackMsg: action.msg,
                    snackOpen: action.state,
                }),
            });
        case Actions.REGISTER_SET_LOADING:
            return Object.assign({}, state, {
                register: Object.assign({}, state.register, {
                    loading: action.state,
                }),
            });
        default:
            // Ignore the initialization call to the reducer. By that we can
            // catch all actions that are not implemented
            if (action.type && !action.type.startsWith("@@redux/INIT")) {
                console.log("Reducer not implemented:", action.type);
            }

            return state;
    }
};
