import { jsxs, jsx } from 'react/jsx-runtime';
import React from 'react';

// ── Default Config ──────────────────────────────────────────────
const DEFAULT_BRUSH = {
    size: 20,
    opacity: 1,
    hardness: 0.8,
    color: "#ffffff",
    blendMode: "normal",
};
// ── Hook ────────────────────────────────────────────────────────
function useTexturePainter(width, height) {
    const [brush, setBrush] = React.useState(DEFAULT_BRUSH);
    const [layers, setLayers] = React.useState([]);
    const [activeLayerId, setActiveLayerId] = React.useState(null);
    const [tool, setTool] = React.useState("brush");
    const [renderVersion, setRenderVersion] = React.useState(0);
    const undoStackRef = React.useRef([]);
    React.useEffect(() => {
        if (typeof document === "undefined")
            return;
        const canvas = document.createElement("canvas");
        canvas.width = width;
        canvas.height = height;
        const ctx = canvas.getContext("2d");
        if (ctx) {
            ctx.fillStyle = "#808080";
            ctx.fillRect(0, 0, width, height);
        }
        const layer = {
            id: "base", name: "Base Color", visible: true, opacity: 1, canvas,
        };
        setLayers([layer]);
        setActiveLayerId("base");
    }, [width, height]);
    const addLayer = React.useCallback((name) => {
        if (typeof document === "undefined")
            return;
        const canvas = document.createElement("canvas");
        canvas.width = width;
        canvas.height = height;
        const id = `layer-${Date.now()}`;
        setLayers((prev) => [...prev, { id, name, visible: true, opacity: 1, canvas }]);
        setActiveLayerId(id);
    }, [width, height]);
    const removeLayer = React.useCallback((id) => {
        setLayers((prev) => prev.filter((l) => l.id !== id));
        setActiveLayerId((prev) => prev === id ? null : prev);
    }, []);
    const toggleLayerVisibility = React.useCallback((id) => {
        setLayers((prev) => prev.map((l) => l.id === id ? { ...l, visible: !l.visible } : l));
        setRenderVersion((v) => v + 1);
    }, []);
    const setLayerOpacity = React.useCallback((id, opacity) => {
        setLayers((prev) => prev.map((l) => l.id === id ? { ...l, opacity } : l));
        setRenderVersion((v) => v + 1);
    }, []);
    const beginStroke = React.useCallback(() => {
        const layer = layers.find((l) => l.id === activeLayerId);
        if (!layer)
            return;
        const ctx = layer.canvas.getContext("2d");
        if (!ctx)
            return;
        undoStackRef.current.push({
            layerId: layer.id,
            imageData: ctx.getImageData(0, 0, layer.canvas.width, layer.canvas.height),
        });
        if (undoStackRef.current.length > 40)
            undoStackRef.current.shift();
    }, [layers, activeLayerId]);
    const undo = React.useCallback(() => {
        const snapshot = undoStackRef.current.pop();
        if (!snapshot)
            return;
        const layer = layers.find((l) => l.id === snapshot.layerId);
        if (!layer)
            return;
        const ctx = layer.canvas.getContext("2d");
        if (!ctx)
            return;
        ctx.putImageData(snapshot.imageData, 0, 0);
        setRenderVersion((v) => v + 1);
    }, [layers]);
    const eyedrop = React.useCallback((x, y) => {
        // Sample composite color from all visible layers
        if (typeof document === "undefined")
            return;
        const tmp = document.createElement("canvas");
        tmp.width = width;
        tmp.height = height;
        const ctx = tmp.getContext("2d");
        if (!ctx)
            return;
        for (const layer of layers) {
            if (!layer.visible)
                continue;
            ctx.globalAlpha = layer.opacity;
            ctx.drawImage(layer.canvas, 0, 0);
        }
        const px = ctx.getImageData(Math.round(x), Math.round(y), 1, 1).data;
        const hex = `#${px[0].toString(16).padStart(2, "0")}${px[1].toString(16).padStart(2, "0")}${px[2].toString(16).padStart(2, "0")}`;
        setBrush((b) => ({ ...b, color: hex }));
        setTool("brush");
    }, [layers, width, height]);
    const paintStroke = React.useCallback((x, y) => {
        const layer = layers.find((l) => l.id === activeLayerId);
        if (!layer)
            return;
        const ctx = layer.canvas.getContext("2d");
        if (!ctx)
            return;
        ctx.globalAlpha = brush.opacity;
        if (tool === "eraser") {
            ctx.globalCompositeOperation = "destination-out";
            ctx.beginPath();
            ctx.arc(x, y, brush.size / 2, 0, Math.PI * 2);
            ctx.fill();
            ctx.globalCompositeOperation = "source-over";
        }
        else if (tool === "brush") {
            const gradient = ctx.createRadialGradient(x, y, 0, x, y, brush.size / 2);
            gradient.addColorStop(0, brush.color);
            gradient.addColorStop(brush.hardness, brush.color);
            gradient.addColorStop(1, "transparent");
            ctx.fillStyle = gradient;
            ctx.beginPath();
            ctx.arc(x, y, brush.size / 2, 0, Math.PI * 2);
            ctx.fill();
        }
        else if (tool === "fill") {
            ctx.fillStyle = brush.color;
            ctx.fillRect(0, 0, width, height);
        }
        ctx.globalAlpha = 1;
        setRenderVersion((v) => v + 1);
    }, [layers, activeLayerId, brush, tool, width, height]);
    const flattenToBlob = React.useCallback(async () => {
        if (typeof document === "undefined")
            return null;
        const canvas = document.createElement("canvas");
        canvas.width = width;
        canvas.height = height;
        const ctx = canvas.getContext("2d");
        if (!ctx)
            return null;
        for (const layer of layers) {
            if (!layer.visible)
                continue;
            ctx.globalAlpha = layer.opacity;
            ctx.drawImage(layer.canvas, 0, 0);
        }
        ctx.globalAlpha = 1;
        return new Promise((resolve) => canvas.toBlob(resolve, "image/png"));
    }, [layers, width, height]);
    return {
        brush, setBrush,
        layers, addLayer, removeLayer,
        activeLayerId, setActiveLayerId,
        tool, setTool,
        paintStroke,
        flattenToBlob,
        beginStroke, undo, canUndo: undoStackRef.current.length > 0,
        toggleLayerVisibility, setLayerOpacity,
        eyedrop, renderVersion,
    };
}
// ── Component ───────────────────────────────────────────────────
/** 3D texture painting tool with UV-space brush painting, zoom/pan, and layers. */
const Nice3DTexturePainter = ({ textureWidth = 1024, textureHeight = 1024, onSave, className = "", }) => {
    const painter = useTexturePainter(textureWidth, textureHeight);
    const canvasRef = React.useRef(null);
    const isPainting = React.useRef(false);
    const [zoom, setZoom] = React.useState(0.5);
    const [panOffset, setPanOffset] = React.useState({ x: 0, y: 0 });
    const isPanning = React.useRef(false);
    const lastPan = React.useRef({ x: 0, y: 0 });
    const [cursorPos, setCursorPos] = React.useState(null);
    const pw = Math.round(textureWidth * zoom);
    const ph = Math.round(textureHeight * zoom);
    // Render composite texture to preview
    React.useEffect(() => {
        const canvas = canvasRef.current;
        if (!canvas)
            return;
        const ctx = canvas.getContext("2d");
        if (!ctx)
            return;
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        const size = 8;
        for (let y = 0; y < canvas.height; y += size) {
            for (let x = 0; x < canvas.width; x += size) {
                ctx.fillStyle = ((x + y) / size) % 2 === 0 ? "#ccc" : "#fff";
                ctx.fillRect(x, y, size, size);
            }
        }
        for (const layer of painter.layers) {
            if (!layer.visible)
                continue;
            ctx.globalAlpha = layer.opacity;
            ctx.drawImage(layer.canvas, 0, 0, canvas.width, canvas.height);
        }
        ctx.globalAlpha = 1;
    }, [painter.layers, painter.renderVersion, zoom]);
    const screenToTexture = (e) => {
        var _a;
        const rect = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
        if (!rect)
            return { x: 0, y: 0 };
        return {
            x: ((e.clientX - rect.left) / rect.width) * textureWidth,
            y: ((e.clientY - rect.top) / rect.height) * textureHeight,
        };
    };
    const handlePointerDown = (e) => {
        if (e.button === 1) {
            isPanning.current = true;
            lastPan.current = { x: e.clientX, y: e.clientY };
            e.preventDefault();
            return;
        }
        if (painter.tool === "eyedropper") {
            const { x, y } = screenToTexture(e);
            painter.eyedrop(x, y);
            return;
        }
        painter.beginStroke();
        isPainting.current = true;
        const { x, y } = screenToTexture(e);
        painter.paintStroke(x, y);
        e.target.setPointerCapture(e.pointerId);
    };
    const handlePointerMove = (e) => {
        const { x, y } = screenToTexture(e);
        setCursorPos({ x: Math.round(x), y: Math.round(y) });
        if (isPanning.current) {
            setPanOffset((prev) => ({
                x: prev.x + e.clientX - lastPan.current.x,
                y: prev.y + e.clientY - lastPan.current.y,
            }));
            lastPan.current = { x: e.clientX, y: e.clientY };
            return;
        }
        if (!isPainting.current)
            return;
        painter.paintStroke(x, y);
    };
    const handlePointerUp = () => {
        isPainting.current = false;
        isPanning.current = false;
    };
    const handleWheel = (e) => {
        e.preventDefault();
        setZoom((z) => Math.max(0.1, Math.min(4, z + (e.deltaY > 0 ? -0.05 : 0.05))));
    };
    const handleSave = async () => {
        const blob = await painter.flattenToBlob();
        if (blob)
            onSave === null || onSave === void 0 ? void 0 : onSave(blob);
    };
    const toolIcons = { brush: "🖌️", eraser: "🧹", eyedropper: "💧", fill: "🪣" };
    const btnStyle = (active) => ({
        padding: "4px 8px", border: "none", borderRadius: 3, cursor: "pointer", fontSize: 11,
        background: active ? "#339af0" : "#2c2e33", color: active ? "#fff" : "#c1c2c5",
        display: "flex", alignItems: "center", gap: 4,
    });
    const toolCursor = painter.tool === "eyedropper" ? "crosshair" : painter.tool === "brush" ? "crosshair" : painter.tool === "eraser" ? "cell" : "crosshair";
    return (jsxs("div", { className: `nice-3d-texture-painter ${className}`, style: { display: "flex", gap: 8, background: "#1a1b1e", color: "#c1c2c5", padding: 12, borderRadius: 8 }, children: [jsxs("div", { style: { width: 140, fontSize: 11, display: "flex", flexDirection: "column", gap: 4 }, children: [jsx("strong", { style: { fontSize: 12 }, children: "Tools" }), ["brush", "eraser", "eyedropper", "fill"].map((t) => (jsxs("button", { onClick: () => painter.setTool(t), style: btnStyle(painter.tool === t), children: [toolIcons[t], " ", t.charAt(0).toUpperCase() + t.slice(1), " ", jsx("span", { style: { color: "#868e96", marginLeft: "auto" }, children: t === "brush" ? "B" : t === "eraser" ? "E" : t === "eyedropper" ? "I" : "G" })] }, t))), jsx("hr", { style: { border: "none", borderTop: "1px solid #373a40", width: "100%", margin: "4px 0" } }), jsx("div", { style: { display: "flex", justifyContent: "space-between" }, children: jsx("button", { onClick: () => painter.undo(), style: btnStyle(false), title: "Undo (Ctrl+Z)", children: "\u21A9 Undo" }) }), jsx("hr", { style: { border: "none", borderTop: "1px solid #373a40", width: "100%", margin: "4px 0" } }), jsxs("label", { children: ["Size: ", painter.brush.size, "px"] }), jsx("input", { type: "range", min: 1, max: 100, value: painter.brush.size, onChange: (e) => painter.setBrush({ ...painter.brush, size: Number(e.target.value) }), style: { width: "100%" } }), jsxs("label", { children: ["Opacity: ", Math.round(painter.brush.opacity * 100), "%"] }), jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: painter.brush.opacity, onChange: (e) => painter.setBrush({ ...painter.brush, opacity: Number(e.target.value) }), style: { width: "100%" } }), jsxs("label", { children: ["Hardness: ", Math.round(painter.brush.hardness * 100), "%"] }), jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: painter.brush.hardness, onChange: (e) => painter.setBrush({ ...painter.brush, hardness: Number(e.target.value) }), style: { width: "100%" } }), jsx("label", { children: "Blend Mode" }), jsxs("select", { value: painter.brush.blendMode, onChange: (e) => painter.setBrush({ ...painter.brush, blendMode: e.target.value }), style: { width: "100%", padding: 2, background: "#2c2e33", color: "#c1c2c5", border: "1px solid #373a40", borderRadius: 3, fontSize: 10 }, children: [jsx("option", { value: "normal", children: "Normal" }), jsx("option", { value: "multiply", children: "Multiply" }), jsx("option", { value: "screen", children: "Screen" }), jsx("option", { value: "overlay", children: "Overlay" })] }), jsx("label", { children: "Color" }), jsxs("div", { style: { display: "flex", gap: 4, alignItems: "center" }, children: [jsx("input", { type: "color", value: painter.brush.color, onChange: (e) => painter.setBrush({ ...painter.brush, color: e.target.value }), style: { width: 32, height: 24, border: "none", cursor: "pointer" } }), jsx("span", { style: { fontFamily: "monospace", fontSize: 10 }, children: painter.brush.color })] }), jsx("hr", { style: { border: "none", borderTop: "1px solid #373a40", width: "100%", margin: "4px 0" } }), jsxs("label", { children: ["Zoom: ", Math.round(zoom * 100), "%"] }), jsxs("div", { style: { display: "flex", gap: 2 }, children: [jsx("button", { onClick: () => setZoom((z) => Math.max(0.1, z - 0.1)), style: btnStyle(false), children: "\u2212" }), jsx("button", { onClick: () => setZoom(0.5), style: btnStyle(false), children: "Reset" }), jsx("button", { onClick: () => setZoom((z) => Math.min(4, z + 0.1)), style: btnStyle(false), children: "+" })] })] }), jsxs("div", { style: { flex: 1, overflow: "hidden", position: "relative", background: "#141517", borderRadius: 6 }, onWheel: handleWheel, children: [jsx("div", { style: { transform: `translate(${panOffset.x}px, ${panOffset.y}px)`, display: "inline-block", padding: 16 }, children: jsx("canvas", { ref: canvasRef, width: pw, height: ph, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, style: { cursor: toolCursor, borderRadius: 4, border: "1px solid #373a40" } }) }), jsxs("div", { style: { position: "absolute", bottom: 4, left: 8, fontSize: 10, color: "#868e96", display: "flex", gap: 12 }, children: [jsxs("span", { children: [textureWidth, "\u00D7", textureHeight] }), cursorPos && jsxs("span", { children: ["X: ", cursorPos.x, " Y: ", cursorPos.y] }), jsxs("span", { children: ["Zoom: ", Math.round(zoom * 100), "%"] })] })] }), jsxs("div", { style: { width: 160, fontSize: 11, display: "flex", flexDirection: "column", gap: 4 }, children: [jsx("strong", { style: { fontSize: 12 }, children: "Layers" }), jsx("div", { style: { flex: 1, overflowY: "auto", display: "flex", flexDirection: "column", gap: 2 }, children: [...painter.layers].reverse().map((l) => (jsxs("div", { style: {
                                padding: "4px 6px", borderRadius: 3,
                                background: painter.activeLayerId === l.id ? "#339af0" : "#2c2e33",
                                color: painter.activeLayerId === l.id ? "#fff" : "#c1c2c5",
                            }, children: [jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4, cursor: "pointer" }, onClick: () => painter.setActiveLayerId(l.id), children: [jsx("button", { onClick: (e) => { e.stopPropagation(); painter.toggleLayerVisibility(l.id); }, style: { background: "transparent", border: "none", cursor: "pointer", padding: 0, color: l.visible ? "#c1c2c5" : "#5c5f66", fontSize: 12 }, title: l.visible ? "Hide layer" : "Show layer", children: l.visible ? "👁" : "👁‍🗨" }), jsx("span", { style: { flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: l.name }), l.id !== "base" && (jsx("button", { onClick: (e) => { e.stopPropagation(); painter.removeLayer(l.id); }, style: { background: "transparent", border: "none", color: "#ff6b6b", cursor: "pointer", padding: 0, fontSize: 10 }, children: "\u2715" }))] }), jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4, marginTop: 2 }, children: [jsx("span", { style: { fontSize: 9, color: "#868e96" }, children: "\u03B1" }), jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: l.opacity, onChange: (e) => painter.setLayerOpacity(l.id, Number(e.target.value)), style: { flex: 1, height: 12 } }), jsxs("span", { style: { fontSize: 9, minWidth: 24, textAlign: "right" }, children: [Math.round(l.opacity * 100), "%"] })] })] }, l.id))) }), jsx("button", { onClick: () => painter.addLayer(`Layer ${painter.layers.length + 1}`), style: { padding: "4px 8px", border: "none", borderRadius: 3, cursor: "pointer", background: "#2c2e33", color: "#c1c2c5" }, children: "+ Add Layer" }), jsx("hr", { style: { border: "none", borderTop: "1px solid #373a40", width: "100%", margin: "4px 0" } }), jsx("button", { onClick: handleSave, style: { padding: "6px 8px", background: "#2f9e44", color: "#fff", border: "none", borderRadius: 3, cursor: "pointer", fontWeight: "bold" }, children: "Save Texture" })] })] }));
};

export { Nice3DTexturePainter, useTexturePainter };
//# sourceMappingURL=Nice3DTexturePainter.js.map
