<?php
/**
 * Gemeinsame Hilfsfunktionen für alle Seiten.
 * Alle Funktionsnamen beginnen mit function_
 */

if (!defined('APP_ROOT')) {
    return;
}

/** Präfix für verschlüsselt gespeicherte Werte in einstellungen */
define('WECKER_ENCRYPTED_PREFIX', 'enc1:');

/**
 * Verschlüsselt einen String (AES-256-CBC) für die Speicherung in der DB.
 * @return string Präfix + Base64(IV + Cipher)
 */
function function_encrypt_secret(string $plain): string
{
    $key = hash('sha256', defined('WECKER_SECRET_KEY') ? WECKER_SECRET_KEY : 'fallback', true);
    $iv = random_bytes(16);
    $cipher = openssl_encrypt($plain, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
    if ($cipher === false) {
        return $plain;
    }
    return WECKER_ENCRYPTED_PREFIX . base64_encode($iv . $cipher);
}

/**
 * Entschlüsselt einen mit function_encrypt_secret gespeicherten String.
 * @return string Klartext oder bei Fehler den Eingabestring
 */
function function_decrypt_secret(string $value): string
{
    if (strpos($value, WECKER_ENCRYPTED_PREFIX) !== 0) {
        return $value;
    }
    $raw = base64_decode(substr($value, strlen(WECKER_ENCRYPTED_PREFIX)), true);
    if ($raw === false || strlen($raw) < 16) {
        return $value;
    }
    $key = hash('sha256', defined('WECKER_SECRET_KEY') ? WECKER_SECRET_KEY : 'fallback', true);
    $iv = substr($raw, 0, 16);
    $cipher = substr($raw, 16);
    $plain = openssl_decrypt($cipher, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
    return $plain !== false ? $plain : $value;
}

/**
 * JSON-Antwort für APIs ausgeben und Script beenden.
 * @param bool $ok
 * @param array $data Zusätzliche Daten (z. B. ['wecker' => ...])
 * @param string $error Fehlermeldung wenn !$ok
 */
function function_json_antwort(bool $ok, array $data = [], string $error = ''): void
{
    $out = ['ok' => $ok];
    if ($ok) {
        $out = array_merge($out, $data);
    } else {
        $out['error'] = $error;
    }
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($out);
    exit;
}

/**
 * Dateisystem-Pfad für Audio (WAV/TTS-Ausgabe).
 */
function function_storage_audio_dir(): string
{
    return (defined('STORAGE_ROOT') ? STORAGE_ROOT : (dirname(APP_ROOT) . '/storage')) . '/audio/';
}

/**
 * URL für eine Audio-Datei aus storage (zum Abspielen im Browser).
 */
function function_storage_audio_url(string $filename): string
{
    return '/audio_file.php?f=' . urlencode(basename($filename));
}

/**
 * Dateisystem-Pfad für TTS-Cache (z. B. tts_models.json).
 */
function function_storage_tts_dir(): string
{
    return (defined('STORAGE_ROOT') ? STORAGE_ROOT : (dirname(APP_ROOT) . '/storage')) . '/tts/';
}

/**
 * TTS-Modelle aus storage/tts/tts_models.json laden.
 * @return array Liste der Modelle
 */
function function_tts_models_laden(): array
{
    $storage_tts = (defined('STORAGE_ROOT') ? STORAGE_ROOT : (dirname(APP_ROOT) . '/storage')) . '/tts/tts_models.json';
    $models_file = file_exists($storage_tts) ? $storage_tts : (defined('APP_ROOT') ? APP_ROOT . '/debug/tts_models.json' : $storage_tts);
    if (!file_exists($models_file)) {
        return [];
    }
    $cache = json_decode(file_get_contents($models_file), true);
    return isset($cache['models']) && is_array($cache['models']) ? $cache['models'] : [];
}

/**
 * Wochentag-Labels für Anzeige (Mo–So).
 * @return array 1=>'Mo', 2=>'Di', ...
 */
function function_wochentage_labels(): array
{
    return [1 => 'Mo', 2 => 'Di', 3 => 'Mi', 4 => 'Do', 5 => 'Fr', 6 => 'Sa', 7 => 'So'];
}

/**
 * Wecker-Liste für Frontend/JS aufbereiten (mit Wochentagen).
 * @param array $wecker Liste aus function_wecker_hole_alle()
 * @return array
 */
function function_wecker_fuer_frontend(array $wecker): array
{
    $out = [];
    foreach ($wecker as $w) {
        $wochentage = ($w['wiederholung'] ?? '') === 'woechentlich'
            ? function_wecker_hole_wochentage((int) $w['id'])
            : [];
        $out[] = [
            'id'          => (int) $w['id'],
            'weckzeit'    => substr($w['weckzeit'], 0, 5),
            'weckdatum'   => $w['weckdatum'] ?: null,
            'wiederholung'=> $w['wiederholung'] ?? 'taeglich',
            'wochentage'  => $wochentage,
            'sprachtext'  => $w['sprachtext'] ?? '',
            'aktiv'       => (bool) ($w['aktiv'] ?? 0),
        ];
    }
    return $out;
}

/**
 * Einstellungen für API (GET) als assoziatives Array.
 * @return array
 */
function function_einstellungen_fuer_api(): array
{
    return [
        'tts_provider'          => function_einstellung_hole('tts_provider') ?? 'piper',
        'tts_modell'            => function_einstellung_hole('tts_modell') ?? 'de_DE-thorsten-high',
        'tts_openai_api_key'     => (function_einstellung_hole('tts_openai_api_key') ?? '') !== '' ? '********' : '',
        'tts_openai_model'       => function_einstellung_hole('tts_openai_model') ?? 'tts-1',
        'tts_openai_voice'       => function_einstellung_hole('tts_openai_voice') ?? 'alloy',
        'lautstaerke'          => function_einstellung_hole('lautstaerke') ?? '100',
        'lautstaerke_musik'    => function_einstellung_hole('lautstaerke_musik') ?? '80',
        'musik_ducking_prozent'=> function_einstellung_hole('musik_ducking_prozent') ?? '20',
        'zeitzone'             => function_einstellung_hole('zeitzone') ?? 'Europe/Berlin',
        'tts_name'             => function_einstellung_hole('tts_name') ?? '',
        'wetter_ort'           => function_einstellung_hole('wetter_ort') ?? '',
        'sleep_mode_sekunden'  => function_einstellung_hole('sleep_mode_sekunden') ?? '0',
        'accent_color'         => function_einstellung_hole('accent_color') ?? '',
    ];
}

/**
 * WMO-Wettercode in lesbare Beschreibung umwandeln.
 * @param int|string $code
 * @return string
 */
function function_wmo_beschreibung($code): string
{
    $map = [
        0 => 'Klar', 1 => 'Überwiegend klar', 2 => 'Teilweise bewölkt', 3 => 'Bewölkt',
        45 => 'Nebel', 48 => 'Nebel', 51 => 'Nieselregen', 53 => 'Nieselregen', 55 => 'Nieselregen',
        61 => 'Regen', 63 => 'Regen', 65 => 'Starkregen',
        71 => 'Schnee', 73 => 'Schnee', 75 => 'Starkschnee',
        77 => 'Schnee', 80 => 'Regenschauer', 81 => 'Regenschauer', 82 => 'Regenschauer',
        85 => 'Schneeschauer', 86 => 'Schneeschauer',
        95 => 'Gewitter', 96 => 'Gewitter mit Hagel', 99 => 'Gewitter mit Hagel',
    ];
    $code = (int) $code;
    return $map[$code] ?? 'Unbekannt';
}
