<?php
/**
 * API: System-Info für Einstellungen (IP, letzter Cron-Lauf, Status).
 * action=run:        Alle Cronjobs einmal manuell ausführen.
 * action=run_job:    Einzelnen Cronjob ausführen (job=name).
 * action=list_jobs:  Liste aller verfügbaren Cronjobs liefern.
 * action=reset_cache: Wetter- und TTS-Cache leeren.
 */
require __DIR__ . '/../config.php';
require FUNCTIONS_ROOT . '/functions_common.php';

header('Content-Type: application/json; charset=utf-8');

$storageRoot = defined('STORAGE_ROOT') ? rtrim(STORAGE_ROOT, DIRECTORY_SEPARATOR) : (dirname(__DIR__) . DIRECTORY_SEPARATOR . 'storage');
$stateFile = $storageRoot . DIRECTORY_SEPARATOR . 'cronjob_master.json';
$weckerRoot = dirname(__DIR__);
$cronjobDir = $weckerRoot . DIRECTORY_SEPARATOR . 'cronjob';

/** Menschenlesbare Labels für bekannte Job-Namen */
function cron_job_label(string $name): string {
    $labels = [
        'tts_vorwecker'  => 'TTS Vorwecker',
        'refresh_wetter' => 'Wetter aktualisieren',
        'timer_pruefung' => 'Timer-Prüfung',
    ];
    return $labels[$name] ?? ucwords(str_replace('_', ' ', $name));
}

// Liste aller verfügbaren Cronjob-Skripte (Dateisystem + DB-Info)
if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'list_jobs') {
    $jobs = [];
    if (is_dir($cronjobDir)) {
        $files = @glob($cronjobDir . DIRECTORY_SEPARATOR . '*.php');
        if ($files) {
            sort($files);
            // DB-Infos laden (optional, wenn verfügbar)
            $dbInfo = [];
            $pdo = $GLOBALS['pdo'] ?? null;
            if ($pdo) {
                try {
                    $stmt = $pdo->query("SELECT name, interval_sekunden, letzte_ausfuehrung, aktiv FROM cronjobs ORDER BY id");
                    if ($stmt) {
                        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                            $dbInfo[$row['name']] = $row;
                        }
                    }
                } catch (Throwable $e) {}
            }
            foreach ($files as $file) {
                $name = basename($file, '.php');
                $safeName = preg_replace('/[^a-z0-9_-]/', '', strtolower($name));
                if ($safeName === '') continue;
                $db = $dbInfo[$safeName] ?? null;
                $jobs[] = [
                    'name'               => $safeName,
                    'label'              => cron_job_label($safeName),
                    'interval_sekunden'  => $db ? (int)$db['interval_sekunden'] : null,
                    'letzte_ausfuehrung' => $db ? ($db['letzte_ausfuehrung'] ?? null) : null,
                    'aktiv'              => $db ? (bool)$db['aktiv'] : true,
                ];
            }
        }
    }
    function_json_antwort(true, ['jobs' => $jobs]);
    exit;
}

// Einzelnen Cronjob ausführen
if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'run_job') {
    $jobName = isset($_REQUEST['job']) ? preg_replace('/[^a-z0-9_-]/', '', strtolower(trim((string)$_REQUEST['job']))) : '';
    if ($jobName === '') {
        function_json_antwort(false, ['message' => 'Kein Job angegeben.']);
        exit;
    }
    $script = $cronjobDir . DIRECTORY_SEPARATOR . $jobName . '.php';
    if (!is_file($script)) {
        function_json_antwort(false, ['message' => 'Job-Skript nicht gefunden: ' . $jobName]);
        exit;
    }
    $php = (defined('PHP_BINARY') && PHP_BINARY !== '') ? PHP_BINARY : 'php';
    $cmd = escapeshellarg($php) . ' ' . escapeshellarg($script) . ' 2>&1';
    $output = [];
    $code = -1;
    @exec($cmd, $output, $code);
    // letzte_ausfuehrung in DB aktualisieren
    $pdo = $GLOBALS['pdo'] ?? null;
    if ($pdo) {
        try {
            $pdo->prepare("UPDATE cronjobs SET letzte_ausfuehrung = NOW() WHERE name = ?")->execute([$jobName]);
        } catch (Throwable $e) {}
    }
    if ($code === 0) {
        function_json_antwort(true, ['message' => cron_job_label($jobName) . ' ausgeführt.']);
    } else {
        $err = trim(implode("\n", $output));
        function_json_antwort(false, ['message' => $err !== '' ? $err : $jobName . ' fehlgeschlagen.']);
    }
    exit;
}

// Cache zurücksetzen (Wetter-Cache + TTS-Cache)
if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'reset_cache') {
    $errors = [];
    $wetterDir = $storageRoot . DIRECTORY_SEPARATOR . 'wetter_cache';
    if (is_dir($wetterDir)) {
        $files = @glob($wetterDir . DIRECTORY_SEPARATOR . '*');
        if ($files !== false) {
            foreach ($files as $f) {
                if (is_file($f)) {
                    @unlink($f);
                }
            }
        }
    }
    $pdo = $GLOBALS['pdo'] ?? null;
    $ttsDir = $storageRoot . DIRECTORY_SEPARATOR . 'tts';
    if ($pdo && is_dir($ttsDir)) {
        try {
            $stmt = $pdo->query('SELECT audio_dateiname FROM wecker_tts_cache');
            if ($stmt) {
                while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                    if (!empty($row['audio_dateiname'])) {
                        $path = $ttsDir . DIRECTORY_SEPARATOR . basename($row['audio_dateiname']);
                        if (is_file($path) && basename($path) !== 'tts_models.json') {
                            @unlink($path);
                        }
                    }
                }
            }
            $pdo->exec('TRUNCATE TABLE wecker_tts_cache');
        } catch (Throwable $e) {
            $errors[] = 'TTS-Cache: ' . $e->getMessage();
        }
    }
    if (count($errors) > 0) {
        function_json_antwort(false, ['message' => implode(' ', $errors)]);
    } else {
        function_json_antwort(true, ['message' => 'Cache wurde zurückgesetzt (Wetter + TTS).']);
    }
    exit;
}

// Manuellen Cron-Lauf ausführen
if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'run') {
    $weckerRoot = dirname(__DIR__);
    $script = $weckerRoot . DIRECTORY_SEPARATOR . 'cronjob_run_once.php';
    if (!is_file($script)) {
        function_json_antwort(false, ['message' => 'cronjob_run_once.php nicht gefunden.']);
        exit;
    }
    $php = (defined('PHP_BINARY') && PHP_BINARY !== '') ? PHP_BINARY : 'php';
    $cmd = escapeshellarg($php) . ' ' . escapeshellarg($script) . ' 2>&1';
    $output = [];
    $code = -1;
    @exec($cmd, $output, $code);
    if ($code === 0) {
        function_json_antwort(true, ['message' => 'Cron einmal ausgeführt.']);
    } else {
        $err = trim(implode("\n", $output));
        function_json_antwort(false, ['message' => $err !== '' ? $err : 'Cron-Ausführung fehlgeschlagen.']);
    }
    exit;
}

$ip = isset($_SERVER['SERVER_ADDR']) ? trim((string) $_SERVER['SERVER_ADDR']) : '';
$isLoopback = ($ip === '127.0.0.1' || $ip === '' || (strpos($ip, '127.') === 0));

// Wenn nur Localhost/Loopback: interne Netzwerk-IP ermitteln (z. B. 192.168.x.x)
if ($isLoopback) {
    $ip = '';
    // Linux: hostname -I liefert die Adressen der Netzwerk-Interfaces (erste ist meist die LAN-IP)
    if (PHP_OS_FAMILY === 'Linux' && function_exists('shell_exec')) {
        $out = @shell_exec('hostname -I 2>/dev/null');
        if ($out !== null && $out !== '') {
            $addrs = preg_split('/\s+/', trim($out), -1, PREG_SPLIT_NO_EMPTY);
            foreach ($addrs as $addr) {
                $addr = trim($addr);
                if ($addr !== '' && strpos($addr, '127.') !== 0) {
                    $ip = $addr;
                    break;
                }
            }
        }
    }
    // Fallback: gethostbyname (kann auf einigen Systemen die LAN-IP liefern)
    if ($ip === '' && function_exists('gethostname')) {
        $host = gethostname();
        if ($host && function_exists('gethostbyname')) {
            $resolved = gethostbyname($host);
            if ($resolved !== $host && strpos($resolved, '127.') !== 0) {
                $ip = $resolved;
            }
        }
    }
}
if ($ip === '' && !$isLoopback) {
    $ip = isset($_SERVER['SERVER_ADDR']) ? trim((string) $_SERVER['SERVER_ADDR']) : '';
}
if ($ip === '' && function_exists('gethostname') && function_exists('gethostbyname')) {
    $host = gethostname();
    if ($host) {
        $resolved = gethostbyname($host);
        if ($resolved !== $host && strpos($resolved, '127.') !== 0) {
            $ip = $resolved;
        }
    }
}

$cronLastActivity = null;
$cronStatus = 'error'; // kein Lauf / älter als 5 Min = rot
if (is_file($stateFile)) {
    $content = @file_get_contents($stateFile);
    if ($content !== false) {
        $state = @json_decode($content, true);
        if (is_array($state) && !empty($state['last_activity'])) {
            $cronLastActivity = $state['last_activity'];
            $ts = strtotime($cronLastActivity);
            if ($ts !== false) {
                $age = time() - $ts;
                if ($age <= 60) {
                    $cronStatus = 'ok';   // ≤ 1 Min = grün
                } elseif ($age <= 300) {
                    $cronStatus = 'warn'; // 1–5 Min = gelb
                }
                // > 5 Min bleibt 'error' (rot)
            }
        }
    }
}

function_json_antwort(true, [
    'ip'                 => $ip,
    'cron_last_activity' => $cronLastActivity,
    'cron_status'        => $cronStatus,
]);
