"use strict";

const NoChange = require("./util/no-change");
const deriveNode = require("../derive-node");
const operations = require("../operations");

module.exports = {
	name: "test-context",
	category: [ "testing" ],
	visitors: {
		columnName: (node, { setState }) => {
			setState("seenColumn", node.name);

			return NoChange;
		},
		select: (node, { registerStateHandler, defer }) => {
			let seenColumns = new Set();

			registerStateHandler("seenColumnsInWhere", (names) => {
				for (let name of names) {
					seenColumns = seenColumns.add(name);
				}
			});
			
			// FIXME: Definitely need better AST modification/derivation tools... probably some sort of deep-modifying utility, for starters. Maybe merge-by-template can be of use here? With a custom AST node merger? It probably doesn't support non-enumerable properties correctly right now, though...

			return defer(() => {
				console.log("Seen columns in WHERE in SELECT:", seenColumns);

				let onlyColumnsClause = node.clauses.find((clause) => clause.type === "onlyColumns");

				let columnsAlreadyAdded = onlyColumnsClause != null && Array.from(seenColumns).every((column) => {
					return onlyColumnsClause.columns.some((existingColumn) => existingColumn.name === column);
				});

				if (!columnsAlreadyAdded) {
					// NOTE: This is a good test case for optimizer stability! Just returning a derived node in every case.
					let newOnlyColumnsClause = (onlyColumnsClause == null)
						? operations.onlyColumns(Array.from(seenColumns))
						: deriveNode(onlyColumnsClause, {
							columns: onlyColumnsClause.columns.concat(Array.from(seenColumns).map((columnName) => {
								return operations.column(columnName);
							}))
						});

					return deriveNode(node, {
						clauses: node.clauses
							.filter((clause) => clause.type !== "onlyColumns")
							.concat([ newOnlyColumnsClause ])
					});
				} else {
					return NoChange;
				}
			});
		},
		where: (node, { registerStateHandler, defer, setState }) => {
			let seenColumns = [];

			registerStateHandler("seenColumn", (name) => seenColumns.push(name));

			return defer(() => {
				setState("seenColumnsInWhere", seenColumns);
				return NoChange;
			});

			// let seenColumns = [];
			// let id = Math.random();

			// registerStateHandler("seenColumn", (name) => {
			// 	seenColumns.push(name);
			// });
			
			// console.log("Scheduling defer", id);
			
			// return defer(() => {
			// 	console.log("Defer called", id);
				
			// 	// MARKER: This gets called twice, but should only be called once!
			// 	// console.log("Seen columns in WHERE:", seenColumns, require("util").inspect(node, {colors:true,depth:null}));
			// 	console.log("Seen columns in WHERE:", seenColumns);
			// 	return NoChange;
			// });
		}
	}
};
