import { app } from "../../../scripts/app.js";
import { $el } from "../../../scripts/ui.js";
import { ModelInfoDialog } from "./common/modelInfoDialog.js";
import { addMenuHandler } from "./common/utils.js";

const MAX_TAGS = 500;

class LoraInfoDialog extends ModelInfoDialog {
	getTagFrequency() {
		if (!this.metadata.ss_tag_frequency) return [];

		const datasets = JSON.parse(this.metadata.ss_tag_frequency);
		const tags = {};
		for (const setName in datasets) {
			const set = datasets[setName];
			for (const t in set) {
				if (t in tags) {
					tags[t] += set[t];
				} else {
					tags[t] = set[t];
				}
			}
		}

		return Object.entries(tags).sort((a, b) => b[1] - a[1]);
	}

	getResolutions() {
		let res = [];
		if (this.metadata.ss_bucket_info) {
			const parsed = JSON.parse(this.metadata.ss_bucket_info);
			if (parsed?.buckets) {
				for (const { resolution, count } of Object.values(parsed.buckets)) {
					res.push([count, `${resolution.join("x")} * ${count}`]);
				}
			}
		}
		res = res.sort((a, b) => b[0] - a[0]).map((a) => a[1]);
		let r = this.metadata.ss_resolution;
		if (r) {
			const s = r.split(",");
			const w = s[0].replace("(", "");
			const h = s[1].replace(")", "");
			res.push(`${w.trim()}x${h.trim()} (Base res)`);
		} else if ((r = this.metadata["modelspec.resolution"])) {
			res.push(r + " (Base res");
		}
		if (!res.length) {
			res.push("⚠️ Unknown");
		}
		return res;
	}

	getTagList(tags) {
		return tags.map((t) =>
			$el(
				"li.pysssss-model-tag",
				{
					dataset: {
						tag: t[0],
					},
					$: (el) => {
						el.onclick = () => {
							el.classList.toggle("pysssss-model-tag--selected");
						};
					},
				},
				[
					$el("p", {
						textContent: t[0],
					}),
					$el("span", {
						textContent: t[1],
					}),
				]
			)
		);
	}

	addTags() {
		let tags = this.getTagFrequency();
		let hasMore;
		if (tags?.length) {
			const c = tags.length;
			let list;
			if (c > MAX_TAGS) {
				tags = tags.slice(0, MAX_TAGS);
				hasMore = $el("p", [
					$el("span", { textContent: `⚠️ Only showing first ${MAX_TAGS} tags ` }),
					$el("a", {
						href: "#",
						textContent: `Show all ${c}`,
						onclick: () => {
							list.replaceChildren(...this.getTagList(this.getTagFrequency()));
							hasMore.remove();
						},
					}),
				]);
			}
			list = $el("ol.pysssss-model-tags-list", this.getTagList(tags));
			this.tags = $el("div", [list]);
		} else {
			this.tags = $el("p", { textContent: "⚠️ No tag frequency metadata found" });
		}

		this.content.append(this.tags);

		if (hasMore) {
			this.content.append(hasMore);
		}
	}

	async addInfo() {
		this.addInfoEntry("Name", this.metadata.ss_output_name || "⚠️ Unknown");
		this.addInfoEntry("Base Model", this.metadata.ss_sd_model_name || "⚠️ Unknown");
		this.addInfoEntry("Clip Skip", this.metadata.ss_clip_skip || "⚠️ Unknown");

		this.addInfoEntry(
			"Resolution",
			$el(
				"select",
				this.getResolutions().map((r) => $el("option", { textContent: r }))
			)
		);

		super.addInfo();
		const p = this.addCivitaiInfo();
		this.addTags();

		const info = await p;
		if (info) {
			$el(
				"p",
				{
					parent: this.content,
					textContent: "Trained Words: ",
				},
				[
					$el("pre", {
						textContent: info.trainedWords.join(", "),
						style: {
							whiteSpace: "pre-wrap",
							margin: "10px 0",
							background: "#222",
							padding: "5px",
							borderRadius: "5px",
							maxHeight: "250px",
							overflow: "auto",
						},
					}),
				]
			);
			$el("div", {
				parent: this.content,
				innerHTML: info.description,
				style: {
					maxHeight: "250px",
					overflow: "auto",
				},
			});
		}
	}

	createButtons() {
		const btns = super.createButtons();

		function copyTags(e, tags) {
			const textarea = $el("textarea", {
				parent: document.body,
				style: {
					position: "fixed",
				},
				textContent: tags.map((el) => el.dataset.tag).join(", "),
			});
			textarea.select();
			try {
				document.execCommand("copy");
				if (!e.target.dataset.text) {
					e.target.dataset.text = e.target.textContent;
				}
				e.target.textContent = "Copied " + tags.length + " tags";
				setTimeout(() => {
					e.target.textContent = e.target.dataset.text;
				}, 1000);
			} catch (ex) {
				prompt("Copy to clipboard: Ctrl+C, Enter", text);
			} finally {
				document.body.removeChild(textarea);
			}
		}

		btns.unshift(
			$el("button", {
				type: "button",
				textContent: "Copy Selected",
				onclick: (e) => {
					copyTags(e, [...this.tags.querySelectorAll(".pysssss-model-tag--selected")]);
				},
			}),
			$el("button", {
				type: "button",
				textContent: "Copy All",
				onclick: (e) => {
					copyTags(e, [...this.tags.querySelectorAll(".pysssss-model-tag")]);
				},
			})
		);

		return btns;
	}
}

class CheckpointInfoDialog extends ModelInfoDialog {
	async addInfo() {
		super.addInfo();
		const info = await this.addCivitaiInfo();
		if (info) {
			this.addInfoEntry("Base Model", info.baseModel || "⚠️ Unknown");

			$el("div", {
				parent: this.content,
				innerHTML: info.description,
				style: {
					maxHeight: "250px",
					overflow: "auto",
				},
			});
		}
	}
}

const generateNames = (prefix, start, end) => {
    const result = [];
    if (start < end) {
        for (let i = start; i <= end; i++) {
            result.push(`${prefix}${i}`);
        }
    } else {
        for (let i = start; i >= end; i--) {
            result.push(`${prefix}${i}`);
        }
    }
	return result
}

// NOTE: Orders reversed so they appear in ascending order
const infoHandler = {
    "Efficient Loader": {
        "loras": ["lora_name"],
        "checkpoints": ["ckpt_name"]
    },
    "Eff. Loader SDXL": {
        "checkpoints": ["refiner_ckpt_name", "base_ckpt_name"]
    },
    "LoRA Stacker": {
        "loras": generateNames("lora_name_", 50, 1)
    },
    "XY Input: LoRA": {
        "loras": generateNames("lora_name_", 50, 1)
    },
    "HighRes-Fix Script": {
        "checkpoints": ["hires_ckpt_name"]
    }
};

// Utility functions and other parts of your code remain unchanged

app.registerExtension({
    name: "efficiency.ModelInfo",
    beforeRegisterNodeDef(nodeType) {
        const types = infoHandler[nodeType.comfyClass];

        if (types) {
            addMenuHandler(nodeType, function (insertOption) { // Here, we are calling addMenuHandler
                let submenuItems = [];  // to store submenu items

                const addSubMenuOption = (type, widgetNames) => {
                    widgetNames.forEach(widgetName => {
                        const widgetValue = this.widgets.find(w => w.name === widgetName)?.value;
                        
                        // Check if widgetValue is "None"
                        if (!widgetValue || widgetValue === "None") {
                            return;
                        }
                        
                        let value = widgetValue;
                        if (value.content) {
                            value = value.content;
                        }
                        const cls = type === "loras" ? LoraInfoDialog : CheckpointInfoDialog;

                        const label = widgetName; 

                        // Push to submenuItems
                        submenuItems.push({
                            content: label,
                            callback: async () => {
                                new cls(value).show(type, value);
                            },
                        });
                    });
                };

                if (typeof types === 'object') {
                    Object.keys(types).forEach(type => {
                        addSubMenuOption(type, types[type]);
                    });
                }

                // If we have submenu items, use insertOption
                if (submenuItems.length) {
                    insertOption({ // Using insertOption here
                        content: "🔍 View model info...",
                        has_submenu: true,
                        callback: (value, options, e, menu, node) => {
                            new LiteGraph.ContextMenu(submenuItems, {
                                event: e,
                                callback: null,
                                parentMenu: menu,
                                node: node
                            });

                            return false; // This ensures the original context menu doesn't proceed
                        }
                    });
                }
            });
        }
    },
});






