<?php
/* ==========================================================================
   ARCHITECT PRO: SUITE UML INTEGRAL v3.8 (2026)
   DB: proyectos | TABLA: flujos_logicos
   Funciones: Física Pro, Continuidad de Color, Importador JSON y Simulador
   ========================================================================== */
session_start();
error_reporting(E_ALL);

$DB_HOST = "localhost"; $DB_USER = "root"; $DB_PASS = "33comRxXMysql"; $DB_NAME = "Proyectos"; 

try {
    $pdo = new PDO("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=utf8mb4", $DB_USER, $DB_PASS);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['accion'])) {
        header('Content-Type: application/json');
        if ($_POST['accion'] === 'guardar') {
            $sql = "INSERT INTO flujos_logicos (nombre, data_json, fecha_update) 
                    VALUES (?, ?, NOW()) 
                    ON DUPLICATE KEY UPDATE data_json = VALUES(data_json), fecha_update = NOW()";
            $pdo->prepare($sql)->execute([$_POST['nombre'], $_POST['data_json']]);
            echo json_encode(["status" => "OK", "msg" => "Proyecto sincronizado."]);
        }
        if ($_POST['accion'] === 'borrar') {
            $sql = "DELETE FROM flujos_logicos WHERE id = ?";
            $pdo->prepare($sql)->execute([$_POST['id']]);
            echo json_encode(["status" => "OK", "msg" => "Proyecto eliminado."]);
        }
        exit;
    }
    
    if (isset($_GET['get_json'])) {
        header('Content-Type: application/json');
        $stmt = $pdo->prepare("SELECT data_json FROM flujos_logicos WHERE id = ?");
        $stmt->execute([$_GET['get_json']]);
        echo $stmt->fetchColumn(); exit;
    }
    $proyectos = $pdo->query("SELECT id, nombre FROM flujos_logicos ORDER BY fecha_update DESC")->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) { die("Error: " . $e->getMessage()); }
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>UML Architect Pro v3.8</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jerosoler/Drawflow/dist/drawflow.min.css">
    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
    <script src="https://cdn.jsdelivr.net/gh/jerosoler/Drawflow/dist/drawflow.min.js"></script>

    <style>
        :root { --primary: #4f46e5; --si: #22c55e; --no: #ef4444; --uml-yellow: #facc15; --uml-blue: #3b82f6; --sidebar-w: 280px; }
        body { background: #f8fafc; font-family: 'Inter', sans-serif; height: 100vh; overflow: hidden; margin: 0; }
        .main-container { display: grid; grid-template-columns: var(--sidebar-w) 1fr 320px; height: 100vh; }
        
        /* PANELES */
        .sidebar { background: #fff; border: 1px solid #e2e8f0; display: flex; flex-direction: column; z-index: 100; padding: 20px; }
        .canvas-area { position: relative; background: #fff; background-image: radial-gradient(#cbd5e1 1.2px, transparent 1.2px); background-size: 25px 25px; }

        /* TABS */
        .nav-tabs-custom { display: flex; border-bottom: 1px solid #e2e8f0; margin-bottom: 15px; }
        .nav-tabs-custom button { flex: 1; padding: 8px; border: none; background: #f8fafc; font-size: 11px; font-weight: bold; color: #64748b; }
        .nav-tabs-custom button.active { background: #fff; color: var(--primary); border-bottom: 2px solid var(--primary); }

        /* NODOS DRAWFLOW */
        .drawflow-node { width: auto !important; height: auto !important; background: transparent !important; border: none !important; }
        .drawflow .drawflow-node .input { top: -80px !important; left: 70px !important; transform: translateX(-50%) !important; border: 2.5px solid #1e293b !important; width: 14px; height: 14px; background: #fff !important; }
       
		

        .drawflow .drawflow-node .output { bottom: -15px !important; top: auto !important; left: 50% !important; transform: translateX(-50%) !important; border: 2.5px solid #1e293b !important; width: 14px; height: 14px; background: #fff !important; }

        /* LÓGICA DE TRIÁNGULO EN DECISIÓN */
        .drawflow-node.decision .output_1 { /* SÍ -> ABAJO */
            bottom: -1px !important; left: 50% !important; transform: translateX(-50%) !important; 
            background: var(--si) !important; border-color: #166534 !important;
        }
        .drawflow-node.decision .output_2 { /* NO -> DERECHA */
            top: 50% !important; right: 170px !important; left: auto !important; transform: translateY(-50%) !important; 
            background: var(--no) !important; border-color: #991b1b !important;
        }
        .drawflow-node.decision .output_1::after { content: 'SÍ'; position: absolute; bottom: -22px; left: 5px; font-size: 9px; font-weight: 900; color: var(--si); }
        .drawflow-node.decision .output_2::after { content: 'NO'; position: absolute; top: -18px; right: -5px; font-size: 9px; font-weight: 900; color: var(--no); }


        /* ESTÉTICA UML */
        .uml-node-box { background: white; border: 2.5px solid #1e293b; min-width: 140px; padding: 12px 20px; font-weight: 600; text-align: center; border-radius: 6px; box-shadow: 0 4px 15px rgba(0,0,0,0.08); display: flex; align-items: center; justify-content: center; }
        .node-start { border-color: var(--uml-yellow); border-radius: 40px; }
        .node-end { border-color: var(--uml-blue); border-radius: 40px; }
        .uml-diamond-box { width: 100px; height: 100px; border: 2.5px solid #1e293b; transform: rotate(45deg); display: flex; align-items: center; justify-content: center; background: white; margin: 30px; }
        .uml-diamond-box span { transform: rotate(-45deg); display: block; text-align: center; font-size: 11px; font-weight: bold; }

        .node-active { border: 4px solid var(--primary) !important; box-shadow: 0 0 20px rgba(79, 70, 229, 0.4) !important; transform: scale(1.05); transition: 0.2s; }
        #propSidebar { transform: translateX(100%); transition: 0.3s; visibility: hidden; }
        #propSidebar.active { transform: translateX(0); visibility: visible; }
        
        .tool-item { padding: 10px; border: 1px solid #e2e8f0; border-radius: 8px; margin-bottom: 8px; cursor: grab; background: white; font-size: 13px; }
        .physics-btn { background: #6366f1; color: white; border: none; padding: 8px; border-radius: 6px; font-size: 11px; width: 100%; font-weight: bold; margin-bottom: 10px; }
    </style>
</head>
<body>

<div class="main-container">
    <aside class="sidebar">
        <nav class="nav-tabs-custom">
            <button id="btn-tools" class="active" onclick="switchTab('tools')">UML</button>
            <button id="btn-json" onclick="switchTab('json')">JSON</button>
        </nav>
        
        <div id="tab-tools">
            <button class="physics-btn shadow-sm" onclick="autoDistribuir()"><i class="fa-solid fa-atom me-2"></i>AUTODISTRIBUIR (FÍSICA)</button>

            <label class="small fw-bold text-muted mb-1">PROYECTOS</label>
            <div class="input-group input-group-sm mb-4">
                <select class="form-select" id="projectSelector" onchange="cargarDiagrama(this.value)">
                    <option value="">-- Cargar --</option>
                    <?php foreach($proyectos as $p): ?>
                        <option value="<?= $p['id'] ?>"><?= htmlspecialchars($p['nombre']) ?></option>
                    <?php endforeach; ?>
                </select>
                <button class="btn btn-outline-danger" onclick="borrarProyecto()"><i class="fa-trash fa-solid"></i></button>
            </div>

            <div class="tool-list">
                <div class="tool-item" draggable="true" ondragstart="drag(event)" data-node="start"><i class="fa-circle-play fa-solid text-warning"></i> Inicio</div>
                <div class="tool-item" draggable="true" ondragstart="drag(event)" data-node="process"><i class="fa-square fa-solid text-secondary"></i> Proceso</div>
                <div class="tool-item" draggable="true" ondragstart="drag(event)" data-node="decision"><i class="fa-diamond fa-solid text-secondary"></i> Decisión</div>
                <div class="tool-item" draggable="true" ondragstart="drag(event)" data-node="db"><i class="fa-database fa-solid text-danger"></i> DB</div>
                <div class="tool-item" draggable="true" ondragstart="drag(event)" data-node="end"><i class="fa-circle-stop fa-solid text-primary"></i> Fin</div>
            </div>
        </div>

        <div id="tab-json" class="d-none">
            <textarea id="jsonConsole" class="form-control bg-dark text-info border-0 mb-2" rows="20" style="font-family:monospace; font-size:10px"></textarea>
            <button class="btn btn-info btn-sm w-100" onclick="importarJson()">IMPORTAR JSON</button>
        </div>

        <div class="mt-auto">
            <button class="btn btn-outline-dark btn-sm w-100 mb-2 fw-bold" onclick="editor.clear()"><i class="fa-solid fa-eraser me-2"></i> LIMPIAR</button>
            <button class="btn btn-primary w-100 fw-bold shadow-sm" onclick="guardarProyecto()"><i class="fa-save fa-solid me-2"></i>GUARDAR</button>
        </div>
    </aside>

    <main class="canvas-area">
        <div class="position-absolute p-3 top-0 end-0" style="z-index: 100;">
            <button class="btn btn-success btn-sm fw-bold shadow" onclick="iniciarSimulacion()"><i class="fa-solid fa-play me-2"></i>SIMULAR</button>
        </div>
        <div id="drawflow" ondrop="drop(event)" ondragover="allowDrop(event)" style="width:100%; height:100%;"></div>
    </main>

    <aside class="sidebar" id="propSidebar">
        <h6 class="fw-bold mb-4 border-bottom pb-2">Propiedades</h6>
        <div class="mb-4">
            <label class="small fw-bold text-muted mb-2">ETIQUETA</label>
            <textarea id="nodeText" class="form-control" rows="4" onkeyup="syncNode()"></textarea>
        </div>
        <div class="mb-4">
            <label class="small fw-bold text-muted mb-2">ROTACIÓN</label>
            <input type="range" class="form-range" id="rotateRange" min="0" max="360" value="0" oninput="syncNode()">
            <div class="text-center small fw-bold text-primary"><span id="rotateVal">0</span>°</div>
        </div>
        <div class="mb-4">
            <label class="small fw-bold text-muted mb-2">BORDE (CONTINUIDAD)</label>
            <input type="color" id="nodeColor" class="form-control form-control-color w-100" onchange="syncNode()">
        </div>
        <button class="btn btn-danger btn-sm w-100 mt-auto fw-bold" onclick="deleteNode()">BORRAR NODO</button>
    </aside>
</div>

<script>
    const editor = new Drawflow(document.getElementById("drawflow"));
    editor.start();
    let selectedId = null;

    // TABS
    function switchTab(tab) {
        document.getElementById('tab-tools').classList.toggle('d-none', tab !== 'tools');
        document.getElementById('tab-json').classList.toggle('d-none', tab !== 'json');
        document.getElementById('btn-tools').classList.toggle('active', tab === 'tools');
        document.getElementById('btn-json').classList.toggle('active', tab === 'json');
        if(tab === 'json') document.getElementById('jsonConsole').value = JSON.stringify(editor.export(), null, 4);
    }

    // DRAG & DROP
    function allowDrop(ev) { ev.preventDefault(); }
    function drag(ev) { ev.dataTransfer.setData("node", ev.target.getAttribute('data-node')); }
    function drop(ev) {
        ev.preventDefault();
        const type = ev.dataTransfer.getData("node");
        const x = ev.clientX - 280; const y = ev.clientY;
        addNode(type, x, y);
    }

    function addNode(type, x, y) {
        let html = '', inps = 1, outs = 1;
        switch(type) {
            case 'start': html = `<div class="uml-node-box node-start"><span>INICIO</span></div>`; inps = 0; break;
            case 'process': html = `<div class="uml-node-box"><span>PROCESO</span></div>`; break;
            case 'decision': html = `<div class="uml-diamond-box"><span>¿?</span></div>`; outs = 2; break;
            case 'db': html = `<div class="uml-node-box" style="border-radius:10px/20px; border-bottom-width:5px"><span>DB</span></div>`; break;
            case 'end': html = `<div class="uml-node-box node-end"><span>FIN</span></div>`; outs = 0; break;
        }
        editor.addNode(type, inps, outs, x, y, type, { label: 'TEXTO', rotate: 0, color: '#1e293b' }, html);
    }

    // CONTINUIDAD DE CONFIGURACIÓN
    editor.on('nodeSelected', id => {
        selectedId = id;
        const d = editor.getNodeFromId(id).data;
        document.getElementById('nodeText').value = d.label || '';
        document.getElementById('rotateRange').value = d.rotate || 0;
        document.getElementById('rotateVal').innerText = d.rotate || 0;
        
        // Sincronizar Color
        const wrapper = document.getElementById('node-' + id);
        const container = wrapper.querySelector('.drawflow_content_node > div');
        const borderColor = rgbToHex(container.style.borderColor) || d.color || '#1e293b';
        document.getElementById('nodeColor').value = borderColor;

        document.getElementById('propSidebar').classList.add('active');
    });

    function syncNode() {
        if(!selectedId) return;
        const wrapper = document.getElementById('node-' + selectedId);
        const val = document.getElementById('nodeText').value;
        const rot = document.getElementById('rotateRange').value;
        const col = document.getElementById('nodeColor').value;
        
        document.getElementById('rotateVal').innerText = rot;
        editor.updateNodeDataFromId(selectedId, { label: val, rotate: rot, color: col });

        const box = wrapper.querySelector('.drawflow_content_node > div');
        const span = box.querySelector('span');

        wrapper.style.transform = `rotate(${rot}deg)`;
        let baseOffset = box.classList.contains('uml-diamond-box') ? -45 : 0;
        span.style.transform = `rotate(${-rot + baseOffset}deg)`;
        span.innerText = val;
        box.style.borderColor = col;

        if(wrapper.offsetWidth > 0) editor.updateConnectionNodes('node-' + selectedId);
    }

    // FÍSICA PRO (Fuerza de repulsión optimizada)
    function autoDistribuir() {
        const data = editor.export().drawflow.Home.data;
        const nodes = Object.keys(data);
        if (nodes.length < 2) return;

        Swal.fire({ title: 'Calculando Física...', timer: 800, didOpen: () => Swal.showLoading() });

        for(let i=0; i<30; i++) { // Iteraciones de fuerza
            nodes.forEach(idA => {
                let nodeA = data[idA];
                let fx = 0, fy = 0;

                nodes.forEach(idB => {
                    if(idA === idB) return;
                    let nodeB = data[idB];
                    let dx = nodeA.pos_x - nodeB.pos_x;
                    let dy = nodeA.pos_y - nodeB.pos_y;
                    let dist = Math.sqrt(dx*dx + dy*dy) || 1;
                    
                    if(dist < 350) { // Fuerza de repulsión
                        let force = (350 - dist) / dist;
                        fx += dx * force * 0.8;
                        fy += dy * force * 0.8;
                    }
                });

                // Fuerza de atracción por conexiones
                const outputs = nodeA.outputs;
                Object.keys(outputs).forEach(out => {
                    outputs[out].connections.forEach(conn => {
                        let nodeTarget = data[conn.node];
                        if(nodeTarget) {
                            let dx = nodeTarget.pos_x - nodeA.pos_x;
                            let dy = nodeTarget.pos_y - nodeA.pos_y;
                            fx += dx * 0.05;
                            fy += dy * 0.05;
                        }
                    });
                });

                nodeA.pos_x += fx;
                nodeA.pos_y += fy;
            });
        }

        // Aplicar posiciones y refrescar cables
        nodes.forEach(id => {
            const el = document.getElementById('node-' + id);
            el.style.left = data[id].pos_x + "px";
            el.style.top = data[id].pos_y + "px";
            editor.drawflow.drawflow.Home.data[id].pos_x = data[id].pos_x;
            editor.drawflow.drawflow.Home.data[id].pos_y = data[id].pos_y;
            editor.updateConnectionNodes('node-' + id);
        });
    }

    // CRUD
    async function guardarProyecto() {
        let n = prompt("Nombre:");
        if(!n) return;
        const fd = new FormData(); fd.append('accion', 'guardar'); fd.append('nombre', n); fd.append('data_json', JSON.stringify(editor.export()));
        await fetch('DiagramaFlujo.php', { method: 'POST', body: fd });
        Swal.fire("Sincronizado", "OK", "success").then(() => location.reload());
    }

    async function cargarDiagrama(id) {
        if(!id) return;
        const res = await fetch('DiagramaFlujo.php?get_json=' + id);
        const data = await res.json();
        editor.clear();
        editor.import(data);
        setTimeout(aplicarVisualesPostImport, 200);
    }

    function aplicarVisualesPostImport() {
        const nodes = editor.export().drawflow.Home.data;
        Object.keys(nodes).forEach(nid => {
            const wrapper = document.getElementById('node-' + nid);
            if(wrapper) {
                const d = nodes[nid].data;
                const rot = d.rotate || 0;
                wrapper.style.transform = `rotate(${rot}deg)`;
                const box = wrapper.querySelector('.drawflow_content_node > div');
                if(d.color) box.style.borderColor = d.color;
                const span = box.querySelector('span');
                let base = box.classList.contains('uml-diamond-box') ? -45 : 0;
                if(span) span.style.transform = `rotate(${-rot + base}deg)`;
                editor.updateConnectionNodes('node-' + nid);
            }
        });
    }

    function importarJson() {
        try {
            const data = JSON.parse(document.getElementById('jsonConsole').value);
            switchTab('tools');
            setTimeout(() => {
                editor.clear();
                editor.import(data);
                aplicarVisualesPostImport();
            }, 100);
        } catch(e) { Swal.fire("Error", "JSON inválido", "error"); }
    }

    // SIMULADOR
    async function iniciarSimulacion() {
        const nodes = editor.export().drawflow.Home.data;
        let cur = Object.keys(nodes).find(id => nodes[id].name === 'start');
        if(!cur) return;
        run(cur);
    }

    async function run(id) {
        document.querySelectorAll('.drawflow-node').forEach(n => n.classList.remove('node-active'));
        document.getElementById('node-' + id).classList.add('node-active');
        const data = editor.getNodeFromId(id);
        if(data.name === 'decision') {
            const { value: res } = await Swal.fire({ title: 'Decisión', text: data.data.label, showCancelButton: true, confirmButtonText: 'SÍ', cancelButtonText: 'NO' });
            const next = res ? data.outputs.output_1.connections[0] : data.outputs.output_2.connections[0];
            if(next) setTimeout(() => run(next.node), 500);
            return;
        }
        const nxt = data.outputs.output_1.connections[0];
        if(nxt) setTimeout(() => run(nxt.node), 800);
    }

    function deleteNode() { editor.removeNodeId('node-' + selectedId); document.getElementById('propSidebar').classList.remove('active'); }
    function rgbToHex(rgb) { if(!rgb) return ""; let res = rgb.match(/\d+/g); return res ? "#" + res.map(x => parseInt(x).toString(16).padStart(2, '0')).join('') : ""; }
</script>
</body>
</html>