// @flow
/* State selectors for our Redux store via Reselect
 * basically a bunch of memoized shortcuts to certain state/derived state
*/
import { createSelector } from 'reselect';
import type { State } from './reducers.js';
import { getTcFromExpName } from '@helpers/beat';

import { getValidDatabaseObj } from '@helpers/beat';
import { getValidDataformatObj } from '@helpers/beat';
import { getValidLibraryObj } from '@helpers/beat';
import { getValidAlgorithmObj } from '@helpers/beat';
import { getValidToolchainObj } from '@helpers/beat';
import { getValidExperimentObj } from '@helpers/beat';
import { getValidPlotterObj } from '@helpers/beat';
import { getValidPlotterparameterObj } from '@helpers/beat';

const getObjs = {
	database: getValidDatabaseObj,
	dataformat: getValidDataformatObj,
	library: getValidLibraryObj,
	algorithm: getValidAlgorithmObj,
	toolchain: getValidToolchainObj,
	experiment: getValidExperimentObj,
	plotter: getValidPlotterObj,
	plotterparameter: getValidPlotterparameterObj,
};

export const databaseGet = (state: State) => state.database.map(o => getObjs['database'](o));
export const dataformatGet = (state: State) => state.dataformat.map(o => getObjs['dataformat'](o));
export const libraryGet = (state: State) => state.library.map(o => getObjs['library'](o));
export const algorithmGet = (state: State) => state.algorithm.map(o => getObjs['algorithm'](o));
export const toolchainGet = (state: State) => state.toolchain.map(o => getObjs['toolchain'](o));
export const experimentGet = (state: State) => createSelector(
	state => state.experiment,
	algorithmGet,
	toolchainGet,
	(exps, algs, tcs) => exps.map(o => {
		const tcName = getTcFromExpName(o.name);
		const tc = tcs.find(tc => tc.name === tcName);
		if(!tc)
			throw new Error(`Could not find toolchain for experiment "${ o.name }`);

		return getObjs['experiment'](o, tc, algs);
	})
)(state);
export const plotterGet = (state: State) => state.plotter.map(o => getObjs['plotter'](o));
export const plotterparameterGet = (state: State) => state.plotterparameter.map(o => getObjs['plotterparameter'](o));
export const settingsGet = (state: State) => state.settings;
export const environmentsGet = (state: State) => state.environments;
export const unsavedGet = (state: State) => state.unsaved;

export type FlattenedDatabaseEntry = {|
	database: string,
	protocol: string,
	protocolTemplate: string,
	set: string,
	setTemplate: string,
	outputs: {
		[string]: string,
	},
|};

export const databaseProtocols: ((state: State) => any[]) = createSelector(
	databaseGet,
	(dbs) => dbs.map((db, i) =>
		db.contents.protocols ? db.contents.protocols.map(p =>
			({
				...p,
				database: db.name,
			})
		) : []
	).reduce((a, ps) => [...a, ...ps], [])
);

export const flattenedDatabases: ((state: State) => FlattenedDatabaseEntry[]) = createSelector(
	databaseGet,
	(dbs) => dbs.map((db, i) =>
		db.contents.protocols ? db.contents.protocols.map(p =>
			p.sets.map(s =>
				({
					database: dbs[i].name,
					protocol: p.name,
					protocolTemplate: p.template,
					set: s.name,
					setTemplate: s.template,
					outputs: s.outputs,
				})
			)
		).reduce((a, ss) => [...a, ...ss], []) : []
	).reduce((a, ss) => [...a, ...ss], [])
);

export const normalBlocks = createSelector(
	algorithmGet,
	(alg) => alg.filter(alg => alg.contents.results === undefined)
);

export const analyzerBlocks = createSelector(
	algorithmGet,
	(alg) => alg.filter(alg => alg.contents.results !== undefined)
);
