<?php
if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * Cached greeting audio manager for the consultation wizard.
 */

if (!defined('ABSPATH')) {
    exit;
}

class VMO_Greeting_Audio_Manager {
    private const CACHE_OPTION = 'vmo_consultation_greeting_audio_cache';
    private const CACHE_TTL = WEEK_IN_SECONDS; // Keep asset warm for one week
    private const STORAGE_FOLDER = 'vmo-greetings';

    /** @var VMO_Greeting_Audio_Manager|null */
    private static $instance = null;

    public static function get_instance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        add_action('rest_api_init', [$this, 'register_routes']);
    }

    public function register_routes(): void {
        register_rest_route('vmo/v1', '/greeting-audio', [
            'methods'  => 'GET',
            'permission_callback' => [$this, 'can_request_audio'],
            'callback' => [$this, 'rest_get_greeting_audio'],
            'args' => [
                'refresh' => [
                    'required' => false,
                    'type' => 'boolean'
                ],
                'voice' => [
                    'required' => false,
                    'type' => 'string'
                ],
            ],
        ]);
    }

    public function can_request_audio(): bool {
        return is_user_logged_in();
    }

    public function rest_get_greeting_audio(WP_REST_Request $request) {
        $force = (bool) $request->get_param('refresh');
        $voice = sanitize_text_field($request->get_param('voice') ?: $this->get_default_voice());
        $meta = $this->ensure_audio_asset($voice, $force);
        if (is_wp_error($meta)) {
            return $meta;
        }

        $meta['text'] = $this->get_greeting_text();
        $meta['rest_endpoint'] = esc_url_raw(rest_url('vmo/v1/greeting-audio'));

        return rest_ensure_response($meta);
    }

    public function get_audio_metadata(bool $generate_if_missing = false) {
        $meta = get_option(self::CACHE_OPTION, []);
        $text = $this->get_greeting_text();
        $voice = $this->get_default_voice();
        $expected_hash = $this->build_audio_hash($text, $voice);

        if ($this->is_meta_valid($meta, $expected_hash)) {
            return $this->normalize_meta($meta);
        }

        if ($generate_if_missing) {
            return $this->ensure_audio_asset($voice, true);
        }

        return [];
    }

    public function warm_cache(bool $force = false) {
        return $this->ensure_audio_asset($this->get_default_voice(), $force);
    }

    private function ensure_audio_asset(string $voice, bool $force_regen = false) {
        $text = $this->get_greeting_text();
        if (!$text) {
            return new WP_Error('vmo_missing_greeting_text', 'Greeting text is not available.');
        }

        $hash = $this->build_audio_hash($text, $voice);
        $meta = get_option(self::CACHE_OPTION, []);

        // If we have a valid cached version, return it (no token cost for cached)
        if (!$force_regen && $this->is_meta_valid($meta, $hash)) {
            return $this->normalize_meta($meta);
        }

        // ✅ TOKEN ENFORCEMENT: Check and deduct tokens before generating new audio
        // This costs API money, so user must have subscription credit
        $user_id = get_current_user_id();
        $token_cost = defined('VMO_TOKENS_GREETING_AUDIO') ? VMO_TOKENS_GREETING_AUDIO : 250;
        
        if ($user_id && function_exists('vmo_token_manager')) {
            $manager = vmo_token_manager();
            if ($manager && method_exists($manager, 'has_tokens') && method_exists($manager, 'deduct_tokens')) {
                if (!$manager->has_tokens($user_id, $token_cost)) {
                    return new WP_Error('insufficient_tokens', 
                        'Your available VMO Credit has been used up. Please add a booster or upgrade to a higher-credit plan to continue.',
                        ['status' => 'insufficient_tokens', 'required' => $token_cost]
                    );
                }
                // Deduct tokens for TTS generation
                $manager->deduct_tokens($user_id, $token_cost, 'Consultation greeting audio generation');
            }
        }

        $paths = $this->get_storage_paths($hash);
        if (is_wp_error($paths)) {
            return $paths;
        }

        $generation = $this->generate_audio_file($text, $voice, $paths['path']);
        if (is_wp_error($generation)) {
            return $generation;
        }

        $meta = [
            'hash' => $hash,
            'voice' => $voice,
            'path' => $paths['path'],
            'url' => $paths['url'],
            'generated_at' => time(),
            'filesize' => @filesize($paths['path']) ?: 0,
        ];

        update_option(self::CACHE_OPTION, $meta, false);
        $this->cleanup_stale_assets($hash, dirname($paths['path']));

        return $this->normalize_meta($meta);
    }

    private function get_storage_paths(string $hash) {
        $uploads = wp_upload_dir(null, true);
        if (!empty($uploads['error'])) {
            return new WP_Error('vmo_greeting_upload_error', 'Unable to access uploads directory: ' . $uploads['error']);
        }

        $dir = trailingslashit($uploads['basedir']) . self::STORAGE_FOLDER;
        if (!wp_mkdir_p($dir)) {
            return new WP_Error('vmo_greeting_dir_error', 'Unable to prepare greeting audio directory.');
        }

        $filename = sprintf('consultation-greeting-%s.mp3', $hash);
        $path = trailingslashit($dir) . $filename;
        $url = trailingslashit($uploads['baseurl']) . self::STORAGE_FOLDER . '/' . $filename;

        return [
            'dir' => $dir,
            'path' => $path,
            'url' => $url,
        ];
    }

    private function is_meta_valid($meta, ?string $expected_hash = null): bool {
        if (!is_array($meta) || empty($meta['hash']) || empty($meta['generated_at'])) {
            return false;
        }

        if ($expected_hash && $expected_hash !== $meta['hash']) {
            return false;
        }

        if ((time() - (int) $meta['generated_at']) > self::CACHE_TTL) {
            return false;
        }

        $paths = $this->get_storage_paths($meta['hash']);
        if (is_wp_error($paths)) {
            return false;
        }

        if (!file_exists($paths['path'])) {
            return false;
        }

        if (@filesize($paths['path']) < 1024) {
            return false;
        }

        return true;
    }

    private function normalize_meta(array $meta): array {
        $paths = $this->get_storage_paths($meta['hash']);
        if (!is_wp_error($paths)) {
            $meta['path'] = $paths['path'];
            $meta['url'] = $paths['url'];
        }

        $generated = (int) ($meta['generated_at'] ?? time());
        $meta['expires_at'] = $generated + self::CACHE_TTL;
        $meta['cache_ttl'] = self::CACHE_TTL;

        return $meta;
    }

    private function get_default_voice(): string {
        return apply_filters('vmo_consultation_greeting_voice', 'ash');
    }

    private function get_greeting_text(): string {
        if (function_exists('vmo_get_consultation_greeting_text')) {
            return trim((string) vmo_get_consultation_greeting_text());
        }
        return '';
    }

    private function build_audio_hash(string $text, string $voice): string {
        return md5($text . '|' . $voice . '|mp3');
    }

    private function generate_audio_file(string $text, string $voice, string $path) {
        $api_key = get_option('vmo_openai_api_key');
        if (!$api_key) {
            return new WP_Error('vmo_missing_openai_key', 'AI API key is not configured.');
        }

        $audio_text = apply_filters('vmo_consultation_greeting_audio_text', $text, $voice);
        if (!is_string($audio_text) || trim($audio_text) === '') {
            $audio_text = $text;
        }

        $payload = [
            'model' => 'tts-1-hd',
            'input' => $audio_text,
            'voice' => $voice,
            'response_format' => 'mp3',
            'speed' => 1.0,
        ];

        // ✅ TOKEN DEDUCTION v8.1.0: Charge for TTS greeting audio
        $user_id = get_current_user_id();
        if (function_exists('vmo_deduct_tokens')) {
            $token_cost = function_exists('vmo_get_token_cost') ? (int) vmo_get_token_cost('greeting_audio') : 120;
            if (!vmo_deduct_tokens($user_id, $token_cost, 'greeting_audio', 'Greeting audio generation')) {
                return new WP_Error('vmo_insufficient_tokens', 'Insufficient tokens for greeting audio');
            }
        }

        $response = wp_remote_post('https://api.openai.com/v1/audio/speech', [
            'headers' => [
                'Authorization' => 'Bearer ' . $api_key,
                'Content-Type'  => 'application/json',
            ],
            'body'    => wp_json_encode($payload),
            'timeout' => 60,
        ]);

        if (is_wp_error($response)) {
            error_log('VMO Greeting Audio: ' . $response->get_error_message());
            return $response;
        }

        $code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);

        if ($code < 200 || $code >= 300 || empty($body)) {
            $error_data = json_decode($body ?? '', true);
            $message = $error_data['error']['message'] ?? 'Unknown TTS error';
            error_log('VMO Greeting Audio OpenAI Error: ' . $message);
            return new WP_Error('vmo_openai_greeting_error', $message, ['status' => $code, 'body' => $error_data]);
        }

        $dir = dirname($path);
        if (!wp_mkdir_p($dir)) {
            return new WP_Error('vmo_greeting_dir_error', 'Unable to create greeting audio directory.');
        }

        $bytes = vmo_get_filesystem()->put_contents($path, $body, FS_CHMOD_FILE);
        if ($bytes === false) {
            return new WP_Error('vmo_greeting_write_failed', 'Unable to write greeting audio file.');
        }

        @chmod($path, 0644);

        return true;
    }

    private function cleanup_stale_assets(string $keep_hash, string $dir): void {
        if (!is_dir($dir)) {
            return;
        }

        $pattern = trailingslashit($dir) . 'consultation-greeting-*.mp3';
        $files = glob($pattern);
        if (empty($files)) {
            return;
        }
        foreach ($files as $file) {
            if (strpos($file, $keep_hash) !== false) {
                continue;
            }
            $age_ok = (time() - @filemtime($file)) > self::CACHE_TTL;
            if ($age_ok) {
                @unlink($file);
            }
        }
    }
}
