class GeoSimulator {
    constructor() {
        this.layers = [];
        this.fs = 3.0;
        this.pileDiameter = 0.4; // Se almacena en metros, input en mm
        this.drivenLength = 10.0; // m (Longitud hincada)
        this.hammerWeight = 5.0; // Ton
        this.dropHeight = 1.2; // m

        this.textures = {};
        this.loadTextures();

        this.initEventListeners();
        // Inicializar con algunas capas diferentes para demo
        this.layers = [
            { type: 'arcilla', depth: 4.0, nspt: 8 },
            { type: 'arena', depth: 6.0, nspt: 25 },
            { type: 'roca', depth: 5.0, nspt: 100 }
        ];
        this.renderLayers();
        this.calculateCapacity();
        this.drawProfile();
    }

    initEventListeners() {
        document.getElementById('add-layer-btn')?.addEventListener('click', () => {
            this.addLayer();
        });

        const fsInput = document.getElementById('fs-input');
        const fsValue = document.getElementById('fs-value');
        if (fsInput && fsValue) {
            fsInput.addEventListener('input', (e) => {
                this.fs = parseFloat(e.target.value);
                fsValue.textContent = this.fs.toFixed(1);
                this.calculateCapacity();
            });
        }

        ['pile-diameter', 'hammer-weight', 'drop-height', 'driven-length'].forEach(id => {
            const el = document.getElementById(id);
            if (el) {
                el.addEventListener('input', (e) => {
                    const val = parseFloat(e.target.value);
                    if (id === 'pile-diameter') this.pileDiameter = val / 1000.0; // Convertir mm a m para cálculos
                    if (id === 'hammer-weight') this.hammerWeight = val;
                    if (id === 'drop-height') this.dropHeight = val;
                    if (id === 'driven-length') {
                        // Limitar a máximo 36m
                        let length = Math.min(val, 36.0);
                        if (length < 0) length = 0;

                        this.drivenLength = length;
                        // Actualizar input si se pasó del límite
                        if (val > 36.0) e.target.value = 36.0;

                        this.drawProfile();
                    }
                    this.calculateCapacity();
                });

                // Formato 2 decimales al perder foco (blur)
                if (id === 'driven-length') {
                    el.addEventListener('blur', (e) => {
                        const val = parseFloat(e.target.value);
                        if (!isNaN(val)) {
                            e.target.value = val.toFixed(2);
                        }
                    });
                }
            }
        });
    }

    addLayer() {
        this.layers.push({
            type: 'arena',
            depth: 5,
            nspt: 10
        });
        this.renderLayers();
        this.calculateCapacity();
        this.drawProfile();
    }

    removeLayer(index) {
        this.layers.splice(index, 1);
        this.renderLayers();
        this.calculateCapacity();
        this.drawProfile();
    }

    updateLayer(index, field, value) {
        this.layers[index][field] = value;
        this.calculateCapacity();
        this.drawProfile();
    }

    loadTextures() {
        const types = ['arena', 'arcilla', 'grava', 'limo', 'roca'];
        let loadedCount = 0;

        types.forEach(type => {
            const img = new Image();
            img.src = `assets/texture_${type}.png`;
            img.onload = () => {
                this.textures[type] = img;
                loadedCount++;
                if (loadedCount === types.length) {
                    this.drawProfile(); // Redibujar cuando todas carguen
                } else {
                    this.drawProfile(); // Redibujar progresivamente
                }
            };
            img.onerror = () => {
                console.warn(`No se pudo cargar textura para ${type}`);
            };
        });
    }

    renderLayers() {
        const container = document.getElementById('layers-container');
        if (!container) return;

        container.innerHTML = '';

        this.layers.forEach((layer, index) => {
            const row = document.createElement('div');
            row.className = 'layer-row';
            row.innerHTML = `
                <div class="layer-index">#${index + 1}</div>
                
                <div class="layer-input-group">
                    <label>Tipo</label>
                    <select onchange="geoSim.updateLayer(${index}, 'type', this.value)">
                        <option value="arena" ${layer.type === 'arena' ? 'selected' : ''}>Arena</option>
                        <option value="arcilla" ${layer.type === 'arcilla' ? 'selected' : ''}>Arcilla</option>
                        <option value="grava" ${layer.type === 'grava' ? 'selected' : ''}>Grava</option>
                        <option value="limo" ${layer.type === 'limo' ? 'selected' : ''}>Limo</option>
                        <option value="roca" ${layer.type === 'roca' ? 'selected' : ''}>Roca</option>
                    </select>
                </div>

                <div class="layer-input-group">
                    <label>Espesor (m)</label>
                    <input type="number" value="${layer.depth}" min="0.1" step="0.1"
                        oninput="geoSim.updateLayer(${index}, 'depth', parseFloat(this.value))">
                </div>

                <div class="layer-input-group">
                    <label>NSPT60</label>
                    <input type="number" value="${layer.nspt}" min="1" max="100"
                        oninput="geoSim.updateLayer(${index}, 'nspt', parseInt(this.value))">
                </div>

                <button class="remove-layer-btn" onclick="geoSim.removeLayer(${index})">×</button>
            `;
            container.appendChild(row);
        });
    }

    drawProfile() {
        const canvas = document.getElementById('geo-chart');
        if (!canvas) return;
        const ctx = canvas.getContext('2d');
        const width = canvas.width;
        const height = canvas.height;

        // Limpiar canvas
        ctx.fillStyle = '#1a1a1a';
        ctx.fillRect(0, 0, width, height);

        // Calcular profundidad total del terreno
        const totalSoilDepth = this.layers.reduce((acc, l) => acc + l.depth, 0);
        // Escala vertical: Usar el mayor entre (profundidad suelo vs longitud hincada + 2m margen)
        const maxDepth = Math.max(totalSoilDepth, this.drivenLength + 2);
        const scaleY = height / maxDepth;

        let currentY = 0;

        // Dibujar Capas de Suelo
        this.layers.forEach(layer => {
            const layerHeight = layer.depth * scaleY;

            // Patrones de Textura Realista
            let pattern = null;
            if (this.textures && this.textures[layer.type]) {
                pattern = ctx.createPattern(this.textures[layer.type], 'repeat');
            }

            if (pattern) {
                ctx.fillStyle = pattern;
            } else {
                // Fallback colores si no carga la textura
                if (layer.type === 'arena') ctx.fillStyle = '#f4d03f';
                else if (layer.type === 'arcilla') ctx.fillStyle = '#d35400';
                else if (layer.type === 'grava') ctx.fillStyle = '#7f8c8d';
                else if (layer.type === 'limo') ctx.fillStyle = '#f39c12';
                else if (layer.type === 'roca') ctx.fillStyle = '#2c3e50';
                else ctx.fillStyle = '#95a5a6';
            }

            ctx.fillRect(0, currentY, width, layerHeight);

            // Overlay para oscurecer ligeramente y unificar
            ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
            ctx.fillRect(0, currentY, width, layerHeight);

            // Texto de capa (con sombra para legibilidad)
            ctx.fillStyle = '#fff';
            ctx.shadowColor = 'rgba(0, 0, 0, 0.9)';
            ctx.shadowBlur = 4;
            ctx.shadowOffsetX = 1;
            ctx.shadowOffsetY = 1;
            ctx.font = 'bold 12px Rajdhani';
            ctx.fillText(`${layer.type.toUpperCase()} (N=${layer.nspt})`, 10, currentY + 15);
            ctx.fillText(`${layer.depth}m`, width - 30, currentY + layerHeight / 2);

            // Reset shadow
            ctx.shadowBlur = 0;
            ctx.shadowOffsetX = 0;
            ctx.shadowOffsetY = 0;

            // Borde capa separador
            ctx.strokeStyle = 'rgba(255,255,255,0.4)';
            ctx.lineWidth = 1;
            ctx.beginPath();
            ctx.moveTo(0, currentY + layerHeight);
            ctx.lineTo(width, currentY + layerHeight);
            ctx.stroke();

            currentY += layerHeight;
        });

        // Dibujar Pilote
        const pileX = width / 2 - 10;
        const pileWidth = 20;
        const pileHeight = this.drivenLength * scaleY;

        ctx.fillStyle = '#e0e0e0'; // Color hormigón claro
        ctx.fillRect(pileX, 0, pileWidth, pileHeight);

        // Contorno Pilote
        ctx.strokeStyle = '#fff';
        ctx.lineWidth = 2;
        ctx.strokeRect(pileX, 0, pileWidth, pileHeight);

        // Punta del Pilote
        ctx.beginPath();
        ctx.moveTo(pileX, pileHeight);
        ctx.lineTo(pileX + pileWidth / 2, pileHeight + 10);
        ctx.lineTo(pileX + pileWidth, pileHeight);
        ctx.fillStyle = '#333';
        ctx.fill();

        // Línea de Cota Hincada
        ctx.setLineDash([5, 5]);
        ctx.strokeStyle = '#e94e1b'; // Naranja Keller
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(0, pileHeight);
        ctx.lineTo(width, pileHeight);
        ctx.stroke();
        ctx.setLineDash([]);

        ctx.fillStyle = '#e94e1b';
        ctx.font = 'bold 12px Rajdhani';
        ctx.fillText(`L = ${this.drivenLength}m`, pileX + 25, pileHeight - 5);
    }

    calculateCapacity() {
        let totalSkinFriction = 0; // kN
        let tipResistance = 0; // kN
        let currentDepth = 0; // Profundidad acumulada del suelo
        let drivenRemaining = this.drivenLength; // Longitud del pilote que falta por analizar

        const perimeter = Math.PI * this.pileDiameter;
        const area = Math.PI * Math.pow(this.pileDiameter / 2, 2);

        let pileTipLayer = null;

        // 1. Calcular Fuste (Skin Friction)
        for (const layer of this.layers) {
            if (drivenRemaining <= 0) break; // Fin del pilote

            // Determine effective length of pile within this layer
            // Es el mínimo entre el espesor de la capa y la longitud restante del pilote
            const effectiveDepth = Math.min(layer.depth, drivenRemaining);

            let unitFriction = 0; // kPa

            // Correlaciones empíricas
            if (layer.type === 'arena') {
                unitFriction = 2.0 * layer.nspt;
            } else if (layer.type === 'arcilla') {
                unitFriction = 1.5 * layer.nspt;
            } else if (layer.type === 'grava') {
                unitFriction = 2.5 * layer.nspt;
            } else if (layer.type === 'limo') {
                unitFriction = 1.8 * layer.nspt; // Limo
            } else if (layer.type === 'roca') {
                unitFriction = 5.0 * layer.nspt; // Roca (alta fricción)
            }

            // Limitar fricción unitaria (ej. 120 kPa) - Roca permite más
            const limit = layer.type === 'roca' ? 500 : 120;
            unitFriction = Math.min(unitFriction, limit);

            totalSkinFriction += unitFriction * perimeter * effectiveDepth;

            drivenRemaining -= effectiveDepth;
            currentDepth += layer.depth; // Solo referencia visual, no cálculo

            // Si drivenRemaining llegó a 0 (o menor), esta es la capa de punta
            if (drivenRemaining <= 0.001) {
                pileTipLayer = layer;
            }
        }

        // 2. Calcular Punta (Tip Resistance)
        if (pileTipLayer) {
            let unitTip = 0; // kPa
            const l = pileTipLayer;

            if (l.type === 'arena') unitTip = 300 * l.nspt;
            else if (l.type === 'arcilla') unitTip = 120 * l.nspt;
            else if (l.type === 'grava') unitTip = 400 * l.nspt;
            else if (l.type === 'limo') unitTip = 200 * l.nspt;
            else if (l.type === 'roca') unitTip = 1000 * l.nspt; // Roca muy alta

            // Límites
            const limit = l.type === 'roca' ? 50000 : 15000;
            unitTip = Math.min(unitTip, limit);

            tipResistance = unitTip * area;
        } else if (this.drivenLength > this.layers.reduce((a, b) => a + b.depth, 0)) {
            // Pilote más largo que el suelo definido? Asumir última capa o 0?
            // Asumiremos las propiedades de la última capa por simplicidad (extensión infinita)
            if (this.layers.length > 0) {
                const l = this.layers[this.layers.length - 1];
                // Recalculate tip based on last layer
                let unitTip = 300 * l.nspt; // Default arena logic fallback
                if (l.type === 'roca') unitTip = 1000 * l.nspt;

                tipResistance = unitTip * area;
            }
        }

        // 3. Resultado Total
        const totalResistance = totalSkinFriction + tipResistance;
        const admissibleResistance = totalResistance / this.fs;

        // Actualizar UI con IDs correctos (según dashboard.html)
        this.animateValue('res-skin', totalSkinFriction);
        this.animateValue('res-tip', tipResistance);
        this.animateValue('res-total', totalResistance);
        this.animateValue('res-adm', admissibleResistance);

        // Actualizar Barra de Capacidad Visual
        const barFill = document.getElementById('capacity-bar-fill');
        if (barFill) {
            // Referencia de escala visual (kN) ~ 500 Ton = 5000 kN
            const maxCapacityRef = 5000;
            const percentage = Math.min((admissibleResistance / maxCapacityRef) * 100, 100);

            barFill.style.width = `${percentage}%`;
            // Color dinámico según capacidad
            if (percentage < 20) barFill.style.backgroundColor = '#e74c3c'; // Rojo (baja)
            else if (percentage < 50) barFill.style.backgroundColor = '#f39c12'; // Naranja (media)
            else barFill.style.backgroundColor = '#2ecc71'; // Verde (alta)
        }

        // 4. Calcular Fórmula Holandesa (Driving Formula)
        this.calculateDrivingFormula(totalResistance);
    }

    calculateDrivingFormula(Ru_kN) {
        // Dutch Formula
        const Ru_ton = Ru_kN / 9.81; // Convertir kN a Ton
        const W = this.hammerWeight; // Ton
        const h_mm = this.dropHeight * 1000; // m -> mm
        const c = 2.5; // mm
        const efficiency = 0.7;

        if (Ru_ton <= 0) return;

        let s = ((efficiency * W * h_mm) / Ru_ton) - c;
        if (s < 0) s = 0;

        let blowsPer10cm = 0;
        if (s > 0.1) {
            blowsPer10cm = 100 / s;
        } else {
            blowsPer10cm = 999;
        }

        // Actualizar UI Hinca (IDs correctos)
        this.animateValueNoUnit('res-set', s, 1);
        this.animateValueNoUnit('res-blows', blowsPer10cm, 0);
    }

    animateValue(id, value_kN) {
        const el = document.getElementById(id);
        if (!el) return;

        // Conversión a Toneladas (aprox / 10 o / 9.81)
        const value_Ton = value_kN / 9.81;

        // Mostrar ambos: "1500 kN / 153 Ton"
        el.textContent = `${Math.round(value_kN)} kN / ${Math.round(value_Ton)} Ton`;
    }

    animateValueNoUnit(id, value, decimals) {
        const el = document.getElementById(id);
        if (!el) return;
        el.textContent = value.toFixed(decimals);
    }
}

// Inicializar
window.geoSim = null;
document.addEventListener('DOMContentLoaded', () => {
    window.geoSim = new GeoSimulator();
});
