<?php
/**
 * Weglot per-language audio column for the post-list screen.
 *
 * Hooks `mementor_tts_render_column` to replace the single-language column
 * with one row per Weglot language (original + destinations). Each row
 * exposes Play / Regenerate / Delete or Generate controls.
 *
 * Audio generation is routed through the SaaS-proxied processor so per-site
 * credits are billed correctly. The processor handles Weglot translation,
 * filename construction, S3 offload, and language-specific post meta.
 *
 * @package    TTSWP
 * @subpackage Mementor_TTS/admin
 */

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

class Mementor_TTS_Weglot_Columns {

    /**
     * Register filter + AJAX actions.
     */
    public function register_hooks() {
        add_filter('mementor_tts_render_column', array($this, 'render_multi_language_column'), 10, 6);
        add_action('wp_ajax_mementor_tts_generate_language_audio', array($this, 'ajax_generate_language_audio'));
        add_action('wp_ajax_mementor_tts_delete_language_audio',   array($this, 'ajax_delete_language_audio'));
    }

    /**
     * Whether the Weglot per-language column should replace the default column.
     */
    private function is_active() {
        return function_exists('weglot_get_current_language')
            && get_option('mementor_tts_weglot_enabled', '0') === '1'
            && function_exists('ttswp_has_paid_plan')
            && ttswp_has_paid_plan();
    }

    /**
     * Build the list of Weglot languages (original + destinations).
     *
     * @return string[] Unique language codes in display order.
     */
    private function get_weglot_languages() {
        $all = array();

        if (function_exists('weglot_get_original_language')) {
            $original = weglot_get_original_language();
            if (is_object($original) && method_exists($original, 'getInternalCode')) {
                $original = $original->getInternalCode();
            } elseif (is_object($original)) {
                $original = (string) $original;
            }
            if (!empty($original)) {
                $all[] = $original;
            }
        }

        if (function_exists('weglot_get_destination_languages')) {
            $dest = weglot_get_destination_languages();
            if (is_array($dest)) {
                foreach ($dest as $lang) {
                    if (is_array($lang) && isset($lang['language_to'])) {
                        $all[] = $lang['language_to'];
                    } elseif (is_object($lang) && method_exists($lang, 'getInternalCode')) {
                        $all[] = $lang->getInternalCode();
                    } elseif (is_object($lang)) {
                        $all[] = (string) $lang;
                    } elseif (is_string($lang)) {
                        $all[] = $lang;
                    }
                }
            }
        }

        return array_values(array_unique(array_filter($all)));
    }

    /**
     * Short uppercase label shown in the column (nb/nn display as "NO").
     */
    private function language_label($code) {
        static $names = array(
            'en' => 'EN', 'no' => 'NO', 'nb' => 'NO', 'nn' => 'NO',
            'sv' => 'SV', 'da' => 'DA', 'fi' => 'FI',
            'de' => 'DE', 'fr' => 'FR', 'es' => 'ES', 'it' => 'IT',
            'pt' => 'PT', 'nl' => 'NL', 'pl' => 'PL', 'ru' => 'RU',
            'ja' => 'JA', 'zh' => 'ZH', 'ko' => 'KO',
        );
        return isset($names[$code]) ? $names[$code] : strtoupper($code);
    }

    /**
     * Map Weglot's locale code (nb/nn) to the storage code actually used on
     * disk and in post meta ("no"). Keeps a single Norwegian audio file.
     */
    private function to_file_lang($code) {
        static $map = array('nb' => 'no', 'nn' => 'no');
        return isset($map[$code]) ? $map[$code] : $code;
    }

    /**
     * Filter callback: render per-language rows in the TTS column.
     *
     * @return bool True when this filter handled rendering; false to let the
     *              default single-language column render instead.
     */
    public function render_multi_language_column($rendered, $post_id, $audio_exists, $audio_url, $processing, $post_status) {
        if ($rendered) {
            return $rendered;
        }

        if (!$this->is_active()) {
            return false;
        }

        $languages = $this->get_weglot_languages();
        if (empty($languages)) {
            return false;
        }

        $upload_dir   = wp_upload_dir();
        $can_generate = in_array($post_status, array('publish', 'future', 'draft', 'pending', 'private'), true);

        echo '<div class="mementor-tts-ml-container">';

        foreach ($languages as $lang_code) {
            $file_lang = $this->to_file_lang($lang_code);
            $label     = $this->language_label($lang_code);

            // Resolve audio URL from post meta (try Weglot code first, then file code).
            $lang_audio_url = get_post_meta($post_id, '_mementor_tts_audio_url_' . $lang_code, true);
            if (empty($lang_audio_url) && $file_lang !== $lang_code) {
                $lang_audio_url = get_post_meta($post_id, '_mementor_tts_audio_url_' . $file_lang, true);
            }

            // Legacy filesystem fallback: `mementor-{id}-{lang}.mp3`.
            if (empty($lang_audio_url)) {
                $legacy_file = $upload_dir['basedir'] . '/text-to-speech-tts/mementor-' . $post_id . '-' . $file_lang . '.mp3';
                if (file_exists($legacy_file)) {
                    $lang_audio_url = $upload_dir['baseurl'] . '/text-to-speech-tts/mementor-' . $post_id . '-' . $file_lang . '.mp3';
                }
            }

            $lang_audio_exists = !empty($lang_audio_url);

            echo '<div class="mementor-tts-column-controls mementor-tts-ml-row" data-lang="' . esc_attr($lang_code) . '" data-file-lang="' . esc_attr($file_lang) . '">';
            echo '<span class="mementor-tts-ml-lang">' . esc_html($label) . '</span>';

            if ($lang_audio_exists) {
                // Route downloads through the AJAX proxy so Content-Disposition
                // is respected (including CDN-hosted files), and pass the
                // language so the per-language file is resolved.
                $download_url = add_query_arg(
                    array(
                        'action'   => 'mementor_tts_download_audio',
                        'post_id'  => $post_id,
                        'language' => $file_lang,
                        'nonce'    => wp_create_nonce('mementor_tts_nonce'),
                    ),
                    admin_url('admin-ajax.php')
                );
                $download_filename = 'tts-' . $post_id . '-' . $file_lang . '.mp3';

                // Use data-audio-url so the shared inline-playback handler in
                // mementor-tts-admin-columns.js picks it up, matching the
                // single-language column's behaviour.
                echo '<a href="#" class="mementor-tts-play-button" data-audio-url="' . esc_url($lang_audio_url) . '" title="' . esc_attr__('Play audio', 'text-to-speech-tts') . '">';
                echo '<img src="' . esc_url(MEMENTOR_TTS_PLUGIN_URL . 'admin/images/icons/list-play2.svg') . '" alt="" class="mementor-tts-play-icon" />';
                echo '</a>';
                echo '<a href="' . esc_url($download_url) . '" class="mementor-tts-download-button" download="' . esc_attr($download_filename) . '" title="' . esc_attr__('Download audio', 'text-to-speech-tts') . '">';
                echo '<img src="' . esc_url(MEMENTOR_TTS_PLUGIN_URL . 'admin/images/icons/list-download.svg') . '" alt="" />';
                echo '</a>';
                echo '<a href="#" class="mementor-tts-ml-generate-btn mementor-tts-regenerate" data-post-id="' . esc_attr($post_id) . '" data-lang="' . esc_attr($lang_code) . '" data-file-lang="' . esc_attr($file_lang) . '" title="' . esc_attr__('Regenerate audio', 'text-to-speech-tts') . '">';
                echo '<img src="' . esc_url(MEMENTOR_TTS_PLUGIN_URL . 'admin/images/icons/list-redo.svg') . '" alt="" />';
                echo '</a>';
                echo '<a href="#" class="mementor-tts-ml-delete-btn" data-post-id="' . esc_attr($post_id) . '" data-lang="' . esc_attr($lang_code) . '" data-file-lang="' . esc_attr($file_lang) . '" title="' . esc_attr__('Delete audio', 'text-to-speech-tts') . '">';
                echo '<img src="' . esc_url(MEMENTOR_TTS_PLUGIN_URL . 'admin/images/icons/list-delete.svg') . '" alt="" />';
                echo '</a>';
            } elseif ($can_generate) {
                echo '<a href="#" class="mementor-tts-ml-generate-btn mementor-tts-ml-create" data-post-id="' . esc_attr($post_id) . '" data-lang="' . esc_attr($lang_code) . '" data-file-lang="' . esc_attr($file_lang) . '" title="' . esc_attr__('Generate audio', 'text-to-speech-tts') . '">';
                echo '<img src="' . esc_url(MEMENTOR_TTS_PLUGIN_URL . 'admin/images/icons/list-create.svg') . '" alt="" class="mementor-tts-create-icon" />';
                echo '</a>';
                echo '<span class="mementor-tts-ml-slot"></span>';
                echo '<span class="mementor-tts-ml-slot"></span>';
                echo '<span class="mementor-tts-ml-slot"></span>';
            } else {
                echo '<span class="mementor-tts-ml-slot"></span>';
                echo '<span class="mementor-tts-ml-slot"></span>';
                echo '<span class="mementor-tts-ml-slot"></span>';
                echo '<span class="mementor-tts-ml-slot"></span>';
            }

            echo '</div>';
        }

        echo '</div>';

        return true;
    }

    /**
     * AJAX: generate audio for a specific language.
     *
     * Routes through Mementor_TTS_Processor so the SaaS proxy, Weglot
     * translation, S3 offload, and credit logging all apply.
     */
    public function ajax_generate_language_audio() {
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_key(wp_unslash($_POST['nonce'])), 'mementor_tts_ml_audio')) {
            wp_send_json_error(array('message' => __('Security check failed.', 'text-to-speech-tts')));
        }
        if (!current_user_can('edit_posts')) {
            wp_send_json_error(array('message' => __('You do not have permission to perform this action.', 'text-to-speech-tts')));
        }

        $post_id  = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
        $language = isset($_POST['language']) ? sanitize_key(wp_unslash($_POST['language'])) : '';

        if (!$post_id || !$language) {
            wp_send_json_error(array('message' => __('Invalid parameters.', 'text-to-speech-tts')));
        }

        $post = get_post($post_id);
        if (!$post) {
            wp_send_json_error(array('message' => __('Post not found.', 'text-to-speech-tts')));
        }

        $file_lang = $this->to_file_lang($language);

        // Assemble the source content in the ORIGINAL language; the processor
        // translates to the target language when Weglot is active.
        $content = $this->assemble_post_content($post);
        if (trim($content) === '') {
            wp_send_json_error(array('message' => __('Post has no content to synthesize.', 'text-to-speech-tts')));
        }

        // Resolve the voice: per-language mapping first, then site default.
        $voice_id = '';
        if (class_exists('Mementor_TTS_I18n_Helper')) {
            $voice_id = Mementor_TTS_I18n_Helper::get_voice_for_language($file_lang);
        }
        if (empty($voice_id)) {
            $voice_id = get_option('mementor_tts_voice', '');
        }

        require_once plugin_dir_path(__DIR__) . 'includes/class-mementor-tts-processor.php';
        require_once plugin_dir_path(__DIR__) . 'includes/class-mementor-tts-speech-builder.php';

        $processor = Mementor_TTS_Processor::get_instance();
        $result    = $processor->generate_audio(
            $content,
            $post_id,
            $voice_id,
            array('target_language' => $file_lang)
        );

        if ($result === false) {
            wp_send_json_error(array('message' => __('Failed to generate audio. Please check your settings and try again.', 'text-to-speech-tts')));
        }
        if (is_array($result) && isset($result['success']) && $result['success'] === false) {
            $msg = isset($result['message'])
                ? $result['message']
                : (isset($result['error']) ? $result['error'] : __('Failed to generate audio.', 'text-to-speech-tts'));
            wp_send_json_error(array(
                'message'      => $msg,
                'error'        => isset($result['error']) ? $result['error'] : null,
                'error_type'   => isset($result['error_type']) ? $result['error_type'] : null,
                'credits_info' => isset($result['credits_info']) ? $result['credits_info'] : null,
            ));
        }
        if (!is_string($result)) {
            wp_send_json_error(array('message' => __('Unexpected response from audio generation.', 'text-to-speech-tts')));
        }

        // Log credit usage (mirrors the single-language handler in class-mementor-tts-ajax.php).
        if (class_exists('Mementor_TTS_Speech_Builder')) {
            $character_cost = get_transient('mementor_tts_char_cost_' . $post_id);
            if ($character_cost !== false && intval($character_cost) > 0) {
                $credits_used = intval($character_cost);
                delete_transient('mementor_tts_char_cost_' . $post_id);
            } else {
                $credits_used = strlen($content);
            }

            $api_type = 'shared';
            if (function_exists('ttswp_has_paid_plan') && ttswp_has_paid_plan()) {
                $api_type = 'saas';
            } elseif (get_option('mementor_tts_api_key')) {
                $api_type = 'user';
            }

            Mementor_TTS_Speech_Builder::get_instance()->log_generation($post_id, $credits_used, array(
                'text_length' => strlen($content),
                'voice_id'    => $voice_id,
                'model_id'    => get_option('mementor_tts_model', 'eleven_flash_v2_5'),
                'api_type'    => $api_type,
                'file_size'   => 0,
            ));
        }

        wp_send_json_success(array(
            'message'   => __('Audio generated successfully.', 'text-to-speech-tts'),
            'audio_url' => $result,
        ));
    }

    /**
     * AJAX: delete audio for a specific language.
     */
    public function ajax_delete_language_audio() {
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_key(wp_unslash($_POST['nonce'])), 'mementor_tts_ml_audio')) {
            wp_send_json_error(array('message' => __('Security check failed.', 'text-to-speech-tts')));
        }
        if (!current_user_can('edit_posts')) {
            wp_send_json_error(array('message' => __('You do not have permission to perform this action.', 'text-to-speech-tts')));
        }

        $post_id  = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
        $language = isset($_POST['language']) ? sanitize_key(wp_unslash($_POST['language'])) : '';

        if (!$post_id || !$language) {
            wp_send_json_error(array('message' => __('Invalid parameters.', 'text-to-speech-tts')));
        }

        $upload_dir = wp_upload_dir();

        // Delete via the stored meta URL first (covers modern `{slug}-{id}-{lang}.mp3`).
        $audio_url = get_post_meta($post_id, '_mementor_tts_audio_url_' . $language, true);
        if (!empty($audio_url)) {
            // Ask the SaaS to delete S3 + invalidate CloudFront for SaaS-hosted URLs.
            if (function_exists('ttswp_is_saas_cdn_url') && ttswp_is_saas_cdn_url($audio_url)) {
                if (!class_exists('Mementor_TTS_Api_Client')) {
                    require_once plugin_dir_path(__DIR__) . 'includes/class-mementor-tts-api-client.php';
                }
                Mementor_TTS_Api_Client::get_instance()->delete_audio($audio_url);
            } else {
                $local_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $audio_url);
                if (file_exists($local_path)) {
                    wp_delete_file($local_path);
                }
            }
        }

        // Also remove the legacy `mementor-{id}-{lang}.mp3` file if present.
        $legacy_path = $upload_dir['basedir'] . '/text-to-speech-tts/mementor-' . $post_id . '-' . $language . '.mp3';
        if (file_exists($legacy_path)) {
            wp_delete_file($legacy_path);
        }

        delete_post_meta($post_id, '_mementor_tts_audio_url_' . $language);

        // Clear the generic has-audio flag when no per-post audio files remain on disk.
        $pattern   = $upload_dir['basedir'] . '/text-to-speech-tts/*-' . $post_id . '-*.mp3';
        $remaining = glob($pattern);
        if (empty($remaining)) {
            delete_post_meta($post_id, '_mementor_tts_has_audio');
        }

        wp_send_json_success(array('message' => __('Audio deleted successfully.', 'text-to-speech-tts')));
    }

    /**
     * Extract post text for synthesis, preserving Elementor content when the
     * post_content stores raw Elementor JSON.
     */
    private function assemble_post_content(WP_Post $post) {
        $include_title = (bool) get_option('mementor_tts_include_title', 1);
        $raw           = $post->post_content;

        if (strpos($raw, '"elType"') !== false) {
            $elementor_json = get_post_meta($post->ID, '_elementor_data', true);
            if (!empty($elementor_json)) {
                $elementor_data = json_decode($elementor_json, true);
                if (is_array($elementor_data)) {
                    $extracted = $this->extract_text_from_elementor_data($elementor_data);
                    if (trim($extracted) !== '') {
                        $body = $extracted;
                    }
                }
            }
        }

        if (!isset($body)) {
            // Apply Truncate After on HTML first so needles like
            // `<strong>Footnotes</strong>` can still match, then strip tags.
            // Use the shared helper so page builders (Fusion Builder, Avada,
            // etc.) emit the full post body, not just the teaser.
            if (function_exists('ttswp_render_content_full')) {
                $rendered = ttswp_render_content_full($raw, $post->ID);
            } else {
                $rendered = apply_filters('the_content', $raw);
            }
            if (function_exists('ttswp_apply_truncate_after')) {
                $rendered = ttswp_apply_truncate_after($rendered);
            }
            if (function_exists('ttswp_inject_speech_breaks')) {
                $rendered = ttswp_inject_speech_breaks($rendered);
            }
            $body = wp_strip_all_tags($rendered);
        } else {
            // Elementor extraction already gave HTML — truncate on that.
            if (function_exists('ttswp_apply_truncate_after')) {
                $body = ttswp_apply_truncate_after($body);
            }
            if (function_exists('ttswp_inject_speech_breaks')) {
                $body = ttswp_inject_speech_breaks($body);
            }
        }

        return ($include_title ? $post->post_title . ' -- ' : '') . $body;
    }

    /**
     * Recursively extract text content from an Elementor data structure.
     */
    private function extract_text_from_elementor_data($elements) {
        $parts = array();

        foreach ($elements as $el) {
            if (isset($el['settings']) && is_array($el['settings'])) {
                foreach (array('editor', 'title') as $key) {
                    if (!empty($el['settings'][$key])) {
                        $clean = trim(wp_strip_all_tags($el['settings'][$key]));
                        if ($clean !== '') {
                            $parts[] = $clean;
                        }
                    }
                }
            }
            if (!empty($el['elements']) && is_array($el['elements'])) {
                $child = $this->extract_text_from_elementor_data($el['elements']);
                if ($child !== '') {
                    $parts[] = $child;
                }
            }
        }

        return implode("\n\n", $parts);
    }
}
