import { fromJS } from 'immutable';

import createReducer from 'lib/reducer';


//basic initial state
export const initialState = {
	filter: {
		status: 'pending',
		options: {},
		data: {}
	},
	list: {
		status: 'pending',
		fresh: true,
		filter: {},
		data: [],
		paging: {},
		sorting: {}
	},
	summary: {
		status: 'pending',
		data: {}
	}
};


//TODO support multiple options
export default function(reduxKey, { reducer, fetchRequest, fetchResponse, filterOptionsRequest, filterOptionsResponse, fetchSummaryRequest, fetchSummaryResponse } = {}) {
	let output = {};
	let actions = {};

	if (!reducer) {
		reducer = createReducer(initialState);
	} else if (process.env.NODE_ENV !== 'production' && typeof reducer.handleAction !== "function") {
		console.log("Provided reducer must implement handleAction(key::string, function(state, action)::state ) method");
		return output;
	}

	//inject fetch action
	if (typeof fetchRequest === "function" && typeof fetchResponse === "function") {
		//TODO add paging
		actions.fetchList = function(filter, paging, sorting, {...opts}) {
			return {
				type: reduxKey + "/LIST",
				payload: fetchRequest({ filter, paging, sorting, ...opts }),
				meta: {
					filter,
					paging,
					sorting,
					...opts
				}
			}
		}

		reducer.handleAction(reduxKey + '/LIST_PENDING', (state, action) => 
			state.withMutations(s => {
				if (action.meta && action.meta.filter) {
					s = s.setIn(["list", "filter"], action.meta.filter);
				}
				s = s.setIn(["list", "status"], "pending");
				return s;
			})
		);

		reducer.handleAction(reduxKey + '/LIST_FULFILLED', (state, action) => 
			state.withMutations(s => {
				s = s.setIn(["list"], fromJS(fetchResponse(action.payload, action.meta)));
				if (action.meta && action.meta.filter) {
					s = s.setIn(["list", "filter"], action.meta.filter);
				}
				s = s.setIn(["list", "status"], "success").setIn(["list", "fresh"], false).deleteIn(["list", "error"]);
				return s;
			})
		);

		reducer.handleAction(reduxKey + '/LIST_REJECTED', (state, action) => 
			state
				.deleteIn(["list", "data"])
				.setIn(["list", "error"], { code: "unhandled" }) //TODO
				.setIn(["list", "status"], "failure")
				.setIn(["list", "fresh"], false)
		);
	}

	//inject filter action
	if (typeof filterOptionsRequest === "function" && typeof filterOptionsResponse === "function") {
		actions.fetchFilterOptions = function(filter, {...opts}) {
			return {
				type: reduxKey + '/FETCH_FILTER',
				payload: filterOptionsRequest({ filter, ...opts })
			}
		}

		reducer.handleAction(reduxKey + '/FETCH_FILTER_PENDING', (state, action) => 
			state
				.setIn(["filter", "status"], "pending")
		);

		reducer.handleAction(reduxKey + '/FETCH_FILTER_FULFILLED', (state, action) => 
			state
				.setIn(["filter", "options"], fromJS(filterOptionsResponse(action.payload, action.meta)))
				.setIn(["filter", "status"], "success")
		);

		reducer.handleAction(reduxKey + '/FETCH_FILTER_REJECTED', (state, action) => 
			state
				.deleteIn(["filter"])
				.setIn(["filter", "error"], {}) //TODO
				.setIn(["filter", "status"], "failure")
		);

	}

	//inject summary
	if (typeof fetchSummaryRequest === "function" && typeof fetchSummaryResponse === "function") {
		actions.fetchSummaryOptions = function(filter, {...opts}) {
			return {
				type: reduxKey + '/SUMMARY',
				payload: fetchSummaryRequest({ filter, ...opts })
			}
		}

		reducer.handleAction(reduxKey + '/SUMMARY_PENDING', (state, action) => 
			state
				.setIn(["summary", "status"], "pending")
		);

		reducer.handleAction(reduxKey + '/SUMMARY_FULFILLED', (state, action) => 
			state
				.setIn(["summary"], fromJS(fetchSummaryResponse(action.payload, action.meta)))
				.setIn(["summary", "status"], "success")
		);

		reducer.handleAction(reduxKey + '/SUMMARY_REJECTED', (state, action) => 
			state
				.deleteIn(["summary"])
				.setIn(["summary", "error"], {}) //TODO
				.setIn(["summary", "status"], "failure")
		);

	}

	//construct response
	output.actions = actions;
	output.reducer = reducer;
	output.selector = function(state) {
		let s = state && state.get && state.get(reduxKey);
		return s ? s.toJS() : initialState;
	};

	return output;
}
