import json
import numpy as np

# Tabela de Cotas Oficial (em mm)
# baliza, x, z_quilha, z_borda, mb_25, mb_50, mb_75, mb_borda
data = [
    (1,     0.0,  845.7, 2008.6, 1465.2, 1640.0, 1686.5, 1691.4),
    (2,  2467.0,  191.6, 1779.2, 1879.5, 2095.2, 2151.0, 2156.6),
    (3,  4933.0,   14.3, 1632.0, 2064.8, 2285.4, 2339.6, 2344.5),
    (4,  7400.0,    0.0, 1585.7, 2171.3, 2394.6, 2447.9, 2452.6),
    (5,  9867.0,   90.9, 1696.8, 1917.4, 2161.0, 2228.8, 2236.4),
    (6, 12333.0,  267.7, 2014.7, 1105.9, 1322.5, 1403.6, 1418.9),
    (7, 14800.0, 2537.1, 2537.1,    0.0,    0.0,    0.0,    0.0)
]

stations = []
for row in data:
    b, x, zk, zd, y25, y50, y75, yd = row
    stations.append({
        'b': int(b),
        'x': x / 1000.0,
        'zk': zk / 1000.0,
        'zd': zd / 1000.0,
        'y25': y25 / 1000.0,
        'y50': y50 / 1000.0,
        'y75': y75 / 1000.0,
        'yd': yd / 1000.0
    })

x_orig = np.array([s['x'] for s in stations])
zk_orig = np.array([s['zk'] for s in stations])
zd_orig = np.array([s['zd'] for s in stations])
y25_orig = np.array([s['y25'] for s in stations])
y50_orig = np.array([s['y50'] for s in stations])
y75_orig = np.array([s['y75'] for s in stations])
yd_orig = np.array([s['yd'] for s in stations])

num_x = 60
num_z = 30
x_dense = np.linspace(0.0, 14.800, num_x)

grid_x = np.zeros((num_x, num_z))
grid_y_be = np.zeros((num_x, num_z))
grid_z = np.zeros((num_x, num_z))

for i, x in enumerate(x_dense):
    if x >= 14.799:
        zk = zk_orig[-1]
        zd = zd_orig[-1]
        z_vals = np.linspace(zk, zd, num_z)
        y_vals = np.zeros(num_z)
    else:
        zk = max(0.0, float(np.interp(x, x_orig, zk_orig)))
        zd = float(np.interp(x, x_orig, zd_orig))
        y25 = max(0.0, float(np.interp(x, x_orig, y25_orig)))
        y50 = max(0.0, float(np.interp(x, x_orig, y50_orig)))
        y75 = max(0.0, float(np.interp(x, x_orig, y75_orig)))
        yd = max(0.0, float(np.interp(x, x_orig, yd_orig)))
        
        z_ctrl = np.array([zk, zk + 0.25*(zd - zk), zk + 0.50*(zd - zk), zk + 0.75*(zd - zk), zd])
        y_ctrl = np.array([0.0, y25, y50, y75, yd])
        
        z_vals = np.linspace(zk, zd, num_z)
        y_vals = np.interp(z_vals, z_ctrl, y_ctrl)
        y_vals[0] = 0.0
        for k in range(1, num_z - 1):
            y_vals[k] = 0.25 * y_vals[k-1] + 0.5 * y_vals[k] + 0.25 * y_vals[k+1]
        y_vals[0] = 0.0
        
    grid_x[i, :] = x
    grid_y_be[i, :] = y_vals
    grid_z[i, :] = z_vals

# Gerar malha de vértices e triângulos (Three.js format)
# Offset de coordenadas para centrar no Three.js: X centrado em LOA/2, Z centrado
positions = []
indices = []

# Boreste (BE: y >= 0)
v_be_offset = len(positions) // 3
for i in range(num_x):
    for j in range(num_z):
        # Three.js: X=Comprimento (x - 7.4), Y=Altura (z), Z=Boca (y)
        positions.extend([float(grid_x[i, j] - 7.4), float(grid_z[i, j] - 1.2), float(grid_y_be[i, j])])

for i in range(num_x - 1):
    for j in range(num_z - 1):
        p1 = v_be_offset + i * num_z + j
        p2 = v_be_offset + (i + 1) * num_z + j
        p3 = v_be_offset + (i + 1) * num_z + (j + 1)
        p4 = v_be_offset + i * num_z + (j + 1)
        indices.extend([p1, p2, p3])
        indices.extend([p1, p3, p4])

# Bombordo (BB: y <= 0)
v_bb_offset = len(positions) // 3
for i in range(num_x):
    for j in range(num_z):
        positions.extend([float(grid_x[i, j] - 7.4), float(grid_z[i, j] - 1.2), float(-grid_y_be[i, j])])

for i in range(num_x - 1):
    for j in range(num_z - 1):
        p1 = v_bb_offset + i * num_z + j
        p2 = v_bb_offset + (i + 1) * num_z + j
        p3 = v_bb_offset + (i + 1) * num_z + (j + 1)
        p4 = v_bb_offset + i * num_z + (j + 1)
        # Inverter normais para BB
        indices.extend([p1, p3, p2])
        indices.extend([p1, p4, p3])

# Espelho de popa (Transom)
v_transom_center = len(positions) // 3
positions.extend([float(0.0 - 7.4), float(grid_z[0, 0] - 1.2), 0.0])
for j in range(num_z - 1):
    p_be1 = v_be_offset + j
    p_be2 = v_be_offset + (j + 1)
    p_bb1 = v_bb_offset + j
    p_bb2 = v_bb_offset + (j + 1)
    indices.extend([v_transom_center, p_be2, p_be1])
    indices.extend([v_transom_center, p_bb1, p_bb2])

# Gerar linhas das 7 balizas oficiais para visualização técnica
station_lines = []
for s in stations:
    zk = s['zk']
    zd = s['zd']
    z_ctrl = np.array([zk, zk + 0.25*(zd - zk), zk + 0.50*(zd - zk), zk + 0.75*(zd - zk), zd])
    y_ctrl = np.array([0.0, s['y25'], s['y50'], s['y75'], s['yd']])
    z_v = np.linspace(zk, zd, 40)
    y_v = np.interp(z_v, z_ctrl, y_ctrl)
    
    pts_be = []
    pts_bb = []
    for k in range(len(z_v)):
        pts_be.append([float(s['x'] - 7.4), float(z_v[k] - 1.2), float(y_v[k])])
        pts_bb.append([float(s['x'] - 7.4), float(z_v[k] - 1.2), float(-y_v[k])])
    
    # Combinar curva contínua de BB até BE passando pela quilha
    line_full = pts_bb[::-1] + pts_be
    station_lines.append({
        'baliza': s['b'],
        'x': s['x'],
        'points': line_full
    })

# Linha d'água de projeto (DWL, T=1.20m acima da linha de base -> Y=0 no modelo centrado)
dwl_points_be = []
dwl_points_bb = []
for i, x in enumerate(x_dense):
    # Encontrar meia-boca na altura z = 1.20m
    zk = max(0.0, float(np.interp(x, x_orig, zk_orig)))
    zd = float(np.interp(x, x_orig, zd_orig))
    if zk <= 1.20 <= zd:
        y25 = max(0.0, float(np.interp(x, x_orig, y25_orig)))
        y50 = max(0.0, float(np.interp(x, x_orig, y50_orig)))
        y75 = max(0.0, float(np.interp(x, x_orig, y75_orig)))
        yd = max(0.0, float(np.interp(x, x_orig, yd_orig)))
        z_ctrl = np.array([zk, zk + 0.25*(zd - zk), zk + 0.50*(zd - zk), zk + 0.75*(zd - zk), zd])
        y_ctrl = np.array([0.0, y25, y50, y75, yd])
        y_dwl = float(np.interp(1.20, z_ctrl, y_ctrl))
    elif 1.20 < zk:
        y_dwl = 0.0
    else:
        y_dwl = 0.0
    dwl_points_be.append([float(x - 7.4), 0.0, float(y_dwl)])
    dwl_points_bb.append([float(x - 7.4), 0.0, float(-y_dwl)])

# Gerar HTML interativo com Three.js
html_content = f"""<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Visualizador 3D Interativo — Casco Redondo Saveiro 14,80 m (Air)</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
    <style>
        * {{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
        }}
        body {{
            overflow: hidden;
            background: radial-gradient(circle at center, #1A202C 0%, #0D1117 100%);
            color: #E2E8F0;
        }}
        #canvas-container {{
            width: 100vw;
            height: 100vh;
            display: block;
        }}
        #ui-panel {{
            position: absolute;
            top: 20px;
            left: 20px;
            background: rgba(26, 32, 44, 0.85);
            backdrop-filter: blur(10px);
            border: 1px solid #4A5568;
            border-radius: 12px;
            padding: 18px 22px;
            max-width: 380px;
            box-shadow: 0 10px 25px rgba(0,0,0,0.5);
            z-index: 10;
        }}
        h1 {{
            font-size: 16px;
            font-weight: 700;
            color: #63B3ED;
            margin-bottom: 4px;
        }}
        .subtitle {{
            font-size: 12px;
            color: #A0AEC0;
            margin-bottom: 14px;
            border-bottom: 1px solid #4A5568;
            padding-bottom: 8px;
        }}
        .stat-grid {{
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 8px;
            margin-bottom: 14px;
        }}
        .stat-card {{
            background: rgba(45, 55, 72, 0.6);
            padding: 8px 10px;
            border-radius: 6px;
            border-left: 3px solid #3182CE;
        }}
        .stat-label {{
            font-size: 10px;
            text-transform: uppercase;
            color: #A0AEC0;
        }}
        .stat-value {{
            font-size: 13px;
            font-weight: 700;
            color: #FFFFFF;
        }}
        .controls-group {{
            margin-top: 10px;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }}
        .control-row {{
            display: flex;
            align-items: center;
            justify-content: space-between;
            font-size: 12px;
        }}
        .btn-group {{
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 6px;
            margin-top: 10px;
        }}
        button {{
            background: #2B6CB0;
            color: white;
            border: none;
            padding: 6px 8px;
            border-radius: 6px;
            font-size: 11px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s;
        }}
        button:hover {{
            background: #3182CE;
            transform: translateY(-1px);
        }}
        button.active {{
            background: #D69E2E;
        }}
        #view-help {{
            position: absolute;
            bottom: 20px;
            right: 20px;
            background: rgba(26, 32, 44, 0.75);
            padding: 10px 14px;
            border-radius: 8px;
            font-size: 11px;
            color: #CBD5E0;
            border: 1px solid #4A5568;
        }}
        .badge {{
            background: #319795;
            color: white;
            padding: 2px 6px;
            border-radius: 4px;
            font-size: 10px;
            margin-left: 6px;
        }}
    </style>
</head>
<body>
    <div id="ui-panel">
        <h1>CASCO REDONDO 3D — SAVEIRO <span class="badge">Air</span></h1>
        <div class="subtitle">Modelo Paramétrico a partir da Tabela de Cotas Oficial (EEE / Brana)</div>
        
        <div class="stat-grid">
            <div class="stat-card">
                <div class="stat-label">Comprimento (LOA)</div>
                <div class="stat-value">14,800 m</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Boca Máxima (BOA)</div>
                <div class="stat-value">4,905 m</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Calado de Projeto</div>
                <div class="stat-value">1,200 m</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Pontal na Seção 4</div>
                <div class="stat-value">1,586 m</div>
            </div>
        </div>

        <div class="controls-group">
            <div class="control-row">
                <label><input type="checkbox" id="chk-surface" checked> Superfície Sólida</label>
                <label><input type="checkbox" id="chk-wireframe"> Wireframe / Malha</label>
            </div>
            <div class="control-row">
                <label><input type="checkbox" id="chk-stations" checked> 7 Balizas de Cota</label>
                <label><input type="checkbox" id="chk-waterline" checked> Linha d'Água (DWL)</label>
            </div>
            <div class="control-row">
                <label><input type="checkbox" id="chk-waterplane" checked> Plano D'Água Translúcido</label>
                <label><input type="checkbox" id="chk-rotate"> Rotação Automática</label>
            </div>
        </div>

        <div class="btn-group">
            <button onclick="setView('iso')">Iso 3D</button>
            <button onclick="setView('profile')">Perfil</button>
            <button onclick="setView('plan')">Planta</button>
            <button onclick="setView('body')">Balizas</button>
        </div>
    </div>

    <div id="view-help">
        🖱️ <b>Rotacionar:</b> Botão esquerdo | 🔍 <b>Zoom:</b> Scroll | ✋ <b>Pan:</b> Botão direito
    </div>

    <div id="canvas-container"></div>

    <script>
        const hullPositions = {json.dumps(positions)};
        const hullIndices = {json.dumps(indices)};
        const stationsData = {json.dumps(station_lines)};
        const dwlBe = {json.dumps(dwl_points_be)};
        const dwlBb = {json.dumps(dwl_points_bb)};

        // Three.js Setup
        const container = document.getElementById('canvas-container');
        const scene = new THREE.Scene();
        scene.fog = new THREE.FogExp2(0x0D1117, 0.015);

        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(16, 8, 16);

        const renderer = new THREE.WebGLRenderer({{ antialias: true, alpha: true }});
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        container.appendChild(renderer.domElement);

        const controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;
        controls.target.set(0, 0, 0);

        // Iluminação
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.65);
        scene.add(ambientLight);

        const dirLight1 = new THREE.DirectionalLight(0xffffff, 0.85);
        dirLight1.position.set(20, 30, 20);
        dirLight1.castShadow = true;
        scene.add(dirLight1);

        const dirLight2 = new THREE.DirectionalLight(0x63B3ED, 0.45);
        dirLight2.position.set(-20, -10, -20);
        scene.add(dirLight2);

        // Grade de Referência (Linha de Base)
        const grid = new THREE.GridHelper(24, 24, 0x4A5568, 0x2D3748);
        grid.position.y = -1.2;
        scene.add(grid);

        // Eixo de Coordenadas Naval
        const axesHelper = new THREE.AxesHelper(3);
        axesHelper.position.set(-7.4, -1.2, 0);
        scene.add(axesHelper);

        // Casco 3D
        const geometry = new THREE.BufferGeometry();
        geometry.setAttribute('position', new THREE.Float32BufferAttribute(hullPositions, 3));
        geometry.setIndex(hullIndices);
        geometry.computeVertexNormals();

        // Material com pintura naval azul escuro e verniz reflexivo
        const hullMaterial = new THREE.MeshPhysicalMaterial({{
            color: 0x1E4E8C,
            metalness: 0.15,
            roughness: 0.25,
            clearcoat: 0.8,
            clearcoatRoughness: 0.1,
            side: THREE.DoubleSide,
            flatShading: false
        }});

        const hullMesh = new THREE.Mesh(geometry, hullMaterial);
        hullMesh.castShadow = true;
        hullMesh.receiveShadow = true;
        scene.add(hullMesh);

        // Wireframe
        const wireframeMaterial = new THREE.MeshBasicMaterial({{
            color: 0x63B3ED,
            wireframe: true,
            transparent: true,
            opacity: 0.25
        }});
        const wireframeMesh = new THREE.Mesh(geometry, wireframeMaterial);
        wireframeMesh.visible = false;
        scene.add(wireframeMesh);

        // Linhas das Balizas Oficiais (1 a 7)
        const stationGroup = new THREE.Group();
        const colorsBalizas = [0xE53E3E, 0xDD6B20, 0xD69E2E, 0x38A169, 0x319795, 0x3182CE, 0x805AD5];

        stationsData.forEach((st, idx) => {{
            const pts = st.points.map(p => new THREE.Vector3(p[0], p[1], p[2]));
            const lineGeom = new THREE.BufferGeometry().setFromPoints(pts);
            const lineMat = new THREE.LineBasicMaterial({{
                color: colorsBalizas[idx % colorsBalizas.length],
                linewidth: 2.5
            }});
            const line = new THREE.Line(lineGeom, lineMat);
            stationGroup.add(line);
        }});
        scene.add(stationGroup);

        // Linha d'Água de Projeto (DWL)
        const dwlGroup = new THREE.Group();
        const ptsDwlBe = dwlBe.map(p => new THREE.Vector3(p[0], p[1], p[2]));
        const ptsDwlBb = dwlBb.map(p => new THREE.Vector3(p[0], p[1], p[2]));
        const dwlMat = new THREE.LineBasicMaterial({{ color: 0x00FFFF, linewidth: 2 }});
        dwlGroup.add(new THREE.Line(new THREE.BufferGeometry().setFromPoints(ptsDwlBe), dwlMat));
        dwlGroup.add(new THREE.Line(new THREE.BufferGeometry().setFromPoints(ptsDwlBb), dwlMat));
        scene.add(dwlGroup);

        // Plano d'Água Translúcido
        const waterPlaneGeom = new THREE.PlaneGeometry(20, 8);
        const waterPlaneMat = new THREE.MeshBasicMaterial({{
            color: 0x3182CE,
            transparent: true,
            opacity: 0.18,
            side: THREE.DoubleSide
        }});
        const waterPlane = new THREE.Mesh(waterPlaneGeom, waterPlaneMat);
        waterPlane.rotation.x = Math.PI / 2;
        waterPlane.position.y = 0.0; // DWL = T=1.20m acima da base (centrado em 0)
        scene.add(waterPlane);

        // Controles de UI
        document.getElementById('chk-surface').addEventListener('change', (e) => {{
            hullMesh.visible = e.target.checked;
        }});
        document.getElementById('chk-wireframe').addEventListener('change', (e) => {{
            wireframeMesh.visible = e.target.checked;
        }});
        document.getElementById('chk-stations').addEventListener('change', (e) => {{
            stationGroup.visible = e.target.checked;
        }});
        document.getElementById('chk-waterline').addEventListener('change', (e) => {{
            dwlGroup.visible = e.target.checked;
        }});
        document.getElementById('chk-waterplane').addEventListener('change', (e) => {{
            waterPlane.visible = e.target.checked;
        }});

        let autoRotate = false;
        document.getElementById('chk-rotate').addEventListener('change', (e) => {{
            autoRotate = e.target.checked;
        }});

        function setView(view) {{
            controls.reset();
            if (view === 'iso') {{
                camera.position.set(16, 8, 16);
            }} else if (view === 'profile') {{
                camera.position.set(0, 0, 22);
            }} else if (view === 'plan') {{
                camera.position.set(0, 22, 0);
            }} else if (view === 'body') {{
                camera.position.set(22, 0, 0);
            }}
            controls.target.set(0, 0, 0);
        }}

        // Redimensionamento de Janela
        window.addEventListener('resize', onWindowResize, false);
        function onWindowResize() {{
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }}

        // Loop de Renderização
        function animate() {{
            requestAnimationFrame(animate);
            if (autoRotate) {{
                scene.rotation.y += 0.004;
            }} else {{
                scene.rotation.y = 0;
            }}
            controls.update();
            renderer.render(scene, camera);
        }}
        animate();
    </script>
</body>
</html>
"""

# Salvar o arquivo HTML solicitado
output_html_group = '/home/magdalena/eee/grupos/grupo-3/Casco-Redondo-3D-Air.html'
output_html_user = '/home/magdalena/eee/alunos/rodolfo-g-giordano/Casco-Redondo-3D-Air.html'

with open(output_html_group, 'w', encoding='utf-8') as f:
    f.write(html_content)

with open(output_html_user, 'w', encoding='utf-8') as f:
    f.write(html_content)

print("Arquivo Casco-Redondo-3D-Air.html gerado com sucesso!")
