<?php
// Fallback tab data helpers

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/partnership.php';   // vv_pt_ssh(), vv_pt_ts_peers()

// ── Conf parsers ──────────────────────────────────────────────────────────────

function vv_fb_bash_array(string $raw, string $varname): array {
    if (!preg_match('/^\s*' . preg_quote($varname, '/') . '\s*=\s*\(\s*(.*?)\s*\)/ms', $raw, $m))
        return [];
    preg_match_all('/"([^"]*)"/', $m[1], $items);
    return array_values(array_filter($items[1]));
}

function vv_fb_scalar(string $raw, string $varname): string {
    return preg_match('/^\s*' . preg_quote($varname, '/') . '\s*=\s*"?([^"\n]*)"?/m', $raw, $m)
        ? trim($m[1]) : '';
}

// ── State file ────────────────────────────────────────────────────────────────

function vv_fb_parse_state(string $text): array {
    $out = [
        'state'            => 'UNKNOWN',
        'fallback_start'   => 0,
        'handback_strikes' => 0,
        'tier2_started'    => false,
        'tier3_started'    => false,
        'tier4_started'    => false,
    ];
    foreach (explode("\n", $text) as $line) {
        $line = trim($line);
        if (!$line || !str_contains($line, '=')) continue;
        [$k, $v] = array_pad(explode('=', $line, 2), 2, '');
        $k = trim($k); $v = trim($v, '"\'');
        switch ($k) {
            case 'state':            $out['state']            = $v;          break;
            case 'fallback_start':   $out['fallback_start']   = (int)$v;     break;
            case 'handback_strikes': $out['handback_strikes'] = (int)$v;     break;
            case 'tier2_started':    $out['tier2_started']    = $v === 'true'; break;
            case 'tier3_started':    $out['tier3_started']    = $v === 'true'; break;
            case 'tier4_started':    $out['tier4_started']    = $v === 'true'; break;
        }
    }
    return $out;
}

function vv_fb_local_state(): array {
    $path = '/boot/config/fallback_state.db';
    return vv_fb_parse_state(file_exists($path) ? file_get_contents($path) : '');
}

function vv_fb_remote_state(string $ip, string $sshKey): array {
    $out = vv_pt_ssh($ip, $sshKey, 'cat /boot/config/fallback_state.db 2>/dev/null');
    return vv_fb_parse_state($out);
}

// ── Running containers ────────────────────────────────────────────────────────

function vv_fb_local_running(): array {
    $out = shell_exec("docker ps --format '{{.Names}}' 2>/dev/null") ?: '';
    return array_values(array_filter(explode("\n", trim($out))));
}

function vv_fb_remote_running(string $ip, string $sshKey): array {
    $out = vv_pt_ssh($ip, $sshKey, "docker ps --format '{{.Names}}' 2>/dev/null");
    return array_values(array_filter(explode("\n", trim($out))));
}

// ── Covers — what a node runs for the other when it's down ───────────────────

function vv_fb_covers(string $covering, string $remote, string $coveringRaw, string $remoteRaw): array {
    $cu = strtoupper($covering); // HOST1
    $ru = strtoupper($remote);   // HOST2
    $tiers = [];
    for ($t = 1; $t <= 4; $t++) {
        $tiers["tier$t"] = vv_fb_bash_array($coveringRaw, "FALLBACK_{$cu}_COVERS_{$ru}_TIER{$t}");
    }
    // Delays: how long the remote (covered) host must be down before each tier fires.
    // Stored in the *remote* host's conf as REMOTE_TIER*_DELAY.
    $tiers['delays'] = [
        'tier2' => (int)(vv_fb_scalar($remoteRaw, "{$ru}_TIER2_DELAY") ?: 240),
        'tier3' => (int)(vv_fb_scalar($remoteRaw, "{$ru}_TIER3_DELAY") ?: 720),
        'tier4' => (int)(vv_fb_scalar($remoteRaw, "{$ru}_TIER4_DELAY") ?: 1440),
    ];
    return $tiers;
}

// ── Known hosts ───────────────────────────────────────────────────────────────

function vv_fb_known_hosts(): array {
    $master = vv_read_conf_raw('master.conf');
    preg_match_all('/^\s*(HOST(\d+))(?:_NAME)?\s*=\s*["\']?(\S+?)["\']?\s*$/m', $master, $m);
    $hosts = [];
    foreach ($m[1] as $i => $key) {
        $num  = $m[2][$i];
        $name = trim($m[3][$i]);
        $hosts['host' . $num] = $name;
    }
    ksort($hosts);
    return $hosts ?: ['host1' => 'HOST1'];
}

// ── Main data builder ─────────────────────────────────────────────────────────

function vv_fb_all(): array {
    $currentHost  = vv_detect_host();
    $hosts        = vv_fb_known_hosts();
    $tsPeers      = vv_pt_ts_peers();
    $handbackReq  = (int)(vv_fb_scalar(vv_read_conf_raw('master.conf'), 'FALLBACK_HANDBACK_STRIKES') ?: 3);
    $fbEnabled    = vv_fb_scalar(vv_read_conf_raw('master.conf'), 'FALLBACK_ENABLED') === 'true';

    // Read all host conf raws upfront
    $raws = [];
    foreach (array_keys($hosts) as $slot) {
        $raws[$slot] = vv_read_conf_raw($slot . '.conf');
    }

    // SSH key — from local host conf
    $myId     = strtoupper($currentHost);
    $myRaw    = $raws[$currentHost] ?? '';
    $mySshKey = vv_fb_scalar($myRaw, $myId . '_SSH_KEY');

    $nodes = [];
    foreach ($hosts as $slot => $hostname) {
        $isMe   = ($slot === $currentHost || $currentHost === 'unknown');
        $tsLabel = strtolower($hostname);
        $ts      = $tsPeers[$tsLabel] ?? ['online' => null, 'active' => false, 'ip' => null];
        $ip      = $ts['ip'] ?? null;

        // State
        if ($isMe) {
            $state = vv_fb_local_state();
        } elseif ($ip && $mySshKey) {
            $state = vv_fb_remote_state($ip, $mySshKey);
        } else {
            $state = vv_fb_parse_state('');
            $state['state'] = $ts['online'] === false ? 'OFFLINE' : 'UNREACHABLE';
        }

        // Running containers
        if ($isMe) {
            $running = vv_fb_local_running();
        } elseif ($ip && $mySshKey && $ts['online']) {
            $running = vv_fb_remote_running($ip, $mySshKey);
        } else {
            $running = [];
        }

        // Covers: for a 2-node setup, each covers the other
        // For N nodes this would need a different approach — for now, assume 2-node
        $covers = null;
        foreach ($hosts as $otherSlot => $otherHostname) {
            if ($otherSlot === $slot) continue;
            $coveringRaw = $raws[$slot]      ?? '';
            $remoteRaw   = $raws[$otherSlot] ?? '';
            $covers = [
                'slot'     => $otherSlot,
                'id'       => strtoupper($otherSlot),
                'hostname' => $otherHostname,
            ] + vv_fb_covers($slot, $otherSlot, $coveringRaw, $remoteRaw);
            break; // 2-node only
        }

        $nodes[] = [
            'slot'         => $slot,
            'id'           => strtoupper($slot),
            'hostname'     => $hostname,
            'is_me'        => $isMe,
            'ts_online'    => $ts['online'],
            'state'        => $state,
            'running'      => $running,
            'covers'       => $covers,
        ];
    }

    return [
        'ts'            => time(),
        'fb_enabled'    => $fbEnabled,
        'handback_req'  => $handbackReq,
        'nodes'         => $nodes,
    ];
}
