import { app } from "/scripts/app.js";

// Use widget values and dates in output filenames

app.registerExtension({
	name: "Comfy.SaveImageExtraOutput",
	async beforeRegisterNodeDef(nodeType, nodeData, app) {
		if (nodeData.name === "SaveImage") {
			const onNodeCreated = nodeType.prototype.onNodeCreated;

         // Simple date formatter
			const parts = {
				d: (d) => d.getDate(),
				M: (d) => d.getMonth() + 1,
				h: (d) => d.getHours(),
				m: (d) => d.getMinutes(),
				s: (d) => d.getSeconds(),
			};
			const format =
				Object.keys(parts)
					.map((k) => k + k + "?")
					.join("|") + "|yyy?y?";

			function formatDate(text, date) {
				return text.replace(new RegExp(format, "g"), function (text) {
					if (text === "yy") return (date.getFullYear() + "").substring(2);
					if (text === "yyyy") return date.getFullYear();
					if (text[0] in parts) {
						const p = parts[text[0]](date);
						return (p + "").padStart(text.length, "0");
					}
					return text;
				});
			}

         // When the SaveImage node is created we want to override the serialization of the output name widget to run our S&R
			nodeType.prototype.onNodeCreated = function () {
				const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;

				const widget = this.widgets.find((w) => w.name === "filename_prefix");
				widget.serializeValue = () => {
					return widget.value.replace(/%([^%]+)%/g, function (match, text) {
						const split = text.split(".");
						if (split.length !== 2) {
                     // Special handling for dates
							if (split[0].startsWith("date:")) {
								return formatDate(split[0].substring(5), new Date());
							}

							if (text !== "width" && text !== "height") {
								// Dont warn on standard replacements
								console.warn("Invalid replacement pattern", text);
							}
							return match;
						}

						// Find node with matching S&R property name
						let nodes = app.graph._nodes.filter((n) => n.properties?.["Node name for S&R"] === split[0]);
						// If we cant, see if there is a node with that title
						if (!nodes.length) {
							nodes = app.graph._nodes.filter((n) => n.title === split[0]);
						}
						if (!nodes.length) {
							console.warn("Unable to find node", split[0]);
							return match;
						}

						if (nodes.length > 1) {
							console.warn("Multiple nodes matched", split[0], "using first match");
						}

						const node = nodes[0];

						const widget = node.widgets?.find((w) => w.name === split[1]);
						if (!widget) {
							console.warn("Unable to find widget", split[1], "on node", split[0], node);
							return match;
						}

						return ((widget.value ?? "") + "").replaceAll(/\/|\\/g, "_");
					});
				};

				return r;
			};
		} else {
         // When any other node is created add a property to alias the node
			const onNodeCreated = nodeType.prototype.onNodeCreated;
			nodeType.prototype.onNodeCreated = function () {
				const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;

				if (!this.properties || !("Node name for S&R" in this.properties)) {
					this.addProperty("Node name for S&R", this.constructor.type, "string");
				}

				return r;
			};
		}
	},
});
