<?php

if ( ! defined( 'ABSPATH' ) ) {
    die( 'No direct access.' );
}

/**
 * TikTok Slide class
 * 
 * @since 2.37
 */
class MetaTikTokSlide extends MetaSlide
{

    public $identifier = "tiktok"; // should be lowercase, one word (use underscores if needed)
    public $name;
    private $slide_settings;

    /**
     * Register slide type
     */
    public function __construct()
    {
        $this->name = __( 'TikTok', 'ml-slider-pro' );

        if ( is_admin() ) {
            add_filter('media_upload_tabs', array($this, 'custom_media_upload_tab_name'), 999, 1);
            add_action( "media_upload_{$this->identifier}", array( $this, 'get_iframe' ) );

            add_action( "wp_ajax_create_{$this->identifier}_slide", array( $this, 'ajax_create_slide' ) );
            add_action( "wp_ajax_duplicate_{$this->identifier}_slide", array( $this, 'ajax_duplicate_slide' ) );
            add_action( "wp_ajax_update_{$this->identifier}_thumbnail", array( $this, 'ajax_update_thumbnail' ) );
            add_action( 'metaslider_register_admin_styles', array( $this, 'register_admin_styles' ), 10, 1 );
            add_action( 'metaslider_register_admin_components', array( $this, 'add_components' ) );
        }

        add_action("metaslider_save_{$this->identifier}_slide", array($this, 'save_slide'), 5, 3);
        //add_action("metaslider_save_{$this->identifier}_slide", array($this, 'update_slide_thumb'), 4, 3);
        add_filter("metaslider_get_{$this->identifier}_slide", array($this, 'get_slide'), 10, 2);
    }

    /**
     * Add extra tabs to the default wordpress Media Manager iframe
     *
     * @since 2.37
     * 
     * @param array $tabs existing media manager tabs
     * @return array tabs
     */
    public function custom_media_upload_tab_name( $tabs )
    {
        // restrict our tab changes to the MetaSlider plugin page
        if ( ( isset( $_GET['page'] ) && $_GET['page'] == 'metaslider' ) ||
            ( isset( $_GET['tab'] ) && in_array( $_GET['tab'], array( $this->identifier ) ) ) 
        ) {
            $newtabs = array(
                $this->identifier => $this->name
            );

            return array_merge( $tabs, $newtabs );
        }

        return $tabs;
    }
    
    /**
     * Return wp_iframe
     * 
     * @since 2.37
     */
    public function get_iframe()
    {
        return wp_iframe( array( $this, 'iframe' ) );
    }

    /**
     * Media Manager iframe HTML
     * 
     * @since 2.37
     */
    public function iframe()
    {
        do_action( 'metaslider_tiktok_iframe' );

        wp_enqueue_style( 'media-views' );
        wp_enqueue_style(
            "metasliderpro-{$this->identifier}-styles",
            plugins_url( 'assets/style.css', __FILE__ ),
            false,
            METASLIDERPRO_VERSION
        );
        wp_enqueue_script(
            "metasliderpro-{$this->identifier}-script",
            plugins_url( 'assets/script.js', __FILE__ ),
            array( 'jquery' ),
            METASLIDERPRO_VERSION
        );
        wp_localize_script( 
            "metasliderpro-{$this->identifier}-script", 
            'metaslider_custom_slide_type', 
            array(
                'identifier' => $this->identifier,
                'name' => $this->name,
                'nonce' => wp_create_nonce( 'tiktok-slide-nonce' )
            )
        );
        echo "<div class='metaslider'>
                <div class='tiktok'>
                    <div class='media-embed'>
                        <label class='embed-url'>
                            <span>" . 
                                esc_html__( 'Enter the URL of a TikTok video:', 'ml-slider-pro' ) . 
                            "</span>
                            <input type='text' placeholder='https://www.tiktok.com/@boykulot241/video/6895595198034873601' class='tiktok_url ms-super-wide'>
                            <span class='spinner' style='display:none'></span>
                        </label>
                        <div class='embed-link-settings'></div>
                    </div>
                </div>
            </div>
            <div class='media-frame-toolbar'>
                <div class='media-toolbar'>
                    <div class='media-toolbar-primary'>
                        <a href='#' class='button media-button button-primary button-large' disabled='disabled'>" . esc_html__(
                "Add to slideshow",
                "ml-slider-pro"
            ) . "</a>
                    </div>
                </div>
            </div>";
    }

    /**
     * Register admin styles
     * 
     * @since 2.37
     */
    public function register_admin_styles()
    {
        wp_enqueue_style(
            "metasliderpro-{$this->identifier}-style",
            plugins_url( 'assets/style.css', __FILE__ ),
            false,
            METASLIDERPRO_VERSION
        );
    }

    /**
     * Create a new slide and echo the admin HTML
     * 
     * @since 2.37
     */
    public function ajax_create_slide()
    {
        if ( ! isset( $_POST['nonce'] ) 
            || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tiktok-slide-nonce' ) 
        ) {
            wp_send_json_error( esc_html__( 'Invalid nonce', 'ml-slider-pro' ), 403 );
        }

        if ( ! isset( $_POST['slider_id'] ) 
            || ! isset( $_POST['video_id'] ) 
            || ! isset( $_POST['video_url'] ) ) {
            wp_send_json_error( esc_html__( 'Bad request', 'ml-slider-pro' ), 400 );
        }

        $slider_id = intval( $_POST['slider_id'] );
        $fields['menu_order'] = 9999;
        $fields['video_id'] = sanitize_text_field( $_POST['video_id'] );
        $fields['video_url'] = esc_url( $_POST['video_url'] );
        /*$fields['settings']['lazyLoad'] = "on";
        $fields['settings']['showControls'] = "on";*/
        
        $new_slide_id = $this->create_slide( $slider_id, $fields );
        
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        $html = $this->get_admin_slide();

        $result = array(
            'slide_id' => $new_slide_id,
            'html' => $html
        );

        if ( is_wp_error( $result ) ) {
            wp_send_json_error( array(
                'message' => $result->get_error_message()
            ), 409 );
        }
        
        wp_send_json_success ( $result, 200 );
    }

    /**
     * Create a new TikTok slide
     *
     * @since 2.37
     * 
     * @param integer $slider_id - slideshow ID
     * @param array $fields - slide details
     * @return string html
     */
    private function create_slide( $slider_id, $fields )
    {
        $this->set_slider( $slider_id );

        $media_id = $this->create_slide_thumb( $fields['video_id'], $fields['video_url'], $fields['menu_order'] );

        // Create a new post for a slide
        $new_slide_id = $this->insert_slide( $media_id, 'tiktok', $slider_id );

        // Set the slide
        $this->set_slide( $new_slide_id );

        // Tag the slide attachment to the slider tax category
        $this->tag_slide_to_slider();

        $this->save( $fields );

        return $new_slide_id;
    }

    /**
     * Admin slide html
     *
     * @since 2.37
     * 
     * @return string html
     */
    protected function get_admin_slide()
    {
        ob_start();
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        echo $this->get_delete_button_html();
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        echo $this->get_update_image_button_html();
        if( method_exists( $this, 'get_duplicate_slide_button_html' ) ) {
            echo $this->get_duplicate_slide_button_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        }
        do_action('metaslider-slide-edit-buttons', $this->identifier, $this->slide->ID);
        $edit_buttons = ob_get_clean();

        $row = "<tr id='slide-" . esc_attr($this->slide->ID) . "' class='slide " . esc_attr($this->identifier) . " flex responsive'>";
        $row .= "    <td class='col-1'>";
        $row .= "        <div class='metaslider-ui-controls ui-sortable-handle'>";
        $row .= "           <h4 class='slide-details'>";
        $row .= "<span class='tiktok'>TikTok Slide</span> | ID: ". esc_html( $this->slide->ID );
        $row .= "           </h4>";
        if (metaslider_this_is_trash($this->slide)) {
            $row .= '<div class="row-actions trash-btns">';
            $row .= "<span class='untrash'>{$this->get_undelete_button_html()}</span>";
            if( method_exists( $this, 'get_permanent_delete_button_html' ) ) {
                $row .= ' | ';
                $row .= "<span class='delete'>{$this->get_permanent_delete_button_html()}</span>";
            }
            $row .= '</div>';
        } else {
            $row .= $edit_buttons;
        }
        $row .= "        </div>";
        $row .= "    </td>";
        $row .= "    <td class='col-2'>";
        $row .= "       <div class='metaslider-ui-inner flex flex-col h-full'>";

        if (method_exists($this, 'get_admin_slide_tabs_html')) {
            $row .= $this->get_admin_slide_tabs_html();
        } else {
            $row .= "<p>" . esc_html__("Please update to MetaSlider to version 3.2 or above.", "ml-slider-pro") . "</p>";
        }

        $row .= "        <input type='hidden' name='attachment[" . esc_attr($this->slide->ID) . "][type]' value='tiktok' />";
        $row .= "        <input type='hidden' class='menu_order' name='attachment[" . esc_attr($this->slide->ID) . "][menu_order]' value='" . esc_attr($this->slide->menu_order) . "' />";
        $row .= "       </div>";
        $row .= "    </td>";
        $row .= "</tr>";

        return $row;
    }

    /**
     * Get TikTok video thumb, upload into site and save
     * 
     * @since 2.37
     */
    private function create_slide_thumb( $video_id, $video_url, $menu_order )
    {
        // Extract valid video URL without extra optional params
        $pattern = '/^(https?:\/\/(?:www\.)?tiktok\.com\/@[\w.-]+\/video\/\d+)/';

        if ( preg_match( $pattern, $video_url, $matches ) ) {
            $video_url = $matches[1];
        } else {
            return;
        }

        $post_info = array(
            'post_title' => "MetaSlider - TikTok Thumbnail - {$video_id}",
            'post_mime_type' => 'image/jpeg',
            'post_status' => 'inherit',
            'post_content' => '',
            'guid' => $video_url,
            'menu_order' => $menu_order,
            'post_name' => $video_id
        );

        $thumb_url = $this->get_thumb_url( $video_id );

        $tiktok_thumb = false;

        if ( $thumb_url ) {
            $tiktok_thumb = new WP_Http();
            $tiktok_thumb = $tiktok_thumb->request( $thumb_url );
        }

        if ( ! is_wp_error( $tiktok_thumb )
            && isset( $tiktok_thumb['response']['code'] )
            && $tiktok_thumb['response']['code'] == 200
        ) {
            $attachment = wp_upload_bits( "tiktok_{$video_id}.jpg", null, $tiktok_thumb['body'] );
            $filename = $attachment['file'];
            $media_id = wp_insert_attachment( $post_info, $filename );

            if ( ! function_exists( 'wp_generate_attachment_metadata' ) ) {
                include( ABSPATH . 'wp-admin/includes/image.php' );
            }

            $attach_data = wp_generate_attachment_metadata( $media_id, $filename );
            wp_update_attachment_metadata( $media_id, $attach_data );

            return $media_id;
        }

        return wp_insert_attachment( $post_info );
    }

    /**
     * Get the thumbnail URL from the vimeo API
     *
     * @since 2.37
     * 
     * @param string $id URL ID
     * @return string|bolean
     */
    private function get_thumb_url( $id )
    {
        $thumb = new WP_Http();
        $thumb = $thumb->request( "https://www.tiktok.com/oembed?url=https://www.tiktok.com/@username/video/$id" );

        if ( ! is_wp_error( $thumb ) && isset( $thumb['body'] ) ) {
            //var_dump($thumb['body']);
            //exit;

            $json = json_decode( $thumb['body'] );
            if ( isset( $json->thumbnail_url ) ) {
                //echo 'test: ' . $json->thumbnail_url;
                //exit;
                return $json->thumbnail_url;
            }
        }

        return false;
    }

    /**
     * Save slide
     *
     * @since 2.37
     * 
     * @param array $fields Array of field options
     */
    protected function save( $fields )
    {
        // Save the url in case it was updated
        if ( isset( $fields['video_url'] ) && ! empty( $fields['video_url'] ) ) {
            update_post_meta( $this->slide->ID, 'ml-slider_tiktok_url', $fields['video_url'] );
        }

        // Update the order
        wp_update_post( 
            array(
                'ID' => $this->slide->ID,
                'menu_order' => $fields['menu_order']
            ) 
        );

        // on/off settings
        if ( ! isset( $fields['settings']['lazyLoad'] ) ) {
            $fields['settings']['lazyLoad'] = 'off';
        }

        // Save all the settings fields serialized
        if ( isset( $fields['settings'] ) ) {
            $this->add_or_update_or_delete_meta( $this->slide->ID, 'settings', $fields['settings'] );
        }

        $this->add_or_update_or_delete_meta(
            $this->slide->ID,
            'hide_slide_smartphone',
            isset( $fields['hide_slide_smartphone'] ) && $fields['hide_slide_smartphone'] === 'on'
        );

        $this->add_or_update_or_delete_meta(
            $this->slide->ID,
            'hide_slide_tablet',
            isset( $fields['hide_slide_tablet'] ) && $fields['hide_slide_tablet'] === 'on'
        );

        $this->add_or_update_or_delete_meta(
            $this->slide->ID,
            'hide_slide_laptop',
            isset( $fields['hide_slide_laptop'] ) && $fields['hide_slide_laptop'] === 'on'
        );

        $this->add_or_update_or_delete_meta(
            $this->slide->ID,
            'hide_slide_desktop',
            isset( $fields['hide_slide_desktop'] ) && $fields['hide_slide_desktop'] === 'on'
        );
    }

    /**
     * Build an array of tabs and their titles to use for the admin slide.
     * 
     * @since 2.37
     */
    public function get_admin_tabs()
    {
        $path = trailingslashit( plugin_dir_path( __FILE__ ) ) . 'tabs/';

        ob_start();
        include $path . 'general.php';
        $general_tab = ob_get_clean();

        $tabs = array(
            'general' => array(
                'title' => __( 'General', 'ml-slider-pro' ),
                'content' => $general_tab
            )
        );

        $global_settings = $this->get_global_settings();
        if ( ! isset($global_settings['mobileSettings'] ) ||
            ( isset( $global_settings['mobileSettings'] ) && true == $global_settings['mobileSettings'] )
        ) {
            ob_start();
            include $path . 'mobile.php';
            $mobile_tab = ob_get_clean();

            $tabs['mobile'] = array(
                'title' => __( 'Mobile', 'ml-slider' ),
                'content' => $mobile_tab
            );
        }

        return apply_filters("metaslider_tiktok_slide_tabs", $tabs, $this->slide, $this->slider, $this->settings);
    }

    /**
     * Public slide html
     *
     * @since 2.37
     * 
     * @return string html
     */
    protected function get_public_slide()
    {
        add_action( 'metaslider_register_public_styles', array( $this, 'add_extra_styles' ), 10, 2 );

        if ( get_post_meta( $this->slide->ID, 'ml-slider_tiktok_url', true ) ) {
            $url = get_post_meta($this->slide->ID, 'ml-slider_tiktok_url', true);
        } else {
            $url = $this->slide->guid;
        }

        $pattern = '/^(?:https?:\/\/)?(?:www\.)?tiktok\.com\/@[\w.-]+\/video\/(\d+)(?:\S+)?$/';

        if ( preg_match( $pattern, $url, $matches ) ) {
            $video_id = $matches[1];
        } else {
            return;
        }

        if ( $this->settings['type'] == 'flex' ) {
            add_filter( 'metaslider_flex_slider_parameters', array( $this, 'get_flex_slider_parameters' ), 10, 2 );

            return $this->get_flex_slider_markup( $video_id, $url );
        }
    }

    /**
     * Add inline styles used by videos
     * 
     * @since 2.37
     */
    public function add_extra_styles()
    {
        $css = '.metaslider .tiktok.video-loaded img,.metaslider .tiktok.video-loaded .play_button{display:none;transition:display 0.5s ease-in-out}.metaslider .tiktok.video-loaded iframe{opacity:1}.metaslider .tiktok .play_button{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center}.metaslider .tiktok .play_button img{width:75px;cursor:pointer;opacity:0.8}.metaslider .tiktok .play_button img:hover{opacity:1}';
        $css = apply_filters( 'metaslider_tiktok_inline_css', $css, $this->slide, $this->slider->ID );
        wp_add_inline_style('metaslider-public', $css);
    }

    /**
     * Flex slider markup
     *
     * @since 2.37
     * 
     * @param integer $video_id Video ID
     * @return string
     */
    public function get_flex_slider_markup( $video_id, $video_url )
    {
        $html = $this->get_video_markup( $video_id, $video_url );

        // store the slide details
        $attributes = array(
            'class' => "slide-{$this->slide->ID} ms-tiktok {$this->get_mobile_css_class( $this->slide->ID )}",
            'style' => "display: none; width: 100%;"
        );

        // Custom delay
        $is_delayed = (bool) get_post_meta( $this->slide->ID, '_meta_slider_slide_is_delayed', true );
        $delay_time = (int) get_post_meta( $this->slide->ID, '_meta_slider_slide_delayed_time', true );
        
        if ( filter_var( $this->settings['autoPlay'], FILTER_VALIDATE_BOOLEAN ) 
            && $is_delayed && $delay_time > 0
        ) {
            $attributes['data-custom-delay'] = $delay_time;
        }

        $attributes = apply_filters(
            'metaslider_flex_slider_li_attributes',
            $attributes,
            $this->slide->ID,
            $this->slider->ID,
            $this->settings
        );

        $li = "<li";

        foreach ($attributes as $att => $val) {
            $li .= " " . $att . '="' . esc_attr($val) . '"';
        }

        $li .= ">" . $html . "</li>";

        $html = $li;

        return $html;
    }

    /**
     * Videon Markup
     *
     * @since 2.37
     * 
     * @param integer $video_id Video ID
     * @return string
     */
    public function get_video_markup( $video_id, $video_url )
    {
        $lazyLoad = 0;
        if ( isset( $this->slide_settings['lazyLoad'] ) 
            && filter_var( $this->slide_settings['lazyLoad'], FILTER_VALIDATE_BOOLEAN ) 
        ) {
            $lazyLoad = 1;
        }

        $iframe_url = "//www.tiktok.com/embed/v2/{$video_id}";

        $div_attrs = array(
            'style' => "height: 700px; width: 100%;",
            'class' => "tiktok",
            'data-lazy-load' => $lazyLoad,
            'data-video-id' => $video_id,
            'data-cite' => $video_url,
            'data-url' => $iframe_url,
            'data-width' => $this->settings['width'],
            'data-height' => $this->settings['height']
        );

        $blockquote_attrs = array(
            //'data-slide-id' => $this->slide->ID,
            'class' => 'tiktok-embed',
            'cite' => $video_url,
            'data-video-id' => $video_id,
            'style' => 'max-width: 605px; min-width: 325px;'
        );

        $html = "<div";
        foreach ($div_attrs as $key => $value) {
            $html .= " " . $key . '="' . $value . '"';
        }
        $html .= ">";

        if ( $lazyLoad ) {
            $html .= $this->temporary_video_image();
        } else {
            $html .= "<blockquote";
            
            foreach ($blockquote_attrs as $key => $value) {
                $html .= " " . $key . '="' . $value . '"';
            }
            
            $html .= "> <section></section> </blockquote> <script async src='//www.tiktok.com/embed.js'></script>";
        }

        $html .= "</div>";

        return $html;
    }

    /**
     * Get image placeholder with play button
     *
     * @since 2.37
     * 
     * @return string
     */
    public function temporary_video_image()
    {
        $imageHelper = new MetaSliderImageHelper(
            $this->slide->ID,
            $this->settings['width'],
            $this->settings['height'],
            isset($this->settings['smartCrop']) ? $this->settings['smartCrop'] : 'false'
        );
        $url = $imageHelper->get_image_url();

        $image_attributes = array(
            'src' => $url,
            'alt' => '', // @TODO - We need an alt
            'title' => '',
            'class' => 'msDefaultImage',
            'height' => $this->settings['height'],
            'width' => $this->settings['width']
        );

        $html = $this->build_image_tag( $image_attributes );

        $play_button_url = apply_filters(
            'metaslider_vimeo_play_button',
            METASLIDERPRO_BASE_URL . "modules/tiktok/assets/play-button.png",
            $this->slide,
            $this->slider->ID
        );
        $html .= "<span class='play_button'><a tabindex='0' role='button' id='toggle'><img width='75' src='{$play_button_url}'></a></span>";

        return $html;
    }

    /**
     * Pause youtube videos when the slide is changed
     *
     * @since 2.37
     * 
     * @param array $options - current slideshow options
     * @param int $slider_id - current slideshow ID
     * @return array
     */
    public function get_flex_slider_parameters( $options, $slider_id )
    {
        $options['start'] = isset($options['start']) ? $options['start'] : array();
        $options['start'] = array_merge($options['start'], array(
                "$('#metaslider_{$slider_id} .tiktok').each(function() {
                    var tiktok = $(this);
                    var active = tiktok.parent('.flex-active-slide').length;
                    var lazyload = tiktok.data('lazyLoad');
                    
                    tiktok.on('click', function() {
                        $(this).addClass('video-loaded');
                        $(this).append(function() {
                            var blockquote = $('<blockquote>', {
                                class: 'tiktok-embed',
                                style: 'max-width: 605px; min-width: 325px;'
                            });

                            blockquote.attr('data-video-id', $(this).data('video-id'));
                            blockquote.attr('cite', $(this).data('cite'));
                        
                            var iframe = $('<iframe>', {
                                frameborder: 0,
                                allowfullscreen: true,
                                src: $(this).data('url')
                            });
                        
                            iframe.attr('width', $(this).data('width'));
                            iframe.attr('height', $(this).data('height'));
                        
                            blockquote.append(iframe);

                            var script = $('<script>', {
                                type: 'text/javascript',
                                src: '//www.tiktok.com/embed.js',
                                async: true
                            });
                        
                            return blockquote.add(script);
                        });                        
                    });
                });"
            )
        );

        // we don't want this filter hanging around if there's more than one slideshow on the page
        remove_filter( 'metaslider_flex_slider_parameters', array( $this, 'get_flex_slider_parameters' ) );

        return $options;
    }


    /**
     * Duplicate slide ajax
     * 
     * @since 2.37
     */
    public function ajax_duplicate_slide()
    {
        if ( ! isset( $_POST['nonce'] ) 
            || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), "metaslider_duplicate_{$this->identifier}_nonce" ) 
        ) {
            wp_send_json_error( esc_html__( 'Invalid nonce', 'ml-slider-pro' ), 403 );
        }

        $capability = apply_filters( 'metaslider_capability', MetaSliderPlugin::DEFAULT_CAPABILITY_EDIT_SLIDES );
        if ( ! current_user_can( $capability )) {
            wp_send_json_error(
                array(
                    'message' => __('Access denied', 'ml-slider')
                ),
                403
            );
        }

        if ( ! isset( $_POST['slide_id']) || ! isset( $_POST['slider_id'] ) ) {
            wp_send_json_error(
                array(
                    'message' => __('Bad request', 'ml-slider'),
                ),
                400
            );
        }

        $result = $this->duplicate_slide(
            absint( $_POST['slider_id'] ),
            absint( $_POST['slide_id'] )
        );

        wp_send_json_success( $result, 200 );
    }

    /**
     * Duplicate slide
     * 
     * @since 2.37
     */
    public function duplicate_slide( $slideshow_id, $slide_id )
    {
        $old_slide = get_post( $slide_id );

        if ( ! $old_slide ) {
            return 0;
        }

        $title          = $old_slide->post_title;
        $post_excerpt   = '';

        if ( isset( $old_slide->post_excerpt ) ){
            $post_excerpt = $old_slide->post_excerpt;
        }

        // Insert post
        $new_slide = [
            'post_title'  => $title,
            'post_name'   => sanitize_title( $title ),
            'post_status' => 'publish',
            'post_type'   => $old_slide->post_type,
            'post_excerpt'   => $post_excerpt
        ];

        $new_slide_id = wp_insert_post( $new_slide );
        
        // Insert post meta
        $slide_meta = get_post_custom( $slide_id );
        
        foreach ( $slide_meta as $key => $values ) {
            foreach ( $values as $value ) {
                add_post_meta( $new_slide_id, $key, maybe_unserialize( $value ) );
            }
        }

        // Insert taxonomy
        $taxonomies = get_post_taxonomies( $slide_id );

        foreach ( $taxonomies as $taxonomy ) {
            $term_ids = wp_get_object_terms( $slide_id, $taxonomy, ['fields' => 'ids'] );
            wp_set_object_terms( $new_slide_id, $term_ids, $taxonomy );
        }

        $this->set_slide( $new_slide_id );
        $this->set_slider( $slideshow_id );

        return array( 'slide_id' => $new_slide_id, 'html' => $this->get_admin_slide() );
    }

    /**
     * Load admin assets
     * 
     * @since 2.37
     */
    public function add_components()
    {
        wp_enqueue_script(
            "metasliderpro-{$this->identifier}-admin-script",
            plugins_url( 'assets/admin.js', __FILE__ ),
            array( 'jquery' ),
            METASLIDERPRO_VERSION
        );
        wp_localize_script( 
            "metasliderpro-{$this->identifier}-admin-script", 
            'metaslider_tiktok', 
            array(
                'nonce' => wp_create_nonce( 'tiktok-slide-nonce' ),
                'duplicate_slide_nonce' => wp_create_nonce( "metaslider_duplicate_{$this->identifier}_nonce" )
            ) 
        );
    }

    /**
     * Extract the slide setings
     *
     * @param integer $id Slide ID
     */
    public function set_slide( $id )
    {
        parent::set_slide($id);
        $this->slide_settings = get_post_meta($id, 'ml-slider_settings', true);
    }

    /**
     * Update the slide's thumbnail
     * 
     * @since 2.37
     */
    public function ajax_update_thumbnail()
    {
        if ( ! isset( $_POST['nonce'] ) 
            || ! wp_verify_nonce(sanitize_key( $_POST['nonce'] ), 'tiktok-slide-nonce' ) 
        ) {
            wp_send_json_error( esc_html__( 'Invalid nonce', 'ml-slider-pro' ), 403 );
        }

        if ( ! isset( $_POST['video_id'] ) 
            || ! isset( $_POST['slide_id'] ) 
            || ! isset( $_POST['video_url'] ) 
        ) {
            wp_send_json_error( esc_html__( 'Bad request', 'ml-slider-pro' ), 400 );
        }

        $slide_id   = intval( $_POST['slide_id'] );
        $video_id   = sanitize_text_field( $_POST['video_id'] );
        $video_url  = esc_url( $_POST['video_url'] );
        $image_id   = $this->create_slide_thumb( $video_id, $video_url, 999 );

        // Update URL
        $this->add_or_update_or_delete_meta( $slide_id, 'tiktok_url', $video_url );

        /*
         * Updates database record and thumbnail if selection changed, 
         * assigns it to the slide, crops the image
         */
        update_post_meta( $slide_id, '_thumbnail_id', $image_id );

        // Get cropped images for srcset attribute
        $thumbnail_url_large    = $this->get_intermediate_image_src( 1024, $image_id );
        $thumbnail_url_medium   = $this->get_intermediate_image_src( 768, $image_id );
        $thumbnail_url_small    = $this->get_intermediate_image_src( 240, $image_id );

        wp_send_json_success([
            'slide_id' => $slide_id,
            'thumbnail_url_small' => $thumbnail_url_small,
            'thumbnail_url_medium' => $thumbnail_url_medium,
            'thumbnail_url_large' => $thumbnail_url_large
        ]);
    }
}
