<?php

declare(strict_types=1);

namespace App\Services;

use App\Core\Logger;
use App\Models\IntegrationModel;

/**
 * ElevenLabsClient
 *
 * Text-to-speech for the Voice Agent's spoken responses when a more
 * natural voice than Twilio's built-in Polly voices is wanted. Same
 * graceful-failure pattern as every other external client in this
 * phase — VoiceAgentService falls back to Twilio's <Say> (Polly) if
 * ElevenLabs isn't configured or a request fails, so a missing/expired
 * API key never breaks call handling, just makes it sound less natural.
 */
final class ElevenLabsClient
{
    private const API_BASE = 'https://api.elevenlabs.io/v1';
    private const DEFAULT_VOICE_ID = '21m00Tcm4TlvDq8ikWAM'; // ElevenLabs' public default voice, "Rachel"

    public function __construct(private readonly IntegrationModel $integrations = new IntegrationModel())
    {
    }

    public function isConfigured(): bool
    {
        $creds = $this->integrations->credentialsFor('elevenlabs');

        return $creds !== null && !empty($creds['api_key']);
    }

    /** @return array{success:bool, audio_binary?:string, error?:string} MP3 bytes on success. */
    public function textToSpeech(string $text, ?string $voiceId = null): array
    {
        $creds = $this->integrations->credentialsFor('elevenlabs');
        if ($creds === null || empty($creds['api_key'])) {
            return ['success' => false, 'error' => 'ElevenLabs is not connected. Configure it from Admin > Integrations.'];
        }

        if (!function_exists('curl_init')) {
            return ['success' => false, 'error' => 'Server is missing the PHP curl extension.'];
        }

        $voice = $voiceId ?? $creds['voice_id'] ?? self::DEFAULT_VOICE_ID;

        $ch = curl_init(self::API_BASE . "/text-to-speech/{$voice}");
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode([
                'text' => $text,
                'model_id' => 'eleven_turbo_v2',
                'voice_settings' => ['stability' => 0.5, 'similarity_boost' => 0.75],
            ]),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'xi-api-key: ' . $creds['api_key'],
                'Accept: audio/mpeg',
            ],
            CURLOPT_TIMEOUT => 30,
        ]);

        $body = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($body === false || $error !== '') {
            Logger::error('ElevenLabsClient: request failed', ['error' => $error]);

            return ['success' => false, 'error' => "Could not reach ElevenLabs: {$error}"];
        }

        if ($status !== 200) {
            $decoded = json_decode((string) $body, true);
            $apiError = $decoded['detail']['message'] ?? "HTTP {$status}";
            Logger::error('ElevenLabsClient: API error', ['status' => $status, 'error' => $apiError]);

            return ['success' => false, 'error' => $apiError];
        }

        return ['success' => true, 'audio_binary' => $body];
    }
}
