<?php
/**
 * TTS-Generierung: Piper (lokal) oder OpenAI (API).
 * Nutzt Einstellungen: tts_provider, tts_modell (Piper), tts_openai_* (OpenAI).
 */
if (!defined('FUNCTIONS_ROOT')) {
    return;
}

require_once __DIR__ . '/functions_wecker.php';
require_once __DIR__ . '/functions_common.php';

/**
 * Generiert TTS-Audio aus Text. Platzhalter werden ersetzt.
 * @param string $text Rohtext (kann {{name}} etc. enthalten)
 * @param DateTimeInterface|null $zeit Für Platzhalter-Ersetzung
 * @param array $overrides Optional: provider, modell (Piper), openai_model, openai_voice, openai_api_key
 * @return array ['ok' => true, 'url' => '/audio_file.php?f=...'] oder ['ok' => false, 'error' => '...']
 */
function function_tts_generieren(string $text, ?DateTimeInterface $zeit = null, array $overrides = []): array
{
    if (empty($overrides['skip_placeholder_replace'])) {
        $weckzeit = isset($overrides['weckzeit']) ? (string) $overrides['weckzeit'] : null;
        $text = function_tts_text_ersetzen($text, $zeit, $weckzeit !== '' ? $weckzeit : null);
    }
    $text = trim($text);
    if ($text === '') {
        return ['ok' => false, 'error' => 'Text nach Ersetzung leer.'];
    }

    $provider = isset($overrides['provider']) ? strtolower(trim((string) $overrides['provider'])) : (function_einstellung_hole('tts_provider') ?: 'piper');
    if ($provider === 'openai') {
        return function_tts_generieren_openai($text, $overrides);
    }
    return function_tts_generieren_piper($text, $overrides);
}

/**
 * TTS per Piper (lokales Skript).
 * @param array $overrides Optional: modell
 */
function function_tts_generieren_piper(string $text, array $overrides = []): array
{
    $model = isset($overrides['modell']) && $overrides['modell'] !== '' ? (string) $overrides['modell'] : (function_einstellung_hole('tts_modell') ?: 'de_DE-thorsten-high');
    $script = defined('TTS_PIPER_SCRIPT') ? TTS_PIPER_SCRIPT : (dirname(STORAGE_ROOT) . '/skripts_webseite/PythonTTS2.sh');
    if (!is_file($script) || !is_executable($script)) {
        return ['ok' => false, 'error' => 'Piper-TTS-Skript nicht gefunden oder nicht ausführbar.'];
    }

    $audioDir = function_storage_audio_dir();
    if (!is_dir($audioDir)) {
        @mkdir($audioDir, 0755, true);
    }
    $filename = 'tts_' . time() . '_' . substr(md5($text), 0, 8) . '.wav';
    $outPath = $audioDir . $filename;

    $cmd = escapeshellcmd($script) . ' '
        . escapeshellarg($model) . ' '
        . escapeshellarg($text) . ' '
        . escapeshellarg($outPath);
    $output = [];
    exec($cmd . ' 2>&1', $output, $ret);

    if ($ret !== 0 || !is_file($outPath)) {
        $msg = !empty($output) ? implode(' ', $output) : 'Piper-TTS fehlgeschlagen.';
        return ['ok' => false, 'error' => $msg];
    }

    return ['ok' => true, 'url' => function_storage_audio_url($filename), 'file' => $filename];
}

/**
 * TTS per OpenAI API (audio/speech).
 * @param array $overrides Optional: openai_api_key, openai_model, openai_voice, openai_speed, openai_instructions
 */
function function_tts_generieren_openai(string $text, array $overrides = []): array
{
    $apiKey = (isset($overrides['openai_api_key']) && trim((string) $overrides['openai_api_key']) !== '')
        ? trim((string) $overrides['openai_api_key'])
        : (function_einstellung_hole('tts_openai_api_key') ?: '');
    $apiKey = trim($apiKey);
    if ($apiKey === '') {
        return ['ok' => false, 'error' => 'OpenAI API-Key fehlt (Einstellungen oder manuell eingeben).'];
    }

    $model = (isset($overrides['openai_model']) && $overrides['openai_model'] !== '') ? (string) $overrides['openai_model'] : (function_einstellung_hole('tts_openai_model') ?: 'tts-1');
    $voice = (isset($overrides['openai_voice']) && $overrides['openai_voice'] !== '') ? (string) $overrides['openai_voice'] : (function_einstellung_hole('tts_openai_voice') ?: 'alloy');
    $allowedVoices = ['alloy', 'ash', 'ballad', 'echo', 'fable', 'onyx', 'nova', 'shimmer', 'coral', 'sage', 'verse', 'marin', 'cedar'];
    if (!in_array($voice, $allowedVoices, true)) {
        $voice = 'alloy';
    }
    if (!in_array($model, ['tts-1', 'tts-1-hd', 'gpt-4o-mini-tts', 'gpt-4o-mini-tts-2025-12-15'], true)) {
        $model = 'tts-1';
    }

    $speed = 1.0;
    if (isset($overrides['openai_speed']) && $overrides['openai_speed'] !== '') {
        $speed = (float) $overrides['openai_speed'];
        $speed = max(0.25, min(4.0, $speed));
    }

    $instructions = isset($overrides['openai_instructions']) ? trim((string) $overrides['openai_instructions']) : '';
    $isGpt4oMini = in_array($model, ['gpt-4o-mini-tts', 'gpt-4o-mini-tts-2025-12-15'], true);

    $audioDir = function_storage_audio_dir();
    if (!is_dir($audioDir)) {
        @mkdir($audioDir, 0755, true);
    }
    $filename = 'tts_' . time() . '_' . substr(md5($text), 0, 8) . '.mp3';
    $outPath = $audioDir . $filename;

    $payload = [
        'model'  => $model,
        'input'  => $text,
        'voice'  => $voice,
        'speed'  => $speed,
        'response_format' => 'mp3',
    ];
    if ($isGpt4oMini && $instructions !== '') {
        $payload['instructions'] = $instructions;
    }
    $body = json_encode($payload);

    $ctx = stream_context_create([
        'http' => [
            'method'  => 'POST',
            'header'  => "Content-Type: application/json\r\nAuthorization: Bearer " . $apiKey . "\r\n",
            'content' => $body,
            'timeout' => 60,
        ],
    ]);

    $response = @file_get_contents('https://api.openai.com/v1/audio/speech', false, $ctx);
    if ($response === false) {
        return ['ok' => false, 'error' => 'OpenAI API-Anfrage fehlgeschlagen.'];
    }

    $status = isset($http_response_header[0]) ? $http_response_header[0] : '';
    if (strpos($status, '200') === false) {
        $err = json_decode($response, true);
        $msg = isset($err['error']['message']) ? $err['error']['message'] : $status;
        return ['ok' => false, 'error' => 'OpenAI: ' . $msg];
    }

    if (file_put_contents($outPath, $response) === false) {
        return ['ok' => false, 'error' => 'Audio-Datei konnte nicht gespeichert werden.'];
    }

    return ['ok' => true, 'url' => function_storage_audio_url($filename), 'file' => $filename];
}
