<?php
/*
Plugin Name: CodeWP Eleven Labs Text-to-Speech Integration
Description: Integrate Eleven Labs Text-to-Speech into your WordPress site.
Version: 1.4
Author: Your Name
License: GPL2
*/

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

class CWP_ElevenLabs_TTS_Plugin {

    private $option_name = 'cwp_elevenlabs_tts_options';

    public function __construct() {
        // Add settings menu
        add_action( 'admin_menu', array( $this, 'cwp_add_settings_page' ) );
        // Register settings
        add_action( 'admin_init', array( $this, 'cwp_register_settings' ) );
        // Add meta box to post editor
        add_action( 'add_meta_boxes', array( $this, 'cwp_add_voice_meta_box' ) );
        // Enqueue scripts
        add_action( 'admin_enqueue_scripts', array( $this, 'cwp_enqueue_admin_scripts' ) );
        // Save post meta
        add_action( 'save_post', array( $this, 'cwp_save_post_meta' ) );
        // AJAX handler
        add_action( 'wp_ajax_cwp_generate_audio', array( $this, 'cwp_ajax_generate_audio' ) );
        // Inject audio into content
        add_filter( 'the_content', array( $this, 'cwp_append_audio_to_content' ) );
        // Add custom column to admin post list
        add_filter( 'manage_post_posts_columns', array( $this, 'cwp_add_audio_column' ) );
        add_action( 'manage_post_posts_custom_column', array( $this, 'cwp_render_audio_column' ), 10, 2 );
    }

    // Add settings page
    public function cwp_add_settings_page() {
        add_options_page(
            'CodeWP Eleven Labs TTS Settings',
            'CodeWP Eleven Labs TTS',
            'manage_options',
            'cwp-elevenlabs-tts-settings',
            array( $this, 'cwp_render_settings_page' )
        );
    }

    // Register settings
    public function cwp_register_settings() {
        register_setting( 'cwp_elevenlabs_tts_settings', $this->option_name, array( $this, 'cwp_sanitize_settings' ) );

        add_settings_section(
            'cwp_elevenlabs_tts_main_section',
            'Main Settings',
            null,
            'cwp-elevenlabs-tts-settings'
        );

        add_settings_field(
            'api_key',
            'API Key',
            array( $this, 'cwp_render_api_key_field' ),
            'cwp-elevenlabs-tts-settings',
            'cwp_elevenlabs_tts_main_section'
        );

        add_settings_field(
            'default_voice',
            'Default Voice',
            array( $this, 'cwp_render_default_voice_field' ),
            'cwp-elevenlabs-tts-settings',
            'cwp_elevenlabs_tts_main_section'
        );

        add_settings_field(
            'display_model_name',
            'Display Model Name',
            array( $this, 'cwp_render_display_model_name_field' ),
            'cwp-elevenlabs-tts-settings',
            'cwp_elevenlabs_tts_main_section'
        );

        add_settings_field(
            'elevenlabs_link',
            'Eleven Labs Platform',
            array( $this, 'cwp_render_elevenlabs_link_field' ),
            'cwp-elevenlabs-tts-settings',
            'cwp_elevenlabs_tts_main_section'
        );
    }

    // Sanitize settings
    public function cwp_sanitize_settings( $input ) {
        $output = array();
        if ( isset( $input['api_key'] ) ) {
            $output['api_key'] = sanitize_text_field( $input['api_key'] );
        }
        if ( isset( $input['default_voice'] ) ) {
            $output['default_voice'] = sanitize_text_field( $input['default_voice'] );
        }
        if ( isset( $input['display_model_name'] ) ) {
            $output['display_model_name'] = sanitize_text_field( $input['display_model_name'] );
        } else {
            $output['display_model_name'] = '0';
        }
        return $output;
    }

    // Render settings page
    public function cwp_render_settings_page() {
        ?>
        <div class="wrap">
            <h1>CodeWP Eleven Labs Text-to-Speech Settings</h1>
            <form method="post" action="options.php">
                <?php
                settings_fields( 'cwp_elevenlabs_tts_settings' );
                do_settings_sections( 'cwp-elevenlabs-tts-settings' );
                submit_button();
                ?>
            </form>
        </div>
        <?php
    }

    // Render API Key field
    public function cwp_render_api_key_field() {
        $options = get_option( $this->option_name );
        ?>
        <input type="text" name="<?php echo esc_attr( $this->option_name ); ?>[api_key]" value="<?php echo isset( $options['api_key'] ) ? esc_attr( $options['api_key'] ) : ''; ?>" size="50" />
        <?php
    }

    // Render Default Voice field
    public function cwp_render_default_voice_field() {
        $options = get_option( $this->option_name );
        $api_key = isset( $options['api_key'] ) ? $options['api_key'] : '';

        if ( ! empty( $api_key ) ) {
            $voices = $this->cwp_get_voices( $api_key );
            if ( ! is_wp_error( $voices ) ) {
                $default_voice = isset( $options['default_voice'] ) ? $options['default_voice'] : '';
                ?>
                <select name="<?php echo esc_attr( $this->option_name ); ?>[default_voice]">
                    <?php foreach ( $voices as $voice ) : ?>
                        <option value="<?php echo esc_attr( $voice['voice_id'] ); ?>" <?php selected( $default_voice, $voice['voice_id'] ); ?>>
                            <?php echo esc_html( $voice['name'] ); ?>
                        </option>
                    <?php endforeach; ?>
                </select>
                <?php
            } else {
                echo '<p style="color:red;">Error fetching voices. Please check your API key.</p>';
            }
        } else {
            echo '<p>Please enter your API key and save to select a default voice.</p>';
        }
    }

    // Render Display Model Name field
    public function cwp_render_display_model_name_field() {
        $options = get_option( $this->option_name );
        $checked = isset( $options['display_model_name'] ) && $options['display_model_name'] === '1' ? 'checked' : '';
        ?>
        <label>
            <input type="checkbox" name="<?php echo esc_attr( $this->option_name ); ?>[display_model_name]" value="1" <?php echo esc_attr( $checked ); ?> />
            Display the model name with the audio player on posts.
        </label>
        <?php
    }

    // Render Eleven Labs link
    public function cwp_render_elevenlabs_link_field() {
        echo '<a href="https://elevenlabs.io/" target="_blank">Visit Eleven Labs Platform</a>';
    }

    // Get voices from API
    private function cwp_get_voices( $api_key ) {
        $response = wp_remote_get( 'https://api.elevenlabs.io/v1/voices', array(
            'headers' => array(
                'xi-api-key' => $api_key,
            ),
            'timeout' => 60,
        ) );

        if ( is_wp_error( $response ) ) {
            return $response;
        }

        $code = wp_remote_retrieve_response_code( $response );

        if ( $code != 200 ) {
            $body = wp_remote_retrieve_body( $response );
            $data = json_decode( $body, true );
            $error_message = isset( $data['detail'] ) ? $data['detail'] : 'Error fetching voices from API.';
            return new WP_Error( 'api_error', $error_message );
        }

        $body = wp_remote_retrieve_body( $response );
        $data = json_decode( $body, true );

        if ( ! isset( $data['voices'] ) ) {
            return new WP_Error( 'api_error', 'Invalid response from API' );
        }

        return $data['voices'];
    }

    // Add meta box to post editor
    public function cwp_add_voice_meta_box() {
        add_meta_box(
            'cwp_elevenlabs_tts_meta_box',
            'CodeWP Eleven Labs TTS',
            array( $this, 'cwp_render_voice_meta_box' ),
            'post',
            'side',
            'default'
        );
    }

    // Render meta box
    public function cwp_render_voice_meta_box( $post ) {
        wp_nonce_field( 'cwp_elevenlabs_tts_meta_box', 'cwp_elevenlabs_tts_meta_box_nonce' );

        $options = get_option( $this->option_name );
        $api_key = isset( $options['api_key'] ) ? $options['api_key'] : '';

        if ( empty( $api_key ) ) {
            echo '<p>Please set your API key in the plugin settings.</p>';
            return;
        }

        $voices = $this->cwp_get_voices( $api_key );
        if ( is_wp_error( $voices ) ) {
            echo '<p style="color:red;">' . esc_html( $voices->get_error_message() ) . '</p>';
            return;
        }

        $selected_voice = get_post_meta( $post->ID, '_cwp_elevenlabs_tts_voice_id', true );
        if ( empty( $selected_voice ) ) {
            $selected_voice = isset( $options['default_voice'] ) ? $options['default_voice'] : '';
        }

        $audio_url = get_post_meta( $post->ID, '_cwp_elevenlabs_tts_audio_url', true );
        $model_name = get_post_meta( $post->ID, '_cwp_elevenlabs_tts_model_name', true );

        ?>
        <p>
            <label for="cwp_elevenlabs_tts_voice_id">Select Voice:</label>
            <select name="cwp_elevenlabs_tts_voice_id" id="cwp_elevenlabs_tts_voice_id">
                <?php foreach ( $voices as $voice ) : ?>
                    <option value="<?php echo esc_attr( $voice['voice_id'] ); ?>" <?php selected( $selected_voice, $voice['voice_id'] ); ?>>
                        <?php echo esc_html( $voice['name'] ); ?>
                    </option>
                <?php endforeach; ?>
            </select>
        </p>
        <?php if ( $audio_url ) : ?>
            <p>
                <strong>Audio generated.</strong>
            </p>
            <p>
                <audio controls>
                    <source src="<?php echo esc_url( $audio_url ); ?>" type="audio/mpeg">
                    Your browser does not support the audio element.
                </audio>
            </p>
            <?php if ( $model_name ) : ?>
                <p><strong>Model Used:</strong> <?php echo esc_html( $model_name ); ?></p>
            <?php endif; ?>
            <p>
                <button type="button" class="button cwp-generate-audio-button" data-action="regenerate">Regenerate Audio</button>
            </p>
        <?php else : ?>
            <p>
                <button type="button" class="button cwp-generate-audio-button" data-action="generate">Generate Audio</button>
            </p>
        <?php endif; ?>
        <div class="cwp-audio-generation-status"></div>
        <?php
    }

    // Save post meta
    public function cwp_save_post_meta( $post_id ) {
        // Check if our nonce is set.
        if ( ! isset( $_POST['cwp_elevenlabs_tts_meta_box_nonce'] ) ) {
            return;
        }

        // Verify that the nonce is valid.
        if ( ! wp_verify_nonce( $_POST['cwp_elevenlabs_tts_meta_box_nonce'], 'cwp_elevenlabs_tts_meta_box' ) ) {
            return;
        }

        // If this is an autosave, our form has not been submitted, so we don't want to do anything.
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return;
        }

        // Check the user's permissions.
        if ( ! current_user_can( 'edit_post', $post_id ) ) {
            return;
        }

        if ( isset( $_POST['cwp_elevenlabs_tts_voice_id'] ) ) {
            $voice_id = sanitize_text_field( $_POST['cwp_elevenlabs_tts_voice_id'] );
            update_post_meta( $post_id, '_cwp_elevenlabs_tts_voice_id', $voice_id );
        }
    }

    // Enqueue admin scripts
    public function cwp_enqueue_admin_scripts( $hook ) {
        global $post;

        if ( 'post.php' != $hook && 'post-new.php' != $hook ) {
            return;
        }

        if ( 'post' != $post->post_type ) {
            return;
        }

        wp_enqueue_script( 'jquery' );

        wp_add_inline_script( 'jquery', '
        jQuery(document).ready(function($){
            $(".cwp-generate-audio-button").on("click", function(e){
                e.preventDefault();

                var button = $(this);
                var action = button.data("action");
                var post_id = ' . $post->ID . ';
                var voice_id = $("#cwp_elevenlabs_tts_voice_id").val();
                var status_div = $(".cwp-audio-generation-status");

                status_div.html("<p>Generating audio, please wait...</p>");

                $.ajax({
                    url: ajaxurl,
                    type: "POST",
                    data: {
                        action: "cwp_generate_audio",
                        nonce: "' . wp_create_nonce( 'cwp_generate_audio_nonce' ) . '",
                        post_id: post_id,
                        voice_id: voice_id,
                    },
                    success: function(response) {
                        if (response.success) {
                            status_div.html("<p>Audio generated successfully. Please save/update the post to refresh the meta box.</p>");
                        } else {
                            status_div.html("<p style=\'color:red;\'>" + response.data + "</p>");
                        }
                    },
                    error: function() {
                        status_div.html("<p style=\'color:red;\'>An error occurred while generating audio.</p>");
                    }
                });
            });
        });
        ' );
    }

    // AJAX handler for generating audio
    public function cwp_ajax_generate_audio() {
        // Check nonce
        check_ajax_referer( 'cwp_generate_audio_nonce', 'nonce' );

        // Check permissions
        if ( ! current_user_can( 'edit_posts' ) ) {
            wp_send_json_error( 'You are not allowed to perform this action.' );
        }

        $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
        $voice_id = isset( $_POST['voice_id'] ) ? sanitize_text_field( $_POST['voice_id'] ) : '';

        if ( ! $post_id || ! $voice_id ) {
            wp_send_json_error( 'Invalid post ID or voice ID.' );
        }

        $post = get_post( $post_id );
        if ( ! $post ) {
            wp_send_json_error( 'Post not found.' );
        }

        // Save the selected voice
        update_post_meta( $post_id, '_cwp_elevenlabs_tts_voice_id', $voice_id );

        $options = get_option( $this->option_name );
        $api_key = isset( $options['api_key'] ) ? $options['api_key'] : '';
        if ( empty( $api_key ) ) {
            wp_send_json_error( 'API key is not set.' );
        }

        $text = strip_tags( $post->post_content );

        // Limit text length to 10,000 characters
        $text = mb_substr( $text, 0, 10000 );

        $result = $this->cwp_generate_audio( $api_key, $voice_id, $text, $post_id );
        if ( $result && ! is_wp_error( $result ) ) {
            update_post_meta( $post_id, '_cwp_elevenlabs_tts_audio_url', $result['audio_url'] );
            update_post_meta( $post_id, '_cwp_elevenlabs_tts_model_name', $result['model_name'] );
            wp_send_json_success( 'Audio generated successfully.' );
        } else {
            $error_message = is_wp_error( $result ) ? $result->get_error_message() : 'Failed to generate audio.';
            wp_send_json_error( $error_message );
        }
    }

    // Generate audio using API
    private function cwp_generate_audio( $api_key, $voice_id, $text, $post_id ) {
        $url = 'https://api.elevenlabs.io/v1/text-to-speech/' . $voice_id;
        $args = array(
            'headers' => array(
                'xi-api-key'    => $api_key,
                'Accept'        => 'audio/mpeg',
                'Content-Type'  => 'application/json',
            ),
            'body'    => wp_json_encode( array(
                'text' => $text,
            ) ),
            'timeout' => 60,
        );

        $response = wp_remote_post( $url, $args );

        if ( is_wp_error( $response ) ) {
            return $response;
        }

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

        if ( $code != 200 ) {
            // Handle different error response formats
            $data = json_decode( $body, true );
            $error_message = 'Failed to generate audio.';
            if ( isset( $data['detail'] ) ) {
                $error_message = $data['detail'];
            } elseif ( isset( $data['message'] ) ) {
                $error_message = $data['message'];
            } elseif ( isset( $data['data']['message'] ) ) {
                $error_message = $data['data']['message'];
            }
            return new WP_Error( 'api_error', $error_message );
        }

        $audio_data = $body;

        // Save audio file to media library
        $upload_dir = wp_upload_dir();
        $filename = 'cwp-elevenlabs-' . $post_id . '-' . time() . '.mp3';
        $audio_file = $upload_dir['path'] . '/' . $filename;
        $file_saved = file_put_contents( $audio_file, $audio_data );

        if ( $file_saved === false ) {
            return new WP_Error( 'file_save_error', 'Failed to save audio file.' );
        }

        // Check file type and set proper MIME type
        $filetype = wp_check_filetype( $filename, null );

        // Prepare an array of post data for the attachment.
        $attachment = array(
            'guid'           => $upload_dir['url'] . '/' . $filename,
            'post_mime_type' => $filetype['type'],
            'post_title'     => 'CodeWP ElevenLabs Audio for Post ' . $post_id,
            'post_content'   => '',
            'post_status'    => 'inherit'
        );

        // Insert the attachment.
        $attach_id = wp_insert_attachment( $attachment, $audio_file, $post_id );

        // Generate the metadata for the attachment, and update the database record.
        require_once( ABSPATH . 'wp-admin/includes/image.php' );
        $attach_data = wp_generate_attachment_metadata( $attach_id, $audio_file );
        wp_update_attachment_metadata( $attach_id, $attach_data );

        // Get the model name (voice name)
        $voice_name = $this->cwp_get_voice_name( $api_key, $voice_id );

        return array(
            'audio_url' => wp_get_attachment_url( $attach_id ),
            'model_name' => $voice_name,
        );
    }

    // Get voice name by voice_id
    private function cwp_get_voice_name( $api_key, $voice_id ) {
        $voices = $this->cwp_get_voices( $api_key );
        if ( is_wp_error( $voices ) ) {
            return '';
        }

        foreach ( $voices as $voice ) {
            if ( $voice['voice_id'] === $voice_id ) {
                return $voice['name'];
            }
        }

        return '';
    }

    // Append audio to content
    public function cwp_append_audio_to_content( $content ) {
        if ( is_singular( 'post' ) ) {
            $post_id = get_the_ID();
            $audio_url = get_post_meta( $post_id, '_cwp_elevenlabs_tts_audio_url', true );
            if ( $audio_url ) {
                $audio_player = do_shortcode( '[audio src="' . esc_url( $audio_url ) . '"]' );
                $options = get_option( $this->option_name );
                $display_model_name = isset( $options['display_model_name'] ) && $options['display_model_name'] === '1';
                $model_name = get_post_meta( $post_id, '_cwp_elevenlabs_tts_model_name', true );
                $model_name_html = '';
                if ( $display_model_name && $model_name ) {
                    $model_name_html = '<p><em>Audio generated using model: ' . esc_html( $model_name ) . '</em></p>';
                }
                $content = $audio_player . $model_name_html . $content;
            }
        }
        return $content;
    }

    // Add custom column to admin post list
    public function cwp_add_audio_column( $columns ) {
        $columns['cwp_audio'] = 'Audio';
        return $columns;
    }

    // Render custom column content
    public function cwp_render_audio_column( $column, $post_id ) {
        if ( 'cwp_audio' === $column ) {
            $audio_url = get_post_meta( $post_id, '_cwp_elevenlabs_tts_audio_url', true );
            if ( $audio_url ) {
                echo '<span style="color:green;">&#10003;</span>';
            } else {
                echo '';
            }
        }
    }

}

new CWP_ElevenLabs_TTS_Plugin();