<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>UV3Dapp</title>
    <link rel="stylesheet" href="https://andregazineu.github.io/madreculo/estilo.css">
    <script src="https://andregazineu.github.io/madreculo/cloud.js"></script>
    <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.5.0/model-viewer.min.js"></script>
</head>
<body>

    <h1></h1>

    <div class="checkbox-container">
    <div>
        <input type="checkbox" id="coffeeBag" name="model" value="https://andregazineu.github.io/madreculo/CAFE%20BRACAFE.glb">
        <label for="coffeeBag">Coffee Bag</label>
    </div>
    <div>
        <input type="checkbox" id="flowpack" name="model" value="https://andregazineu.github.io/madreculo/polenta.glb">
        <label for="flowpack">Flowpack</label>
    </div>
    <div>
        <input type="checkbox" id="vacuumCoffee" name="model" value="https://andregazineu.github.io/madreculo/Coffee_with_texture.glb">
        <label for="vacuumCoffee">Vacuum Coffee</label>
    </div>
    <div>
        <input type="checkbox" id="ziplock" name="model" value="https://andregazineu.github.io/madreculo/ziplock.glb">
        <label for="ziplock">Ziplock</label>
    </div>
    <div>
        <input type="checkbox" id="sachet" name="model" value="https://andregazineu.github.io/madreculo/Sachet.glb">
        <label for="sachet">Sachet</label>
    </div>
    <div>
        <input type="checkbox" id="pack2" name="model" value="https://andregazineu.github.io/madreculo/Pack2.glb">
        <label for="pack2">Pack 2</label>
    </div>
    <div>
        <input type="checkbox" id="melitta" name="model" value="https://andregazineu.github.io/madreculo/Melitta.glb">
        <label for="melitta">Melitta</label>
    </div>
    <div>
        <input type="checkbox" id="almofada" name="model" value="https://andregazineu.github.io/madreculo/Almofada.glb">
        <label for="almofada">Almofada</label>
    </div>
    <div>
        <input type="checkbox" id="pouchComBico" name="model" value="https://andregazineu.github.io/madreculo/Pouch%20Com%20bico.glb">
        <label for="pouchComBico">Pouch com bico</label>
    </div>
</div>


    <div class="container">
        <div id="dropzone">Arraste e solte a textura aqui</div>
        <div id="loadingPlaceholder">
            <div class="loader"></div>
        </div>
        <model-viewer id="viewer" src="" alt="Modelo 3D" auto-rotate camera-controls></model-viewer>
    </div>

    <i class="fas fa-video icon-medium disabled" id="renderBtn"></i>
    <i class="fas fa-ruler-combined icon-medium-ruler" id="openUVEditorBtn"></i>

    <div id="overlay"></div>

    <div id="uvEditorContainer">
        <div id="uvEditorControls">
            <button id="closeUVEditorBtn">Fechar</button>
            <button id="resetUVBtn">Salvar e Redefinir UV</button>
            <button id="toggleIslandMovementBtn">Habilitar Movimentação Individual de Ilhas UV</button>
        </div>
        <canvas id="uvCanvas"></canvas>

        <div class="texture-options-container">
            <h3>Escolha as Texturas</h3>
            <div>
                <input type="checkbox" id="normalMap1Checkbox" name="normalMap1">
                <label for="normalMap1Checkbox">Normal Map 1</label>
            </div>
            <div>
                <input type="checkbox" id="normalMap2Checkbox" name="normalMap2">
                <label for="normalMap2Checkbox">Normal Map 2</label>
            </div>
            <div>
                <input type="checkbox" id="metalCheckbox" name="metal">
                <label for="metalCheckbox">Aplicar Metalness</label>
            </div>
            <div>
                <input type="checkbox" id="roughnessCheckbox" name="roughness">
                <label for="roughnessCheckbox">Aplicar Roughness</label>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/three@0.143.0/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.143.0/examples/js/loaders/GLTFLoader.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.143.0/examples/js/exporters/GLTFExporter.js"></script>

    <script>
let model, texture, normalMap, textureLoaded = false;
let uvOffsetU = 0.000, uvOffsetV = 0.0;
let updatedUVs = null;
let isDragging = false;
let lastMouseX, lastMouseY;
let offsetX = 0, offsetY = 0;
let scale = 1;
let selectedIsland = null;
const islandOffsets = new Map();
let isIslandMovementEnabled = false;

/**
 * Novo: array global para armazenar ilhas que estão nas bordas
 * (ou seja, que tocam U=0, U=1, V=0 ou V=1 dentro de alguma tolerância).
 */
let edgeIslands = [];  
let currentEdgeIslandIndex = 0; // qual ilha de borda estamos selecionando no momento?

const dropzone = document.getElementById('dropzone');
const coffeeBagCheckbox = document.getElementById('coffeeBag');
const flowpackCheckbox = document.getElementById('flowpack');
const vacuumCoffeeCheckbox = document.getElementById('vacuumCoffee');
const ziplockCheckbox = document.getElementById('ziplock');
const sachetCheckbox = document.getElementById('sachet');
const pack2Checkbox = document.getElementById('pack2');
const melittaCheckbox = document.getElementById('melitta');
const almofadaCheckbox = document.getElementById('almofada');
const pouchComBicoCheckbox = document.getElementById('pouchComBico');
const metalCheckbox = document.getElementById('metalCheckbox');
const normalMap1Checkbox = document.getElementById('normalMap1Checkbox');
const normalMap2Checkbox = document.getElementById('normalMap2Checkbox');
const roughnessCheckbox = document.getElementById('roughnessCheckbox');
const viewer = document.getElementById('viewer');

viewer.addEventListener('dblclick', () => {
    if (!document.fullscreenElement) {
        viewer.requestFullscreen();
    } else {
        document.exitFullscreen();
    }
});

const renderBtn = document.getElementById('renderBtn');
const loadingPlaceholder = document.getElementById('loadingPlaceholder');
const openUVEditorBtn = document.getElementById('openUVEditorBtn');
const uvEditorContainer = document.getElementById('uvEditorContainer');
const closeUVEditorBtn = document.getElementById('closeUVEditorBtn');
const resetUVBtn = document.getElementById('resetUVBtn');
const toggleIslandMovementBtn = document.getElementById('toggleIslandMovementBtn');
const overlay = document.getElementById('overlay');
const uvCanvas = document.getElementById('uvCanvas');
const ctx = uvCanvas.getContext('2d');
let uvWidth = 500;
let uvHeight = 500;
uvCanvas.width = uvWidth;
uvCanvas.height = uvHeight;

const normalMapPaths = {
    normal1: 'https://andregazineu.github.io/madreculo/MetalGoldPaint002_NRM_2K_METALNESS.png',
    normal2: 'https://andregazineu.github.io/madreculo/Material_normal.png'
};

const metalMapPaths = {
    metal: 'https://andregazineu.github.io/madreculo/metal_0071_metallic_1k.jpg'
};

const roughnessMapPaths = {
    roughness: 'https://andregazineu.github.io/madreculo/plastic_0002_roughness_1k.jpg'
};

function initializeIslandOffsets(islandKey) {
    if (!islandOffsets.has(islandKey)) {
        islandOffsets.set(islandKey, { offsetX: 0, offsetY: 0, scale: 1 });
    }
    return islandOffsets.get(islandKey);
}

/**
 * Função para identificar se a ilha toca as bordas (U=0, U=1, V=0, V=1).
 * Se minU <= 0.01 ou maxU >= 0.99 (idem para V), consideramos "ilha de borda".
 */
function isIslandOnEdge(uvArray, island) {
    let minU = 1, maxU = 0;
    let minV = 1, maxV = 0;
    island.triangles.forEach(tri => {
        tri.indices.forEach(idx => {
            const u = uvArray[idx*2];
            const v = uvArray[idx*2 + 1];
            if (u < minU) minU = u;
            if (u > maxU) maxU = u;
            if (v < minV) minV = v;
            if (v > maxV) maxV = v;
        });
    });
    const tolerance = 0.01;
    // Se a ilha está "encostando" em qualquer borda...
    return (
        minU <= tolerance ||
        maxU >= 1 - tolerance ||
        minV <= tolerance ||
        maxV >= 1 - tolerance
    );
}

/**
 * Monta as ilhas de UV e já verifica quais estão na borda,
 * salvando em `edgeIslands`.
 */
function buildUVIslands(mesh) {
    const geometry = mesh.geometry;
    const uvAttribute = geometry.attributes.uv;
    const index = geometry.index;
    if (!uvAttribute || !index) return { islands: [] };

    const faceCount = index.count / 3;
    const parent = new Array(faceCount).fill(0).map((_, i) => i);

    function find(i) {
        if (parent[i] !== i) {
            parent[i] = find(parent[i]);
        }
        return parent[i];
    }

    function union(i, j) {
        const rootI = find(i);
        const rootJ = find(j);
        if (rootI !== rootJ) {
            parent[rootI] = rootJ;
        }
    }

    const edgeMap = new Map();

    for (let i = 0; i < faceCount; i++) {
        const idx0 = index.array[i * 3];
        const idx1 = index.array[i * 3 + 1];
        const idx2 = index.array[i * 3 + 2];

        const uv0 = [uvAttribute.getX(idx0), uvAttribute.getY(idx0)];
        const uv1 = [uvAttribute.getX(idx1), uvAttribute.getY(idx1)];
        const uv2 = [uvAttribute.getX(idx2), uvAttribute.getY(idx2)];

        const edges = [
            { a: idx0, b: idx1, uvA: uv0, uvB: uv1 },
            { a: idx1, b: idx2, uvA: uv1, uvB: uv2 },
            { a: idx2, b: idx0, uvA: uv2, uvB: uv0 },
        ];

        edges.forEach(edge => {
            const key = edge.a < edge.b ? `${edge.a}_${edge.b}` : `${edge.b}_${edge.a}`;
            if (!edgeMap.has(key)) {
                edgeMap.set(key, []);
            }
            edgeMap.get(key).push({ faceIndex: i, uvA: edge.uvA, uvB: edge.uvB });
        });
    }

    for (const faces of edgeMap.values()) {
        if (faces.length < 2) continue;
        const baseFace = faces[0];
        for (let i = 1; i < faces.length; i++) {
            const compareFace = faces[i];

            const sameUVs =
                baseFace.uvA[0] === compareFace.uvB[0] &&
                baseFace.uvA[1] === compareFace.uvB[1] &&
                baseFace.uvB[0] === compareFace.uvA[0] &&
                baseFace.uvB[1] === compareFace.uvA[1];

            if (sameUVs) {
                union(baseFace.faceIndex, compareFace.faceIndex);
            }
        }
    }

    const islandsMap = new Map();

    for (let i = 0; i < faceCount; i++) {
        const root = find(i);
        if (!islandsMap.has(root)) {
            islandsMap.set(root, []);
        }
        islandsMap.get(root).push(i);
    }

    const islands = [];

    islandsMap.forEach(faceIndices => {
        const island = { triangles: [] };
        faceIndices.forEach(faceIndex => {
            const idx0 = index.array[faceIndex * 3];
            const idx1 = index.array[faceIndex * 3 + 1];
            const idx2 = index.array[faceIndex * 3 + 2];
            island.triangles.push({ indices: [idx0, idx1, idx2] });
        });
        islands.push(island);
    });

    return { islands };
}

function modifyUVs(selectedIsland) {
    if (!selectedIsland || !selectedIsland.mesh) return;
    const mesh = selectedIsland.mesh;
    const islandIndex = selectedIsland.islandIndex;
    const islandKey = `${mesh.uuid}_${islandIndex}`;
    const uvIslandsData = mesh.userData.uvIslands;
    const islandTriangles = uvIslandsData.islands[islandIndex].triangles;
    const uvAttribute = mesh.geometry.attributes.uv;
    const originalUVs = mesh.userData.originalUVs;
    const islandData = initializeIslandOffsets(islandKey);

    let sumU = 0, sumV = 0, count = 0;
    const vertexIndicesSet = new Set();
    islandTriangles.forEach(triangle => {
        triangle.indices.forEach(vertexIndex => {
            if (!vertexIndicesSet.has(vertexIndex)) {
                vertexIndicesSet.add(vertexIndex);
                sumU += originalUVs[vertexIndex * 2];
                sumV += originalUVs[vertexIndex * 2 + 1];
                count++;
            }
        });
    });
    const centerU = sumU / count;
    const centerV = sumV / count;

    islandTriangles.forEach(triangle => {
        triangle.indices.forEach(vertexIndex => {
            const origU = originalUVs[vertexIndex * 2];
            const origV = originalUVs[vertexIndex * 2 + 1];
            uvAttribute.array[vertexIndex * 2] = ((origU - centerU) * islandData.scale) + centerU + islandData.offsetX;
            uvAttribute.array[vertexIndex * 2 + 1] = ((origV - centerV) * islandData.scale) + centerV + islandData.offsetY;
        });
    });
    uvAttribute.needsUpdate = true;
}

function drawUVMap() {
    if (!model) return;
    ctx.clearRect(0, 0, uvWidth, uvHeight);
    if (texture && texture.image) {
        ctx.drawImage(texture.image, 0, 0, uvWidth, uvHeight);
    } else {
        ctx.fillStyle = '#3c3f41';
        ctx.fillRect(0, 0, uvWidth, uvHeight);
    }

    model.traverse((mesh) => {
        if (mesh.isMesh) {
            const uvIslandsData = mesh.userData.uvIslands;
            if (!uvIslandsData) return;
            const uvArray = mesh.geometry.attributes.uv.array;

            uvIslandsData.islands.forEach((island, index) => {
                const isSelected = selectedIsland && selectedIsland.mesh === mesh && selectedIsland.islandIndex === index;
                ctx.strokeStyle = isSelected ? '#ff0000' : '#00ffff';
                ctx.lineWidth = isSelected ? 2 : 1;

                island.triangles.forEach(triangle => {
                    const [idx0, idx1, idx2] = triangle.indices;
                    ctx.beginPath();
                    ctx.moveTo(uvArray[idx0 * 2] * uvWidth, uvArray[idx0 * 2 + 1] * uvHeight);
                    ctx.lineTo(uvArray[idx1 * 2] * uvWidth, uvArray[idx1 * 2 + 1] * uvHeight);
                    ctx.lineTo(uvArray[idx2 * 2] * uvWidth, uvArray[idx2 * 2 + 1] * uvHeight);
                    ctx.closePath();
                    ctx.stroke();
                });
            });
        }
    });
}

function findIslandUnderMouse(x, y) {
    if (!model) return null;
    let foundIsland = null;

    model.traverse((mesh) => {
        if (mesh.isMesh && !foundIsland) {
            const uvIslandsData = mesh.userData.uvIslands;
            if (!uvIslandsData) return;
            const uvArray = mesh.geometry.attributes.uv.array;

            uvIslandsData.islands.some((island, index) => {
                const path = new Path2D();
                island.triangles.forEach(triangle => {
                    const [idx0, idx1, idx2] = triangle.indices;
                    path.moveTo(uvArray[idx0 * 2] * uvWidth, uvArray[idx0 * 2 + 1] * uvHeight);
                    path.lineTo(uvArray[idx1 * 2] * uvWidth, uvArray[idx1 * 2 + 1] * uvHeight);
                    path.lineTo(uvArray[idx2 * 2] * uvWidth, uvArray[idx2 * 2 + 1] * uvHeight);
                    path.closePath();
                });
                if (ctx.isPointInPath(path, x, y)) {
                    foundIsland = { mesh, islandIndex: index };
                    return true;
                }
            });
        }
    });
    return foundIsland;
}

/**
 * Botão que habilita/desabilita movimentação das ilhas.
 * (O código antigo permanece.)
 */
toggleIslandMovementBtn.addEventListener('click', () => {
    isIslandMovementEnabled = !isIslandMovementEnabled;
    toggleIslandMovementBtn.textContent = isIslandMovementEnabled ? 'Desabilitar Movimentação Individual de Ilhas UV' : 'Habilitar Movimentação Individual de Ilhas UV';
    selectedIsland = null;
    drawUVMap();
});

/**
 * MOUSE EVENTS
 * Se for uma ilha de borda, não deixaremos arrastar com o mouse (exclusividade do teclado).
 */
uvCanvas.addEventListener('mousedown', (e) => {
    const rect = uvCanvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    if (isIslandMovementEnabled) {
        const clickedIsland = findIslandUnderMouse(x, y);
        if (clickedIsland) {
            // Verifica se a ilha clicada é de borda
            const uvArray = clickedIsland.mesh.geometry.attributes.uv.array;
            const islandData = clickedIsland.mesh.userData.uvIslands.islands[clickedIsland.islandIndex];
            const onEdge = isIslandOnEdge(uvArray, islandData);

            // Se estiver na borda, não habilita movimento via mouse.
            if (onEdge) {
                // Evita arraste
                return;
            } else {
                // Permite arrastar normalmente
                selectedIsland = clickedIsland;
                isDragging = true;
                lastMouseX = e.clientX;
                lastMouseY = e.clientY;
                uvCanvas.style.cursor = 'grabbing';
            }
        }
        drawUVMap();
    } else {
        // Caso a movimentação de ilhas não esteja habilitada
        isDragging = true;
        lastMouseX = e.clientX;
        lastMouseY = e.clientY;
        uvCanvas.style.cursor = 'grabbing';
    }
});

uvCanvas.addEventListener('mousemove', (e) => {
    if (isDragging) {
        if (isIslandMovementEnabled && selectedIsland) {
            const islandKey = `${selectedIsland.mesh.uuid}_${selectedIsland.islandIndex}`;
            const islandData = initializeIslandOffsets(islandKey);

            const deltaX = e.clientX - lastMouseX;
            const deltaY = e.clientY - lastMouseY;

            islandData.offsetX += deltaX / uvWidth;
            islandData.offsetY += deltaY / uvHeight;

            lastMouseX = e.clientX;
            lastMouseY = e.clientY;

            modifyUVs(selectedIsland);
            drawUVMap();
        } else if (!isIslandMovementEnabled) {
            const deltaX = e.clientX - lastMouseX;
            const deltaY = e.clientY - lastMouseY;
            offsetX += deltaX;
            offsetY += deltaY;
            lastMouseX = e.clientX;
            lastMouseY = e.clientY;
            updateUVs(false);
            drawUVMap();
        }
    }
});

uvCanvas.addEventListener('mouseup', () => {
    isDragging = false;
    uvCanvas.style.cursor = 'default';
});

uvCanvas.addEventListener('wheel', (e) => {
    if (isIslandMovementEnabled && selectedIsland) {
        e.preventDefault();
        const islandKey = `${selectedIsland.mesh.uuid}_${selectedIsland.islandIndex}`;
        const islandData = initializeIslandOffsets(islandKey);

        const zoomIntensity = 0.001;
        islandData.scale = Math.max(0.1, Math.min(10, islandData.scale + e.deltaY * -zoomIntensity));

        modifyUVs(selectedIsland);
        drawUVMap();
    } else if (!isIslandMovementEnabled) {
        e.preventDefault();
        const zoomIntensity = 0.0002;
        scale += e.deltaY * -zoomIntensity;
        scale = Math.min(Math.max(0.1, scale), 10);
        updateUVs(false);
        drawUVMap();
    }
});

/**
 * EVENTO DE TECLADO para mover apenas as ilhas de borda.
 * Se existir ao menos uma ilha de borda, podemos alternar e mover.
 */
window.addEventListener('keydown', (e) => {
    if (!edgeIslands.length) return; // se não há ilhas de borda, não faz nada

    // Exemplo: se apertar TAB, troca para a próxima ilha de borda
    if (e.key === 'Tab') {
        e.preventDefault();
        currentEdgeIslandIndex = (currentEdgeIslandIndex + 1) % edgeIslands.length;
        selectedIsland = edgeIslands[currentEdgeIslandIndex];
        drawUVMap();
        return;
    }

    // Setas movem a ilha de borda selecionada
    if (!selectedIsland) {
        // Se não há ilha selecionada, seleciona logo a 1ª da lista
        selectedIsland = edgeIslands[0];
    }

    const islandKey = `${selectedIsland.mesh.uuid}_${selectedIsland.islandIndex}`;
    const islandData = initializeIslandOffsets(islandKey);
    const step = 0.01;

    switch(e.key) {
        case 'ArrowUp':
            islandData.offsetY -= step;
            modifyUVs(selectedIsland);
            drawUVMap();
            break;
        case 'ArrowDown':
            islandData.offsetY += step;
            modifyUVs(selectedIsland);
            drawUVMap();
            break;
        case 'ArrowLeft':
            islandData.offsetX -= step;
            modifyUVs(selectedIsland);
            drawUVMap();
            break;
        case 'ArrowRight':
            islandData.offsetX += step;
            modifyUVs(selectedIsland);
            drawUVMap();
            break;
        default:
            break;
    }
});

function updateUVs(invertV = true) {
    if (!model) return;
    model.traverse((child) => {
        if (child.isMesh) {
            const uvAttribute = child.geometry.attributes.uv;
            if (!uvAttribute) return;
            for (let i = 0; i < uvAttribute.count; i++) {
                const originalU = child.userData.originalUVs[i * 2];
                const originalV = child.userData.originalUVs[i * 2 + 1];
                let u = originalU * scale + offsetX / uvWidth;
                let v = originalV * scale + offsetY / uvHeight;
                uvAttribute.array[i * 2] = u;
                uvAttribute.array[i * 2 + 1] = v;
            }
            uvAttribute.needsUpdate = true;
        }
    });
}

function initUVEditor() {
    if (!model) {
        alert("Carregue e visualize um modelo primeiro.");
        uvEditorContainer.classList.remove('active');
        overlay.classList.remove('active');
        return;
    }

    // Limpa edgeIslands para recalcular
    edgeIslands = [];

    model.traverse((mesh) => {
        if (mesh.isMesh) {
            const uvAttribute = mesh.geometry.attributes.uv;
            if (uvAttribute) {
                mesh.userData.originalUVs = uvAttribute.array.slice();
                mesh.userData.uvIslands = buildUVIslands(mesh);

                // Para cada ilha, verificamos se está na borda
                const uvIslandsData = mesh.userData.uvIslands;
                uvIslandsData.islands.forEach((island, index) => {
                    if (isIslandOnEdge(uvAttribute.array, island)) {
                        edgeIslands.push({ mesh, islandIndex: index });
                    }
                });
            }
        }
    });

    // Se quisermos já selecionar a primeira ilha de borda, caso exista
    if (edgeIslands.length > 0) {
        selectedIsland = edgeIslands[0];
        currentEdgeIslandIndex = 0;
    }

    drawUVMap();
}

dropzone.addEventListener('dragover', (e) => {
    e.preventDefault();
    dropzone.style.borderColor = '#3897f0';
});

dropzone.addEventListener('dragleave', () => {
    dropzone.style.borderColor = '#dbdbdb';
});

dropzone.addEventListener('drop', (e) => {
    e.preventDefault();
    dropzone.style.borderColor = '#dbdbdb';
    const file = e.dataTransfer.files[0];
    const reader = new FileReader();

    reader.onload = function(event) {
        texture = new THREE.TextureLoader().load(event.target.result);
        texture.flipY = false;
        textureLoaded = true;
        alert("Textura carregada com sucesso!");
        renderBtn.classList.add('enabled');
        renderBtn.classList.remove('disabled');
    };

    reader.readAsDataURL(file);
});

renderBtn.addEventListener('click', function() {
    if (!textureLoaded) return;

    loadingPlaceholder.style.display = "flex";
    viewer.style.display = "none";

    const loader = new THREE.GLTFLoader();
    loader.load(viewer.src, function(gltf) {
        model = gltf.scene;

        model.traverse((mesh) => {
            if (mesh.isMesh) {
                const uvAttribute = mesh.geometry.attributes.uv;
                if (uvAttribute) {
                    mesh.userData.originalUVs = uvAttribute.array.slice();
                    mesh.userData.uvIslands = buildUVIslands(mesh);
                }
            }
        });

        const texturePromises = [];

        if (metalCheckbox.checked) {
            const metalnessMapPath = metalMapPaths.metal;
            texturePromises.push(applyMetalnessMap(metalnessMapPath, model));
        }

        if (normalMap1Checkbox.checked) {
            texturePromises.push(applyNormalMap(normalMapPaths.normal1, model));
        } else if (normalMap2Checkbox.checked) {
            texturePromises.push(applyNormalMap(normalMapPaths.normal2, model));
        }

        if (roughnessCheckbox.checked) {
            const roughnessMapPath = roughnessMapPaths.roughness;
            texturePromises.push(applyRoughnessMap(roughnessMapPath, model));
        }

        Promise.all(texturePromises).then(() => {
            if (texture) {
                model.traverse((child) => {
                    if (child.isMesh) {
                        child.material.map = texture;
                        child.material.needsUpdate = true;
                    }
                });
            }

            model.traverse((mesh) => {
                if (mesh.isMesh) {
                    const uvIslandsData = mesh.userData.uvIslands;
                    uvIslandsData.islands.forEach((island, index) => {
                        const selectedIsland = { mesh, islandIndex: index };
                        modifyUVs(selectedIsland);
                    });
                }
            });

            const exporter = new THREE.GLTFExporter();
            exporter.parse(model, function(result) {
                const blob = new Blob([result], { type: 'application/octet-stream' });
                const url = URL.createObjectURL(blob);
                viewer.src = url;
                loadingPlaceholder.style.display = "none";
                viewer.style.display = "block";
            }, { binary: true });
        }).catch((error) => {
            console.error('Erro ao aplicar texturas:', error);
        });
    });
});

function applyNormalMap(normalMapPath, model) {
    return new Promise((resolve, reject) => {
        const loader = new THREE.TextureLoader();
        loader.load(normalMapPath, (loadedNormalMap) => {
            normalMap = loadedNormalMap;
            normalMap.flipY = false;
            model.traverse((child) => {
                if (child.isMesh) {
                    child.material.normalMap = normalMap;
                    child.material.normalScale = new THREE.Vector2(2, 2);
                    child.material.needsUpdate = true;
                }
            });
            resolve();
        }, undefined, (error) => {
            reject(error);
        });
    });
}

function applyMetalnessMap(metalnessMapPath, model) {
    return new Promise((resolve, reject) => {
        const loader = new THREE.TextureLoader();
        loader.load(metalnessMapPath, (loadedMetalnessMap) => {
            const metalnessMap = loadedMetalnessMap;
            metalnessMap.flipY = false;
            model.traverse((child) => {
                if (child.isMesh) {
                    child.material.metalnessMap = metalnessMap;
                    child.material.metalness = 1;
                    child.material.needsUpdate = true;
                }
            });
            resolve();
        }, undefined, (error) => {
            reject(error);
        });
    });
}

function applyRoughnessMap(roughnessMapPath, model) {
    return new Promise((resolve, reject) => {
        const loader = new THREE.TextureLoader();
        loader.load(roughnessMapPath, (loadedRoughnessMap) => {
            const roughnessMap = loadedRoughnessMap;
            roughnessMap.flipY = false;
            model.traverse((child) => {
                if (child.isMesh) {
                    child.material.roughnessMap = roughnessMap;
                    child.material.roughness = 0.7;
                    child.material.needsUpdate = true;
                }
            });
            resolve();
        }, undefined, (error) => {
            reject(error);
        });
    });
}

function updateModel() {
    if (coffeeBagCheckbox.checked) {
        viewer.src = coffeeBagCheckbox.value;
    } else if (flowpackCheckbox.checked) {
        viewer.src = flowpackCheckbox.value;
    } else if (vacuumCoffeeCheckbox.checked) {
        viewer.src = vacuumCoffeeCheckbox.value;
    } else if (ziplockCheckbox.checked) {
        viewer.src = ziplockCheckbox.value;
    } else if (sachetCheckbox.checked) {
        viewer.src = sachetCheckbox.value;
    } else if (pack2Checkbox.checked) {
        viewer.src = pack2Checkbox.value;
    } else if (melittaCheckbox.checked) {
        viewer.src = melittaCheckbox.value;
    } else if (almofadaCheckbox.checked) {
        viewer.src = almofadaCheckbox.value;
    } else if (pouchComBicoCheckbox.checked) {
        viewer.src = pouchComBicoCheckbox.value;
    }
}

function uncheckAllExcept(checkedCheckbox) {
    const checkboxes = [
        coffeeBagCheckbox,
        flowpackCheckbox,
        vacuumCoffeeCheckbox,
        ziplockCheckbox,
        sachetCheckbox,
        pack2Checkbox,
        melittaCheckbox,
        almofadaCheckbox,
        pouchComBicoCheckbox
    ];
    checkboxes.forEach((checkbox) => {
        if (checkbox !== checkedCheckbox) {
            checkbox.checked = false;
        }
    });
    updateModel();
}

coffeeBagCheckbox.addEventListener('change', () => {
    if (coffeeBagCheckbox.checked) {
        uncheckAllExcept(coffeeBagCheckbox);
    }
});

flowpackCheckbox.addEventListener('change', () => {
    if (flowpackCheckbox.checked) {
        uncheckAllExcept(flowpackCheckbox);
    }
});

vacuumCoffeeCheckbox.addEventListener('change', () => {
    if (vacuumCoffeeCheckbox.checked) {
        uncheckAllExcept(vacuumCoffeeCheckbox);
    }
});

ziplockCheckbox.addEventListener('change', () => {
    if (ziplockCheckbox.checked) {
        uncheckAllExcept(ziplockCheckbox);
    }
});

sachetCheckbox.addEventListener('change', () => {
    if (sachetCheckbox.checked) {
        uncheckAllExcept(sachetCheckbox);
    }
});

pack2Checkbox.addEventListener('change', () => {
    if (pack2Checkbox.checked) {
        uncheckAllExcept(pack2Checkbox);
    }
});

melittaCheckbox.addEventListener('change', () => {
    if (melittaCheckbox.checked) {
        uncheckAllExcept(melittaCheckbox);
    }
});

almofadaCheckbox.addEventListener('change', () => {
    if (almofadaCheckbox.checked) {
        uncheckAllExcept(almofadaCheckbox);
    }
});

pouchComBicoCheckbox.addEventListener('change', () => {
    if (pouchComBicoCheckbox.checked) {
        uncheckAllExcept(pouchComBicoCheckbox);
    }
});

openUVEditorBtn.addEventListener('click', () => {
    uvEditorContainer.classList.add('active');
    overlay.classList.add('active');
    initUVEditor();
});

closeUVEditorBtn.addEventListener('click', () => {
    uvEditorContainer.classList.remove('active');
    overlay.classList.remove('active');
});

resetUVBtn.addEventListener('click', () => {
    if (model) {
        model.traverse((mesh) => {
            if (mesh.isMesh) {
                const uvAttribute = mesh.geometry.attributes.uv;
                mesh.userData.originalUVs = uvAttribute.array.slice();
                alert("Nova UV salva com sucesso.");
            }
        });
        scale = 1;
        offsetX = 0;
        offsetY = 0;
        drawUVMap();
        updateModelViewer();
    }
});

function updateModelViewer() {
    const exporter = new THREE.GLTFExporter();
    exporter.parse(model, function(result) {
        const blob = new Blob([result], { type: 'application/octet-stream' });
        const url = URL.createObjectURL(blob);
        viewer.src = url;
        loadingPlaceholder.style.display = "none";
        viewer.style.display = "block";
    }, { binary: true });
}

overlay.addEventListener('click', () => {
    uvEditorContainer.classList.remove('active');
    overlay.classList.remove('active');
});

updateModel();
    </script>
</body>
</html>