import isObject from 'lodash/isObject';
import reduce from 'lodash/reduce';
import get from 'lodash/get';

import {
    REQUEST_DATA,
    NETWORK_ERROR,
    POST_DATA,
    RECEIVE_DATA,
    CANCEL_REQUEST,
    REQUEST_ERROR,
} from './Actions';

const initialState = {
    sources: {},
    isFetching: false,
    has404Error: false,
};

function getSourceState(action) {
    switch (action.type) {
        case REQUEST_DATA:
            return {
                isFetching: true,
                source: action.source,
            };

        case POST_DATA:
            return {
                isFetching: true,
                isPosted: true,
                postData: action.data,
                source: action.source,
            };

        case NETWORK_ERROR:
            return {
                isFetching: false,
                error: action.error,
                source: action.source,
            };

        case REQUEST_ERROR:
            return {
                isFetching: false,
                error: action.error,
                source: action.source,
            };

        case RECEIVE_DATA:
            return {
                isFetching: false,
                data: action.data,
                source: action.source,
            };

        case CANCEL_REQUEST:
            return {
                isFetching: false,
                isCancelled: true,
                source: action.source,
            };
    }
}

function has404Error(sourceState) {
    return get(sourceState, 'error.response.status', null) === 404;
}

export default function apiReducer(state = initialState, action = {}) {
    switch (action.type) {
        case REQUEST_DATA:
        case POST_DATA:
        case NETWORK_ERROR:
        case RECEIVE_DATA:
        case CANCEL_REQUEST:
        case REQUEST_ERROR: {
            const sourceState = getSourceState(action);
            const sources = { ...state.sources };
            const key = isObject(action.source) ? action.source.url : action.source;
            if (sourceState.isFetching) {
                sources[key] = sourceState;
            } else {
                // remove when fetching finished... maybe it saves a bit of memory
                delete sources[key];
            }
            return {
                ...state,
                sources,
                isFetching: reduce(
                    sources,
                    function(result, value) {
                        return result || value.isFetching;
                    },
                    false
                ),
                has404Error: has404Error(sourceState),
            };
        }

        default:
            return state;
    }
}
