import { app } from "../../scripts/app.js";
function showPreviewCanvas(node, app) {

    const widget = {
        type: "customCanvas",
        name: "mask-rect-area-canvas",
        get value() {
            return this.canvas.value;
        },
        set value(x) {
            this.canvas.value = x;
        },
        draw: function (ctx, node, widgetWidth, widgetY) {

            // If we are initially offscreen when created we wont have received a resize event
            // Calculate it here instead
            if (!node.canvasHeight) {
                computeCanvasSize(node, node.size);
            }

            const visible = true;
            const t = ctx.getTransform();
            const margin = 12;
            const border = 2;
            const widgetHeight = node.canvasHeight;
            const width = 512;
            const height = 512;
            const scale = Math.min((widgetWidth - margin * 3) / width, (widgetHeight - margin * 3) / height);
            const blurRadius = node.properties["blur_radius"] || 0;
            const index = 0;

            Object.assign(this.canvas.style, {
                left: `${t.e}px`,
                top: `${t.f + (widgetY * t.d)}px`,
                width: `${widgetWidth * t.a}px`,
                height: `${widgetHeight * t.d}px`,
                position: "absolute",
                zIndex: 1,
                fontSize: `${t.d * 10.0}px`,
                pointerEvents: "none"
            });

            this.canvas.hidden = !visible;

            let backgroundWidth = width * scale;
            let backgroundHeight = height * scale;
            let xOffset = margin;
            if (backgroundWidth < widgetWidth) {
                xOffset += (widgetWidth - backgroundWidth) / 2 - margin;
            }
            let yOffset = (margin / 2);
            if (backgroundHeight < widgetHeight) {
                yOffset += (widgetHeight - backgroundHeight) / 2 - margin;
            }

            let widgetX = xOffset;
            widgetY = widgetY + yOffset;

            // Draw the background border
            ctx.fillStyle = globalThis.LiteGraph.WIDGET_OUTLINE_COLOR;
            ctx.fillRect(widgetX - border, widgetY - border, backgroundWidth + border * 2, backgroundHeight + border * 2);

            // Draw the main background area 
            ctx.fillStyle = globalThis.LiteGraph.WIDGET_BGCOLOR;
            ctx.fillRect(widgetX, widgetY, backgroundWidth, backgroundHeight);

            // Draw the conditioning zone
            let [x, y, w, h] = getDrawArea(node, backgroundWidth, backgroundHeight);

            ctx.fillStyle = getDrawColor(0, "80");
            ctx.fillRect(widgetX + x, widgetY + y, w, h);
            ctx.beginPath();
            ctx.lineWidth = 1;

            // Draw grid lines
            for (let x = 0; x <= width / 64; x += 1) {
                ctx.moveTo(widgetX + x * 64 * scale, widgetY);
                ctx.lineTo(widgetX + x * 64 * scale, widgetY + backgroundHeight);
            }

            for (let y = 0; y <= height / 64; y += 1) {
                ctx.moveTo(widgetX, widgetY + y * 64 * scale);
                ctx.lineTo(widgetX + backgroundWidth, widgetY + y * 64 * scale);
            }

            ctx.strokeStyle = "#66666650";
            ctx.stroke();
            ctx.closePath();

            // Draw current zone
            let [sx, sy, sw, sh] = getDrawArea(node, backgroundWidth, backgroundHeight);

            ctx.fillStyle = getDrawColor(0, "80");
            ctx.fillRect(widgetX + sx, widgetY + sy, sw, sh);

            ctx.fillStyle = getDrawColor(0, "40");
            ctx.fillRect(widgetX + sx + border, widgetY + sy + border, sw - border * 2, sh - border * 2);

            // Draw white border around the current zone
            ctx.strokeStyle = globalThis.LiteGraph.NODE_SELECTED_TITLE_COLOR;
            ctx.lineWidth = 2;
            ctx.strokeRect(widgetX + sx, widgetY + sy, sw, sh);
            //ctx.strokeRect(finalSX, finalSY, finalSW, finalSH);

            // Display
            ctx.beginPath();

            ctx.arc(LiteGraph.NODE_SLOT_HEIGHT * 0.5, LiteGraph.NODE_SLOT_HEIGHT * (index + 0.5) + 4, 4, 0, Math.PI * 2);
            ctx.fill();

            ctx.lineWidth = 1;
            ctx.strokeStyle = "white";
            ctx.stroke();
            ctx.lineWidth = 1;
            ctx.closePath();

            // Draw progress bar canvas
            if (backgroundWidth < widgetWidth) {
                xOffset += (widgetWidth - backgroundWidth) / 2 - margin;
            }

            const barHeight = 8;
            let widgetYBar = widgetY + backgroundHeight + margin;

            // Draw progress bar border
            ctx.fillStyle = globalThis.LiteGraph.WIDGET_OUTLINE_COLOR;
            ctx.fillRect(
                    widgetX - border,
                    widgetYBar - border,
                    backgroundWidth + border * 2,
                    barHeight + border * 2
                    );

            // Draw progress bar area
            ctx.fillStyle = globalThis.LiteGraph.WIDGET_BGCOLOR; // Mismo color de fondo que el canvas
            ctx.fillRect(
                    widgetX,
                    widgetYBar,
                    backgroundWidth,
                    barHeight
                    );

            // Draw progress bar grid
            ctx.beginPath();
            ctx.lineWidth = 1;
            ctx.strokeStyle = "#66666650";

            // Determine max lines
            const numLines = Math.floor(backgroundWidth / 64);

            // Draw progress bar grid
            for (let x = 0; x <= width / 64; x += 1) {
                ctx.moveTo(widgetX + x * 64 * scale, widgetYBar);
                ctx.lineTo(widgetX + x * 64 * scale, widgetYBar + barHeight);
            }
            ctx.stroke();
            ctx.closePath();

            // Draw progress bar
            const progress = Math.min(blurRadius / 255, 1);
            ctx.fillStyle = "rgba(0, 120, 255, 0.5)";

            ctx.fillRect(
                    widgetX,
                    widgetYBar,
                    backgroundWidth * progress,
                    barHeight
                    );
        }
    };

    widget.canvas = document.createElement("canvas");
    widget.canvas.className = "mask-rect-area-canvas";
    widget.parent = node;

    document.body.appendChild(widget.canvas);
    node.addCustomWidget(widget);

    app.canvas.onDrawBackground = function () {
        // Draw node isnt fired once the node is off the screen
        // if it goes off screen quickly, the input may not be removed
        // this shifts it off screen so it can be moved back if the node is visible.
        for (let n in app.graph._nodes) {
            n = app.graph._nodes[n];
            for (let w in n.widgets) {
                let wid = n.widgets[w];
                if (Object.hasOwn(wid, "canvas")) {
                    wid.canvas.style.left = -8000 + "px";
                    wid.canvas.style.position = "absolute";
                }
            }
        }
    };

    node.onResize = function (size) {
        computeCanvasSize(node, size);
    };

    return {minWidth: 200, minHeight: 200, widget};
}

app.registerExtension({
    name: 'drltdata.MaskRectArea',
    async beforeRegisterNodeDef(nodeType, nodeData, app) {
        if (nodeData.name === "MaskRectArea") {
            const onNodeCreated = nodeType.prototype.onNodeCreated;
            nodeType.prototype.onNodeCreated = function () {
                const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;

                this.setProperty("width", 512);
                this.setProperty("height", 512);
                this.setProperty("x", 0);
                this.setProperty("y", 0);
                this.setProperty("w", 50);
                this.setProperty("h", 50);
                this.setProperty("blur_radius", 0);

                this.selected = false;
                this.index = 3;
                this.serialize_widgets = true;

                CUSTOM_INT(this, "x", 0, function (v, _, node) {
                    this.value = Math.max(0, Math.min(100, Math.round(v))); // Limitar entre 0 y 100
                    node.properties["x"] = this.value;
                });
                CUSTOM_INT(this, "y", 0, function (v, _, node) {
                    this.value = Math.max(0, Math.min(100, Math.round(v)));
                    node.properties["y"] = this.value;
                });
                CUSTOM_INT(this, "w", 50, function (v, _, node) {
                    this.value = Math.max(0, Math.min(100, Math.round(v)));
                    node.properties["w"] = this.value;
                });
                CUSTOM_INT(this, "h", 50, function (v, _, node) {
                    this.value = Math.max(0, Math.min(100, Math.round(v)));
                    node.properties["h"] = this.value;
                });
                CUSTOM_INT(this, "blur_radius", 0, function (v, _, node) {
                    this.value = Math.round(v) || 0;
                    node.properties["blur_radius"] = this.value;
                },
                        {"min": 0, "max": 255, "step": 10}
                );

                showPreviewCanvas(this, app);

                this.onSelected = function () {
                    this.selected = true;
                };
                this.onDeselected = function () {
                    this.selected = false;
                };

                return r;
            };
        }
    }
});

// Calculate the drawing area using percentage-based properties.
function getDrawArea(node, backgroundWidth, backgroundHeight) {
    // Convert percentages to actual pixel values based on the background dimensions
    let x = (node.properties["x"] / 100) * backgroundWidth;
    let y = (node.properties["y"] / 100) * backgroundHeight;
    let w = (node.properties["w"] / 100) * backgroundWidth;
    let h = (node.properties["h"] / 100) * backgroundHeight;

    // Ensure the values do not exceed the background boundaries
    if (x > backgroundWidth) {
        x = backgroundWidth;
    }
    if (y > backgroundHeight) {
        y = backgroundHeight;
    }

    // Adjust width and height to fit within the background dimensions
    if (x + w > backgroundWidth) {
        w = Math.max(0, backgroundWidth - x);
    }
    if (y + h > backgroundHeight) {
        h = Math.max(0, backgroundHeight - y);
    }

    return [x, y, w, h];
}

function CUSTOM_INT(node, inputName, val, func, config = {}) {
    return {
        widget: node.addWidget(
                "number",
                inputName,
                val,
                func,
                Object.assign({}, {min: 0, max: 100, step: 10, precision: 0}, config)
                )
    };
}

function getDrawColor(percent, alpha) {
    let h = 360 * percent;
    let s = 50;
    let l = 50;
    l /= 100;
    const a = s * Math.min(l, 1 - l) / 100;
    const f = n => {
        const k = (n + h / 30) % 12;
        const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
        return Math.round(255 * color).toString(16).padStart(2, '0');   // convert to Hex and prefix "0" if needed
    };
    return `#${f(0)}${f(8)}${f(4)}${alpha}`;
}

function computeCanvasSize(node, size) {
    if (node.widgets[0].last_y == null) {
        return;
    }

    const MIN_HEIGHT = 200;
    const MIN_WIDTH = 200;

    let y = LiteGraph.NODE_WIDGET_HEIGHT * Math.max(node.inputs.length, node.outputs.length) + 5;
    let freeSpace = size[1] - y;

    // Compute the height of all non-customCanvas widgets
    let widgetHeight = 0;
    for (let i = 0; i < node.widgets.length; i++) {
        const w = node.widgets[i];
        if (w.type !== "customCanvas") {
            if (w.computeSize) {
                widgetHeight += w.computeSize()[1] + 4;
            } else {
                widgetHeight += LiteGraph.NODE_WIDGET_HEIGHT + 5;
            }
        }
    }

    // Ensure there is enough vertical space
    freeSpace -= widgetHeight;

    // Adjust the height of the node if needed
    if (freeSpace < MIN_HEIGHT) {
        freeSpace = MIN_HEIGHT;
        node.size[1] = y + widgetHeight + freeSpace;
        node.graph.setDirtyCanvas(true);
    }

    // Ensure the node width meets the minimum width requirement
    if (node.size[0] < MIN_WIDTH) {
        node.size[0] = MIN_WIDTH;
        node.graph.setDirtyCanvas(true);
    }

    // Position each of the widgets
    for (const w of node.widgets) {
        w.y = y;
        if (w.type === "customCanvas") {
            y += freeSpace;
        } else if (w.computeSize) {
            y += w.computeSize()[1] + 4;
        } else {
            y += LiteGraph.NODE_WIDGET_HEIGHT + 4;
        }
    }

    node.canvasHeight = freeSpace;
}
