<?php
/**
 * Demo Oracle — declaration des bases de demonstration.
 *
 * Cinq bases au maximum. La limite est verifiee ICI, cote serveur, et pas
 * seulement en masquant le bouton : c'est la contrainte qui definit la
 * demonstration, elle ne peut pas dependre de l'interface.
 *
 * Accessible aux seuls porteurs de demo_oracle_admin. Les mots de passe sont
 * chiffres par lib/Crypto avant stockage, et jamais reaffiches — le formulaire
 * applique le motif « laisser vide pour conserver ».
 */
require_once dirname(__DIR__, 2) . '/bootstrap.php';
require_once __DIR__ . '/lib/boot.php';

$auth->requireRole('demo_oracle_admin');

if (!$moduleRegistry->canAccess('demo_oracle', $currentUser)) {
    http_response_code(403);
    include WEBROOT_PATH . '/includes/403.php';
    exit;
}

if (!Session::has('csrf_token')) {
    Session::set('csrf_token', bin2hex(random_bytes(32)));
}
$csrfToken = Session::get('csrf_token');
$action    = $_GET['action'] ?? 'list';
$editId    = (int)($_GET['id'] ?? 0);
$errors    = [];

/* ── POST ───────────────────────────────────────────────────────────────── */
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!hash_equals($csrfToken, $_POST['csrf_token'] ?? '')) {
        Session::setFlash('error', t('msg.error'));
        header('Location: ' . demo_oracle_url('db.list'));
        exit;
    }

    $post = $_POST['action'] ?? '';

    if ($post === 'delete') {
        $id = (int)($_POST['db_id'] ?? 0);

        /* Le portefeuille part avec la fiche : le laisser sur le disque
           reviendrait a garder des cles de connexion pour une base qui n'est
           plus declaree. */
        $gone = $db->fetchOne("SELECT wallet_path FROM demo_oracle_databases WHERE id = ?", [$id]);
        if ($gone && ($gone['wallet_path'] ?? '') !== '') {
            DemoOracleWallet::delete((string)$gone['wallet_path']);
        }

        $db->execute("DELETE FROM demo_oracle_databases WHERE id = ?", [$id]);
        // La base supprimee etait peut-etre celle en cours de consultation.
        $sel = Session::get('demo_oracle_selected_db');
        if ($sel && (int)($sel['id'] ?? 0) === $id) {
            Session::remove('demo_oracle_selected_db');
        }
        Session::setFlash('success', t('msg.deleted'));
        header('Location: ' . demo_oracle_url('db.list'));
        exit;
    }

    if ($post === 'save') {
        $id      = (int)($_POST['id'] ?? 0);
        $name    = trim((string)($_POST['name'] ?? ''));
        $type    = ($_POST['conn_type'] ?? 'standard') === 'cloud' ? 'cloud' : 'standard';
        $host    = trim((string)($_POST['host'] ?? ''));
        $port    = (int)($_POST['port'] ?? 1521);
        $service = trim((string)($_POST['service_name'] ?? ''));
        $alias   = trim((string)($_POST['tns_alias'] ?? ''));
        $user    = trim((string)($_POST['username'] ?? ''));
        $pass    = (string)($_POST['password'] ?? '');
        $sysdba  = empty($_POST['sysdba']) ? 0 : 1;
        $desc    = trim((string)($_POST['description'] ?? ''));

        $walletUp = isset($_FILES['wallet']) && $_FILES['wallet']['error'] === UPLOAD_ERR_OK;

        if ($name === '') $errors[] = t('demo_oracle.db_name_required');

        /* Les champs obligatoires dependent du type : une base joignable par
           portefeuille n'a ni hote ni service, elle a un alias. */
        if ($type === 'standard') {
            if ($host === '')    $errors[] = t('demo_oracle.db_host_required');
            if ($service === '') $errors[] = t('demo_oracle.db_service_required');
            if ($port <= 0 || $port > 65535) $errors[] = t('demo_oracle.db_port_invalid');
        } else {
            if ($alias === '') $errors[] = t('demo_oracle.cloud_alias_required');
            /* Le portefeuille n'est exige qu'a la creation : une modification
               conserve celui deja extrait, sauf remplacement explicite. */
            $hasWallet = false;
            if ($id) {
                $cur = $db->fetchOne("SELECT wallet_path FROM demo_oracle_databases WHERE id = ?", [$id]);
                $hasWallet = $cur && ($cur['wallet_path'] ?? '') !== '' && is_dir($cur['wallet_path']);
            }
            if (!$walletUp && !$hasWallet) $errors[] = t('demo_oracle.cloud_wallet_required');
        }

        // Le plafond ne concerne que la creation : modifier la cinquieme base
        // doit rester possible.
        if (!$id && !DemoOracleSchema::hasRoom($db)) {
            $errors[] = t('demo_oracle.db_limit_reached', ['max' => (string)DEMO_ORACLE_MAX_DATABASES]);
        }

        if (!$errors) {
            /* Les champs de l'autre type sont vides plutot que conserves : un
               enregistrement qui garderait un hote ET un alias laisserait
               planer un doute sur ce qui sert reellement. */
            $vHost  = $type === 'standard' ? $host    : '';
            $vPort  = $type === 'standard' ? $port    : 1521;
            $vSvc   = $type === 'standard' ? $service : '';
            $vAlias = $type === 'cloud'    ? $alias   : '';

            if ($id) {
                // Mot de passe vide = on conserve celui deja enregistre.
                if ($pass !== '') {
                    $db->execute(
                        "UPDATE demo_oracle_databases
                            SET name=?, conn_type=?, host=?, port=?, service_name=?,
                                tns_alias=?, username=?, password=?, sysdba=?,
                                description=?, updated_at=datetime('now')
                          WHERE id=?",
                        [$name, $type, $vHost, $vPort, $vSvc, $vAlias, $user,
                         Crypto::encrypt($pass), $sysdba, $desc, $id]
                    );
                } else {
                    $db->execute(
                        "UPDATE demo_oracle_databases
                            SET name=?, conn_type=?, host=?, port=?, service_name=?,
                                tns_alias=?, username=?, sysdba=?,
                                description=?, updated_at=datetime('now')
                          WHERE id=?",
                        [$name, $type, $vHost, $vPort, $vSvc, $vAlias, $user,
                         $sysdba, $desc, $id]
                    );
                }
                $savedId = $id;
            } else {
                $db->execute(
                    "INSERT INTO demo_oracle_databases
                        (name, conn_type, host, port, service_name, tns_alias,
                         username, password, sysdba, description)
                     VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                    [$name, $type, $vHost, $vPort, $vSvc, $vAlias, $user,
                     Crypto::encrypt($pass), $sysdba, $desc]
                );
                $savedId = (int)$db->lastInsertId();
            }

            /* Portefeuille : extrait apres l'enregistrement, le repertoire
               etant nomme d'apres l'identifiant de la fiche. Un remplacement
               efface l'ancien d'abord — deux jeux de cles melanges dans le
               meme repertoire ne donneraient rien de bon. */
            if ($type === 'cloud' && $walletUp) {
                $dir = DemoOracleWallet::pathFor($savedId);
                DemoOracleWallet::delete($dir);
                $res = DemoOracleWallet::extract($_FILES['wallet']['tmp_name'], $dir);
                if ($res['ok']) {
                    $db->execute("UPDATE demo_oracle_databases SET wallet_path=? WHERE id=?",
                                 [$dir, $savedId]);
                } else {
                    $errors[] = $res['msg'];
                }
            }

            /* Le type a change pour « direct » : le portefeuille devenu inutile
               est efface, plutot que laisse en place sans reference. */
            if ($type === 'standard') {
                $old = $db->fetchOne("SELECT wallet_path FROM demo_oracle_databases WHERE id = ?", [$savedId]);
                if ($old && ($old['wallet_path'] ?? '') !== '') {
                    DemoOracleWallet::delete((string)$old['wallet_path']);
                    $db->execute("UPDATE demo_oracle_databases SET wallet_path=NULL WHERE id=?", [$savedId]);
                }
            }

            if (!$errors) {
                Session::setFlash('success', t('msg.saved'));
                header('Location: ' . demo_oracle_url('db.list'));
                exit;
            }
        }

        // On repasse par le formulaire en conservant la saisie.
        $action = $id ? 'edit' : 'new';
        $editId = $id;
    }
}

/* ── GET ────────────────────────────────────────────────────────────────── */
$record = [];
if ($action === 'edit' && $editId) {
    $record = demo_oracle_database($db, $editId);
    if (!$record) {
        Session::setFlash('error', t('demo_oracle.db_not_found'));
        header('Location: ' . demo_oracle_url('db.list'));
        exit;
    }
}
if ($action === 'new' && !DemoOracleSchema::hasRoom($db) && !$errors) {
    Session::setFlash('error', t('demo_oracle.db_limit_reached',
        ['max' => (string)DEMO_ORACLE_MAX_DATABASES]));
    header('Location: ' . demo_oracle_url('db.list'));
    exit;
}

View::display(__DIR__ . '/views/databases.php', [
    'action'    => in_array($action, ['new', 'edit'], true) ? $action : 'list',
    'record'    => $record,
    'databases' => demo_oracle_databases($db),
    'hasRoom'   => DemoOracleSchema::hasRoom($db),
    'maxDbs'    => DEMO_ORACLE_MAX_DATABASES,
    'errors'    => $errors,
    'post'      => $_POST,
    'csrfToken' => $csrfToken,
    'pageTitle' => t('demo_oracle.db_manage'),
]);
