const vm = require('vm');
const Cursor = require('pg-cursor');
const { pool, setSurvey, transaction, fetchRow } = require('../../db/connection')

/** Run shot QCs for project
 *
 * @a projectId The project in which to run the QCs
 * @a sequence The sequence number in which to run the QCs
 * @a definitions The QC definitions, as a flat array
 * @a parameters The QC parameters (variables)
 *
 * @a return results array
 */
async function runShotQCs (projectId, sequence, definitions, parameters) {

	const client = await setSurvey(projectId);

	const results = {}; // The structure will be { point: { qc_id: test_result } }

	const text = `
		SELECT
		CASE
			WHEN fs.sequence IS NOT NULL THEN 'final'
			WHEN fs.sequence IS NULL AND rsp.hash = '*online*' THEN 'real-time'
			WHEN fs.sequence IS NULL AND rsp.hash <> '*online*' THEN 'raw'
		END AS type,
		rsp.sequence,
		rsp.line,
		rsp.point,
		rsp.objref,
		rsp.tstamp,
		COALESCE(
			fs.hash,
			rsp.hash
		) hash,
		COALESCE(
			ST_AsGeoJSON(ST_Transform(fs.geometry, 4326)),
			ST_AsGeoJSON(ST_Transform(rsp.geometry, 4326))
		) geometry,
		COALESCE(
			fse.error_i,
			rse.error_i
		) error_i,
		COALESCE(
			fse.error_j,
			rse.error_j
		) error_j,
		ST_AsGeoJSON(rsp.pp_geometry) preplot_geometry,
		ST_AsGeoJSON(rsp.geometry) raw_geometry,
		ST_AsGeoJSON(fs.geometry) final_geometry,
		rsp.pp_meta,
		rsp.meta raw_meta,
		fs.meta final_meta
		FROM raw_shots_preplots rsp
		INNER JOIN raw_shots_ij_error rse USING (sequence, point)
		LEFT JOIN final_shots fs USING (sequence, point)
		LEFT JOIN final_shots_ij_error fse USING (sequence, point)
		WHERE
			sequence = $1
		ORDER BY sequence, point;
	`;

	const values = [ sequence ];

	// Let us run shotpoint QCs
	for (qc of definitions.filter(i => i.iterate == "shots")) {
		if (!qc.disabled) {
			const cursor = client.query(new Cursor(text, values));
			let currentItem;
			while (currentItem = await fetchRow(cursor)) {
				currentItem._ = (k) => k.split(".").reduce((a, b) => typeof a != "undefined" ? a[b] : a, currentItem);

				const point = currentItem.point;
				const ctx = {currentItem, parameters}; // No variables for now

				const res = vm.runInNewContext(qc.check, ctx);

				if (!(point in results)) {
					results[point] = {};
				}
				results[point][qc.id] = res === true ? res : {remarks: res, labels: qc.labels};
			}

			if (qc.ignoreAllFailed) {
				const allFailed = Object.values(results).map(i => i[qc.id]).every(i => i !== true);
				if (allFailed) {
					console.info("IGNORING ALL FAILED", qc.id);
					for (const point in results) {
						delete results[point][qc.id];
					}
				}
			}
			cursor.close();
		}
	}

	client.release();
	return results;
}

module.exports = runShotQCs;
