<?php

namespace MovieEngine\Frontend;

if (! defined("ABSPATH")) {
    exit; // Exit if accessed directly
}

use MovieEngine\Utils\Helpers;

class Ajax {

    public function __construct() {
        add_action('wp_ajax_movie_engine_get_filter_terms', [$this, 'get_filter_terms']);
        add_action('wp_ajax_nopriv_movie_engine_get_filter_terms', [$this, 'get_filter_terms']);

        add_action('wp_ajax_movie_engine_load_more_episodes', [$this, 'load_more_episodes']);
        add_action('wp_ajax_nopriv_movie_engine_load_more_episodes', [$this, 'load_more_episodes']);

        add_action('wp_ajax_movie_engine_filter_movies', [$this, 'filter_movies']);
        add_action('wp_ajax_nopriv_movie_engine_filter_movies', [$this, 'filter_movies']);

        add_action('wp_ajax_movie_engine_get_video_source', [$this, 'get_video_source']);
        add_action('wp_ajax_nopriv_movie_engine_get_video_source', [$this, 'get_video_source']);

        add_action('wp_ajax_movie_engine_mark_watched', [$this, 'mark_watched']);

        add_action('wp_ajax_movie_engine_toggle_like', [$this, 'toggle_like']);
        add_action('wp_ajax_movie_engine_mark_notif_read', [$this, 'mark_notif_read']);
        add_action('wp_ajax_movie_engine_mark_all_notif_read', [$this, 'mark_all_notif_read']); // NEW
        add_action('wp_ajax_movie_engine_delete_notif', [$this, 'delete_notif']);
        add_action('wp_ajax_movie_engine_get_notifications', [$this, 'ajax_get_notifications']);
        add_action('wp_ajax_movie_engine_track_view', [$this, 'track_view']);
        add_action('wp_ajax_nopriv_movie_engine_track_view', [$this, 'track_view']);

        add_action('wp_ajax_movie_engine_live_search', [$this, 'live_search']);
        add_action('wp_ajax_nopriv_movie_engine_live_search', [$this, 'live_search']);

        add_action('wp_ajax_movie_engine_fetch_reviews', [$this, 'fetch_reviews']);
        add_action('wp_ajax_nopriv_movie_engine_fetch_reviews', [$this, 'fetch_reviews']);
    }


    public function live_search() {
        check_ajax_referer('movie_engine_nonce', 'nonce');
        $search = isset($_GET['s']) ? sanitize_text_field(wp_unslash($_GET['s'])) : '';

        $min_chars = isset($_GET['min_chars']) ? absint($_GET['min_chars']) : 2;
        if (strlen($search) < $min_chars) {
            wp_send_json_success(['html' => '', 'count' => 0]);
        }

        $post_types = isset($_GET['post_types']) ? sanitize_text_field(wp_unslash($_GET['post_types'])) : 'movie_engine_movie,movie_engine_series';
        $limit = isset($_GET['limit']) ? absint($_GET['limit']) : 8;

        $args = [
            'post_type'      => explode(',', $post_types),
            'posts_per_page' => $limit,
            's'              => $search,
            'post_status'    => 'publish',
            'orderby'        => 'relevance'
        ];

        $query = new \WP_Query($args);
        $results_html = '';

        $show_thumbnail = !isset($_GET['show_thumbnail']) || filter_var(wp_unslash($_GET['show_thumbnail'] ?? ''), FILTER_VALIDATE_BOOLEAN);
        $show_year      = !isset($_GET['show_year'])      || filter_var(wp_unslash($_GET['show_year'] ?? ''), FILTER_VALIDATE_BOOLEAN);
        $show_type      = !isset($_GET['show_type'])      || filter_var(wp_unslash($_GET['show_type'] ?? ''), FILTER_VALIDATE_BOOLEAN);

        if ($query->have_posts()) {
            while ($query->have_posts()) {
                $query->the_post();
                $id = get_the_ID();
                $poster = get_the_post_thumbnail_url($id, 'thumbnail');

                $type = get_post_type($id) === 'movie_engine_movie' ? esc_html__('Movie', 'cine-movie-engine') : esc_html__('TV Series', 'cine-movie-engine');
                $year = '';
                $years = get_the_terms($id, 'movie_engine_year');
                if ($years && !is_wp_error($years)) {
                    $year = $years[0]->name;
                }

                $results_html .= '<a href="' . esc_url(get_permalink()) . '" class="movie-engine-live-search-result">';
                
                if ($show_thumbnail) {
                    if ($poster) {
                        $results_html .= '<div class="movie-engine-ls-poster"><img src="' . esc_url($poster) . '" alt="' . esc_attr(get_the_title()) . '"></div>';
                    } else {
                        $results_html .= '<div class="movie-engine-ls-poster me-ls-placeholder"><span class="dashicons dashicons-format-video"></span></div>';
                    }
                }

                $results_html .= '<div class="movie-engine-ls-info">';
                $results_html .= '<span class="movie-engine-ls-title">' . esc_html(get_the_title()) . '</span>';
                
                if ($show_year || $show_type) {
                    $results_html .= '<span class="movie-engine-ls-meta">';
                    if ($show_year && $year) {
                        $results_html .= esc_html($year);
                    }
                    if ($show_year && $year && $show_type) {
                        $results_html .= ' &bull; ';
                    }
                    if ($show_type) {
                        $results_html .= esc_html($type);
                    }
                    $results_html .= '</span>';
                }

                $results_html .= '</div>';
                $results_html .= '</a>';
            }
            wp_reset_postdata();
        } else {
            $results_html = '<div class="movie-engine-ls-no-results">' . esc_html__('No results found.', 'cine-movie-engine') . '</div>';
        }

        wp_send_json_success([
            'html'  => $results_html,
            'count' => $query->post_count
        ]);
    }


    public function get_video_source() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
        $server_index = isset($_POST['server_index']) ? absint($_POST['server_index']) : 0;

        if (!$post_id) {
            wp_send_json_error('Invalid post ID');
        }

        if (!class_exists('\MovieEngine\Frontend\Player')) {
            wp_send_json_error('Player class not found');
        }

        $sources = \MovieEngine\Frontend\Player::get_player_data($post_id);

        if (empty($sources) || !isset($sources[$server_index])) {
            wp_send_json_error('Source not found');
        }

        $source = $sources[$server_index];
        $url = $source['url'];
        $type = ! empty($source['type']) ? $source['type'] : 'iframe';

        if (strpos($url, '.m3u8') !== false) {
            $type = 'hls';
        } elseif (strpos($url, '.mpd') !== false) {
            $type = 'dash';
        } elseif (preg_match('/(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&\?\/]+)/', $url)) {
            $type = 'youtube';
        } elseif ($type === 'iframe' || $type === 'embed') {
            $type = 'iframe_embed';
        }

        $is_mp4_format = in_array($type, ['mp4', 'video_file', 'direct'], true);

        if (is_ssl()) {
            $url = str_replace('http://', 'https://', $url);
        }

        $player_settings = get_option('movie_engine_player_settings', []);
        $hide_video_url = !empty($player_settings['movie_engine_hide_video_url']) || !empty($player_settings['hide_video_url']);
        $player_lib = $player_settings['movie_engine_player_library'] ?? ($player_settings['player_library'] ?? 'plyr');
        $is_shaka = ($player_lib === 'shaka');
        $is_clappr = ($player_lib === 'clappr');
        $is_proxy_url = (strpos($url, '/wp-json/movie-engine/v1/stream/') !== false);

        if ($is_proxy_url && ! $hide_video_url) {
            $raw_sources = get_post_meta($post_id, '_movie_engine_sources', true);
            $raw_index = isset($source['source_index']) ? (int) $source['source_index'] : $server_index;
            if (preg_match('/[?&]index=(\d+)/', $url, $m)) {
                $raw_index = (int) $m[1];
            }
            if (!empty($raw_sources) && is_array($raw_sources) && isset($raw_sources[$raw_index]['url'])) {
                $raw_url = esc_url_raw(trim($raw_sources[$raw_index]['url']));
                if (!empty($raw_url)) {
                    $secure_tokens = !empty($player_settings['movie_engine_secure_tokens']) || !empty($player_settings['secure_tokens']);
                    if ($secure_tokens) {
                        $raw_url = $this->generate_signed_url($raw_url, $post_id);
                    }
                    if (is_ssl() && strpos($raw_url, 'http:') === 0) {
                        $raw_url = str_replace('http://', 'https://', $raw_url);
                    }
                    $url = $raw_url;
                }
            }
        }

        $encoded_url = base64_encode($url);

        $progress = 0;
        if (is_user_logged_in()) {
            $user_id = get_current_user_id();
            $progress = \MovieEngine\Frontend\Users\WatchHistory::get_progress($user_id, $post_id);
        }

        $response = [
            'url' => $encoded_url,
            'type' => $type,
            'progress' => $progress,
            'quality'  => $source['quality'] ?? 'HD',
            'poster'   => get_the_post_thumbnail_url($post_id, 'full') ?: ''
        ];

        if ($is_mp4_format && ! empty($source['quality_variants']) && is_array($source['quality_variants'])) {
            $is_ssl = is_ssl();
            $raw_sources_for_variants = (!$hide_video_url && $is_shaka) ? get_post_meta($post_id, '_movie_engine_sources', true) : null;
            $secure_tokens_variants = $is_shaka ? (!empty($player_settings['movie_engine_secure_tokens']) || !empty($player_settings['secure_tokens'])) : false;

            $response['quality_variants'] = array_map(function ($v) use ($is_ssl, $is_shaka, $hide_video_url, $raw_sources_for_variants, $post_id, $secure_tokens_variants) {
                $v_url = $v['url'];

                if (! $hide_video_url && $is_shaka && strpos($v_url, '/wp-json/movie-engine/v1/stream/') !== false) {
                    if (preg_match('/[?&]index=(\d+)/', $v_url, $m)) {
                        $v_index = (int) $m[1];
                        if (!empty($raw_sources_for_variants[$v_index]['url'])) {
                            $v_url = esc_url_raw(trim($raw_sources_for_variants[$v_index]['url']));
                            if ($secure_tokens_variants) {
                                $v_url = $this->generate_signed_url($v_url, $post_id);
                            }
                        }
                    }
                }

                if ($is_ssl && strpos($v_url, 'http:') === 0) {
                    $v_url = str_replace('http://', 'https://', $v_url);
                }
                return [
                    'url' => base64_encode($v_url),
                    'size' => (int) ($v['size'] ?? 720),
                    'label' => $v['label'] ?? (($v['size'] ?? 720) . 'p')
                ];
            }, $source['quality_variants']);
        }

        if ($is_mp4_format && ! empty($source['language_variants']) && is_array($source['language_variants'])) {
            $is_ssl = is_ssl();
            $secure_tokens = $is_shaka ? (!empty($player_settings['movie_engine_secure_tokens']) || !empty($player_settings['secure_tokens'])) : false;
            $response['language_variants'] = array_map(function ($v) use ($is_ssl, $is_shaka, $post_id, $secure_tokens) {
                $v_url = $v['url'];
                if ($is_shaka && ! empty($v['direct_url'])) {
                    $v_url = $v['direct_url'];
                    if ($secure_tokens) {
                        $v_url = $this->generate_signed_url($v_url, $post_id);
                    }
                }
                if ($is_ssl && strpos($v_url, 'http:') === 0) {
                    $v_url = str_replace('http://', 'https://', $v_url);
                }
                return [
                    'code'  => $v['code'] ?? 'en',
                    'label' => $v['label'] ?? 'English',
                    'url'   => base64_encode($v_url),
                ];
            }, $source['language_variants']);
        }

        wp_send_json_success($response);
    }

    private function generate_signed_url($url, $post_id) {
        $expires = time() + (2 * 60 * 60);
        $ip = $this->get_client_ip_for_signing();
        $secret = defined('AUTH_KEY') ? AUTH_KEY : 'movie-engine-secret';
        $data = $url . $expires . $ip . $post_id;
        $signature = hash_hmac('sha256', $data, $secret);
        $separator = (strpos($url, '?') !== false) ? '&' : '?';
        return $url . $separator . http_build_query([
            'token'   => $signature,
            'expires' => $expires,
            'vid'     => $post_id,
        ]);
    }

    private function get_client_ip_for_signing() {
        $ip = '';
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = sanitize_text_field(wp_unslash($_SERVER['HTTP_CLIENT_IP']));
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR']));
        } else {
            $ip = sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'] ?? ''));
        }
        return sanitize_text_field($ip);
    }


    public function get_filter_terms() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        $post_type = isset($_GET['post_type']) ? sanitize_text_field(wp_unslash($_GET['post_type'])) : '';
        $genre     = isset($_GET['genre']) ? sanitize_text_field(wp_unslash($_GET['genre'])) : '';
        $year      = isset($_GET['year']) ? sanitize_text_field(wp_unslash($_GET['year'])) : '';

        $filters = [];
        if (!empty($genre)) $filters['movie_engine_genre'] = $genre;
        if (!empty($year))  $filters['movie_engine_year']  = $year;

        $genres = Helpers::get_filtered_terms('movie_engine_genre', [
            'post_type' => $post_type,
            'filters'   => $filters
        ]);

        $genre_options = [];
        foreach ($genres as $g) {
            $genre_options[] = [
                'slug' => $g->slug,
                'name' => $g->name
            ];
        }

        // Get Years
        $years = Helpers::get_filtered_terms('movie_engine_year', [
            'post_type' => $post_type,
            'filters'   => $filters
        ]);

        // Sort years
        usort($years, function ($a, $b) {
            return strcmp($b->name, $a->name);
        });

        $year_options = [];
        foreach ($years as $y) {
            $year_options[] = [
                'slug' => $y->slug,
                'name' => $y->name
            ];
        }

        wp_send_json_success([
            'genres' => $genre_options,
            'years'  => $year_options
        ]);
    }


    public function load_more_episodes() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        $series_id = isset($_POST['series_id']) ? absint(wp_unslash($_POST['series_id'])) : null;
        $season = isset($_POST['season']) ? intval(wp_unslash($_POST['season'])) : null;
        $page = isset($_POST['page']) ? absint(wp_unslash($_POST['page'])) : 1;
        $per_page = isset($_POST['per_page']) ? intval(wp_unslash($_POST['per_page'])) : 10;
        $layout = isset($_POST['layout']) ? sanitize_text_field(wp_unslash($_POST['layout'])) : 'list';

        if ($series_id === null || $season === null) {
            wp_send_json_error([
                'message' => 'Invalid parameters',
                'series_id' => $series_id,
                'season' => $season
            ]);
        }

        $current_episode_id = isset($_POST['current_episode_id']) ? absint($_POST['current_episode_id']) : 0;

        // phpcs:ignore WordPress.DB.SlowDBQuery
        $episodes = new \WP_Query([
            'post_type' => 'movie_engine_episode',
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
            'meta_key' => '_movie_engine_episode_number',
            'orderby' => 'meta_value_num',
            'order' => 'ASC',
            'posts_per_page' => $per_page,
            'paged' => $page,
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
            'meta_query' => [
                // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
                'relation' => 'AND',
                // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                ['key' => '_movie_engine_series_id', 'value' => $series_id],
                // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                ['key' => '_movie_engine_season_number', 'value' => $season]
            ]
        ]);

        if (!$episodes->have_posts()) {
            wp_send_json_error('No more episodes');
        }

        ob_start();
        while ($episodes->have_posts()) : $episodes->the_post();
            $episode_id = get_the_ID();
            $episode_num = get_post_meta($episode_id, '_movie_engine_episode_number', true);
            $duration = get_post_meta($episode_id, '_movie_engine_runtime', true);
            $thumbnail = get_the_post_thumbnail_url($episode_id, 'large');

            if (!$thumbnail) {
                $thumbnail = get_post_meta($series_id, '_movie_engine_backdrop_url', true);
                if (!$thumbnail) {
                    $thumbnail = get_the_post_thumbnail_url($series_id, 'large');
                }
            }
            if (!$thumbnail) {
                $thumbnail = MOVIE_ENGINE_URL . 'assets/images/episode-placeholder.svg';
            }

            $is_active = ($episode_id == $current_episode_id);
            $active_class = $is_active ? 'is-active' : '';

            if ($layout === 'sidebar') : ?>
                <a href="<?php the_permalink(); ?>" class="me-playlist-item <?php echo ($is_active ? 'active' : ''); ?>">
                    <div class="me-item-thumb">
                        <img src="<?php echo esc_url($thumbnail); ?>" alt="<?php the_title_attribute(); ?>">
                        <?php if ($is_active) : ?>
                            <div class="me-playing-overlay">
                                <span class="dashicons dashicons-controls-play"></span>
                            </div>
                        <?php endif; ?>
                    </div>
                    <div class="me-item-info">
                        <span class="me-ep-num">
                            <?php printf(
                                /* translators: %s: episode number */
                                esc_html__('Episode %s', 'cine-movie-engine'),
                                esc_html($episode_num)
                            ); ?></span>
                        <h4 class="me-ep-title"><?php the_title(); ?></h4>
                        <?php if ($duration) : ?>
                            <span class="me-ep-runtime"><?php echo esc_html($duration); ?>m</span>
                        <?php endif; ?>
                    </div>
                </a>
            <?php elseif ($layout === 'list') : ?>
                <a href="<?php the_permalink(); ?>" class="movie-engine-episode-list-item <?php echo esc_attr($active_class); ?>">
                    <div class="me-episode-index"><?php echo esc_html($episode_num); ?></div>
                    <div class="me-episode-thumb">
                        <img src="<?php echo esc_url($thumbnail); ?>" alt="<?php the_title_attribute(); ?>">
                        <span class="me-play-icon"><span class="dashicons dashicons-controls-play"></span></span>
                    </div>
                    <div class="me-episode-info">
                        <h3 class="me-episode-title">
                            <?php the_title(); ?>
                            <?php if ($duration) : ?><span class="me-duration"><?php echo esc_html($duration); ?></span><?php endif; ?>
                        </h3>
                        <div class="me-episode-excerpt"><?php echo \MovieEngine\Utils\Helpers::kses_post(wp_strip_all_tags(get_the_excerpt())); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- kses_post sanitizes HTML ?></div>
                    </div>
                    <div class="me-episode-meta">
                        <span class="me-date"><?php echo get_the_date(); ?></span>
                    </div>
                </a>
            <?php else : ?>
                <div class="movie-engine-episode-card <?php echo esc_attr($active_class); ?>">
                    <a href="<?php the_permalink(); ?>" class="me-episode-thumb-wrapper">
                        <img src="<?php echo esc_url($thumbnail); ?>" alt="<?php the_title_attribute(); ?>">
                        <div class="me-episode-overlay">
                            <span class="dashicons dashicons-controls-play"></span>
                        </div>
                        <?php if ($episode_num) : ?>
                            <span class="me-episode-badge">
                                <?php printf(
                                    /* translators: %s: episode number */
                                    esc_html__('Ep %s', 'cine-movie-engine'),
                                    esc_html($episode_num)
                                ); ?>
                            </span>
                        <?php endif; ?>
                    </a>
                    <div class="me-episode-content">
                        <h3 class="me-episode-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
                        <div class="me-episode-meta">
                            <?php if ($duration) : ?>
                                <span class="me-meta-item">
                                    <span class="dashicons dashicons-clock"></span> <?php echo esc_html($duration); ?>m
                                </span>
                            <?php endif; ?>
                        </div>
                    </div>
                </div>
            <?php endif;
        endwhile;
        $html = ob_get_clean();

        $pagination_html = '';
        if ($episodes->max_num_pages > 1) {
            $pagination_html = paginate_links([
                'base' => add_query_arg('ep_page', '%#%'),
                'format' => '',
                'current' => $page,
                'total' => $episodes->max_num_pages,
                'prev_text' => '<span class="fa-solid fa-angle-left"></span>',
                'next_text' => '<span class="fa-solid fa-angle-right"></span>',
                'type' => 'list'
            ]);
        }

        wp_reset_postdata();

        wp_send_json_success([
            'html' => $html,
            'pagination' => $pagination_html
        ]);
    }


    public function filter_movies() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        $post_type = isset($_GET['me_post_type']) ? wp_unslash($_GET['me_post_type']) : (isset($_GET['post_type']) ? wp_unslash($_GET['post_type']) : '');
        if (is_array($post_type)) {
            $post_type = array_filter(array_map('sanitize_text_field', $post_type));
        } else {
            $post_type = sanitize_text_field($post_type);
            if (strpos($post_type, ',') !== false) {
                $post_type = array_filter(array_map('trim', explode(',', $post_type)));
            }
        }

        $get_val = function ($key1, $key2) {
            // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            if (isset($_GET[$key1])) return array_map('sanitize_text_field', wp_unslash((array)$_GET[$key1]));
            // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            if (isset($_GET[$key2])) return array_map('sanitize_text_field', wp_unslash((array)$_GET[$key2]));
            return [];
        };

        $genres = $get_val('movie_engine_genre', 'me_genre');
        $tags = $get_val('movie_engine_tag', 'me_tag');
        $years = $get_val('movie_engine_year', 'me_year');
        $qualities = $get_val('movie_engine_quality', 'me_quality');
        $languages = $get_val('movie_engine_language', 'me_language');
        $access = isset($_GET['me_access']) ? array_map('sanitize_text_field', wp_unslash((array)$_GET['me_access'])) : [];
        $duration = isset($_GET['me_duration']) ? sanitize_text_field(wp_unslash($_GET['me_duration'])) : '';
        $rating_min = isset($_GET['me_rating_min']) ? floatval(wp_unslash($_GET['me_rating_min'])) : 0;
        $orderby = isset($_GET['orderby']) ? sanitize_text_field(wp_unslash($_GET['orderby'])) : 'date';
        $search = isset($_GET['s']) ? sanitize_text_field(wp_unslash($_GET['s'])) : '';
        $paged = isset($_REQUEST['paged']) ? absint(wp_unslash($_REQUEST['paged'])) : (isset($_REQUEST['me_paged']) ? absint(wp_unslash($_REQUEST['me_paged'])) : 1);
        $paged = max(1, $paged);

        $design_settings = get_option('movie_engine_design_settings', []);

        $is_search = !empty($search);
        $setting_key = $is_search ? 'search_items_per_page' : 'archive_items_per_page';
        $items_per_page = isset($design_settings[$setting_key]) ? intval($design_settings[$setting_key]) : 12;

        if (isset($_REQUEST['posts_per_page'])) {
            $req_limit = intval($_REQUEST['posts_per_page']);
            if ($req_limit > 0 && $req_limit <= 100) {
                $items_per_page = $req_limit;
            }
        }

        $args = [
            'post_type' => !empty($post_type) ? $post_type : ['movie_engine_movie', 'movie_engine_series'],
            'posts_per_page' => $items_per_page,
            'paged' => $paged,
            'post_status' => 'publish',
        ];

        if (!empty($search)) {
            $args['s'] = $search;
        }

        switch ($orderby) {
            case 'title_asc':
                $args['orderby'] = 'title';
                $args['order'] = 'ASC';
                break;
            case 'title_desc':
                $args['orderby'] = 'title';
                $args['order'] = 'DESC';
                break;
            case 'rating':
                $args['meta_key'] = '_movie_engine_rating'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                $args['orderby'] = 'meta_value_num';
                $args['order'] = 'DESC';
                break;
            case 'views':
                $args['meta_key'] = '_movie_engine_views'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                $args['orderby'] = 'meta_value_num';
                $args['order'] = 'DESC';
                break;
            case 'oldest':
                $args['orderby'] = 'date';
                $args['order'] = 'ASC';
                break;
            case 'upcoming':
                $args['meta_key'] = '_movie_engine_release_date'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                $args['orderby'] = 'meta_value';
                $args['order'] = 'ASC';
                // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
                $args['meta_query'][] = [
                    'key' => '_movie_engine_release_date',
                    'value' => gmdate('Y-m-d'),
                    'compare' => '>',
                    'type' => 'DATE'
                ];
                break;
            default:
                $args['orderby'] = 'date';
                $args['order'] = 'DESC';
                break;
        }

        $genres    = array_filter($genres);
        $tags      = array_filter($tags);
        $years     = array_filter($years);
        $languages = array_filter($languages);
        $qualities = array_filter($qualities);

        $tax_query = ['relation' => 'AND'];

        if (!empty($genres)) {
            $tax_query[] = [
                'taxonomy' => 'movie_engine_genre',
                'field' => 'slug',
                'terms' => $genres,
                'operator' => 'IN'
            ];
        }

        if (!empty($years)) {
            $tax_query[] = [
                'taxonomy' => 'movie_engine_year',
                'field' => 'slug',
                'terms' => $years,
                'operator' => 'IN'
            ];
        }

        if (!empty($tags)) {
            $tax_query[] = [
                'taxonomy' => 'movie_engine_tag',
                'field' => 'slug',
                'terms' => $tags,
                'operator' => 'IN'
            ];
        }

        if (!empty($languages)) {
            $tax_query[] = [
                'taxonomy' => 'movie_engine_language',
                'field' => 'slug',
                'terms' => $languages,
                'operator' => 'IN'
            ];
        }

        if (!empty($qualities)) {
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
            $tax_query[] = [
                'relation' => 'OR',
                [
                    'taxonomy' => 'movie_engine_quality',
                    'field' => 'slug',
                    'terms' => $qualities,
                    'operator' => 'IN'
                ],
                [
                    'taxonomy' => 'movie_engine_tv_quality',
                    'field' => 'slug',
                    'terms' => $qualities,
                    'operator' => 'IN'
                ]
            ];
        }

        if (count($tax_query) > 1) {
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
            $args['tax_query'] = $tax_query;
        }
        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
        $meta_query = ['relation' => 'AND'];

        if (!empty($access)) {
            $access_queries = ['relation' => 'OR'];
            foreach ($access as $type) {
                if ($type === 'free') {
                    $access_queries[] = [
                        'relation' => 'OR',
                        [
                            'key'     => '_movie_engine_is_premium',
                            'value'   => '1',
                            'compare' => '!='
                        ],
                        [
                            'key'     => '_movie_engine_is_premium',
                            'compare' => 'NOT EXISTS'
                        ]
                    ];
                } elseif ($type === 'premium') {
                    $access_queries[] = [
                        'key'     => '_movie_engine_is_premium',
                        'value'   => '1',
                        'compare' => '='
                    ];
                } elseif ($type === 'rent') {
                    $access_queries[] = [
                        'relation' => 'OR',
                        [
                            'key'     => '_movie_engine_rent_price',
                            'value'   => 0,
                            'compare' => '>',
                            'type'    => 'NUMERIC'
                        ],
                        [
                            'key'     => '_movie_engine_sale_price',
                            'value'   => 0,
                            'compare' => '>',
                            'type'    => 'NUMERIC'
                        ]
                    ];
                }
            }
            $meta_query[] = $access_queries;
        }

        if (!empty($duration)) {
            switch ($duration) {
                case 'under_1':
                    $meta_query[] = [
                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                        'key' => '_movie_engine_runtime',
                        'value' => 60,
                        'compare' => '<',
                        'type' => 'NUMERIC'
                    ];
                    break;
                case '1_2':
                    $meta_query[] = [
                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                        'key' => '_movie_engine_runtime',
                        'value' => [60, 120],
                        'compare' => 'BETWEEN',
                        'type' => 'NUMERIC'
                    ];
                    break;
                case '2_3':
                    $meta_query[] = [
                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                        'key' => '_movie_engine_runtime',
                        'value' => [120, 180],
                        'compare' => 'BETWEEN',
                        'type' => 'NUMERIC'
                    ];
                    break;
                case 'above_3':
                    $meta_query[] = [
                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                        'key' => '_movie_engine_runtime',
                        'value' => 180,
                        'compare' => '>',
                        'type' => 'NUMERIC'
                    ];
                    break;
            }
        }

        if ($rating_min > 0) {
            $meta_query[] = [
                // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                'key' => '_movie_engine_rating',
                'value' => $rating_min,
                'compare' => '>=',
                'type' => 'NUMERIC'
            ];
        }

        if (isset($_REQUEST['me_gender'])) {
            $genders = array_map('sanitize_text_field', wp_unslash((array)$_REQUEST['me_gender']));
            if (!empty($genders)) {
                $gender_meta = ['relation' => 'OR'];
                foreach ($genders as $gender) {
                    $gender_meta[] = [
                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                        'key'     => '_movie_engine_gender',
                        'value'   => $gender,
                        'compare' => '='
                    ];
                }
                $meta_query[] = $gender_meta;
            }
        }

        if (isset($_REQUEST['me_birth_year'])) {
            $birth_years = array_map('sanitize_text_field', wp_unslash((array)$_REQUEST['me_birth_year']));
            if (!empty($birth_years)) {
                $year_meta = ['relation' => 'OR'];
                foreach ($birth_years as $year) {
                    $year_meta[] = [
                        'relation' => 'OR',
                        [
                            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                            'key'     => '_movie_engine_birthday',
                            'value'   => $year . '-',
                            'compare' => 'LIKE'
                        ],
                        [
                            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                            'key'     => '_movie_engine_birthday',
                            'value'   => $year,
                            'compare' => '='
                        ]
                    ];
                }
                $meta_query[] = $year_meta;
            }
        }

        if (isset($_REQUEST['movie_engine_known_for'])) {
            $known_for = map_deep(wp_unslash($_REQUEST['movie_engine_known_for']), 'sanitize_text_field');
            if (!empty($known_for)) {
                $known_for_arr = array_map('sanitize_text_field', (array)$known_for);
                $kf_meta = ['relation' => 'OR'];
                foreach ($known_for_arr as $kf) {
                    $kf_meta[] = [
                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
                        'key'     => '_movie_engine_known_for',
                        'value'   => $kf,
                        'compare' => '='
                    ];
                }
                $meta_query[] = $kf_meta;
            }
        }

        if (count($meta_query) > 1) {
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
            $args['meta_query'] = isset($args['meta_query']) ? array_merge($args['meta_query'], $meta_query) : $meta_query;
        }

        // phpcs:ignore WordPress.DB.SlowDBQuery
        $query = new \WP_Query($args);

        ob_start();
        if ($query->have_posts()) {
            while ($query->have_posts()) {
                $query->the_post();
                if (get_post_type() === 'movie_engine_person') {
                    \MovieEngine\Utils\TemplateLoader::get_template_part('loop/content-person');
                } else {
                    \MovieEngine\Utils\TemplateLoader::get_template_part('loop/content-movie');
                }
            }
        } else {
            echo '<div class="movie-engine-no-results"><p>' . esc_html__('No content found.', 'cine-movie-engine') . '</p></div>';
        }
        $html = ob_get_clean();

        $pagination_html = \MovieEngine\Utils\Helpers::kses_post(\MovieEngine\Utils\Helpers::render_pagination($paged, $query->max_num_pages));

        wp_reset_postdata();

        $start = (($paged - 1) * $items_per_page) + 1;
        $end = $start + $query->post_count - 1;

        wp_send_json_success([
            'html'        => $html,
            'pagination'  => $pagination_html,
            'max_pages'   => $query->max_num_pages,
            'found_posts' => $query->found_posts,
            'count_text'  => sprintf(
                /* translators: 1: start index, 2: end index, 3: total number of posts */
                esc_html__('Showing %1$d-%2$d of %3$d results', 'cine-movie-engine'),
                (int) $start,
                (int) $end,
                (int) $query->found_posts
            ),
        ]);
    }


    public function mark_watched() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        if (!is_user_logged_in()) {
            wp_send_json_error('User not logged in');
        }

        $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
        if (!$post_id) {
            wp_send_json_error('Invalid post ID');
        }

        $user_id = get_current_user_id();
        $watched = get_user_meta($user_id, '_movie_engine_watched', true);
        if (!is_array($watched)) {
            $watched = [];
        }

        if (!in_array($post_id, $watched)) {
            $watched[] = $post_id;
            update_user_meta($user_id, '_movie_engine_watched', $watched);
        }

        wp_send_json_success(['message' => esc_html__('Marked as watched', 'cine-movie-engine')]);
    }


    public function toggle_like() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        if (!is_user_logged_in()) {
            wp_send_json_error(['message' => esc_html__('Please login to like this content.', 'cine-movie-engine')]);
        }

        $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
        if (!$post_id) {
            wp_send_json_error(['message' => esc_html__('Invalid content.', 'cine-movie-engine')]);
        }

        $user_id = get_current_user_id();
        $action = \MovieEngine\Frontend\Users\UserActions::toggle_like($user_id, $post_id);
        $likes_count = (int) get_post_meta($post_id, '_movie_engine_likes_count', true);

        wp_send_json_success([
            'liked' => ($action === 'added'),
            'count' => $likes_count,
            'formatted_count' => Helpers::format_number($likes_count)
        ]);
    }


    public function track_view() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
        if (!$post_id) {
            wp_send_json_error();
        }

        $cookie_name = 'movie_engine_viewed_' . $post_id;
        if (isset($_COOKIE[$cookie_name])) {
            wp_send_json_success(['message' => esc_html__('Already viewed', 'cine-movie-engine')]);
        }

        $views = (int) get_post_meta($post_id, '_movie_engine_views', true);
        $views++;
        update_post_meta($post_id, '_movie_engine_views', $views);

        setcookie($cookie_name, '1', time() + 3600, COOKIEPATH, COOKIE_DOMAIN);

        wp_send_json_success(['views' => Helpers::format_number($views)]);
    }


    public function mark_notif_read() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        if (!is_user_logged_in()) {
            wp_send_json_error();
        }

        $notif_id = isset($_POST['id']) ? sanitize_text_field(wp_unslash($_POST['id'])) : '';
        if (!$notif_id) {
            wp_send_json_error();
        }

        $user_id = get_current_user_id();
        $success = \MovieEngine\Frontend\Users\Notifications::mark_as_read($user_id, $notif_id);

        if ($success) {
            wp_send_json_success();
        } else {
            wp_send_json_error();
        }
    }


    public function mark_all_notif_read() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        if (!is_user_logged_in()) {
            wp_send_json_error();
        }

        $user_id = get_current_user_id();
        $success = \MovieEngine\Frontend\Users\Notifications::mark_all_read($user_id);

        if ($success) {
            wp_send_json_success(['message' => esc_html__('All marked as read', 'cine-movie-engine')]);
        } else {
            wp_send_json_error(['message' => esc_html__('Nothing to update', 'cine-movie-engine')]);
        }
    }


    public function delete_notif() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        if (!is_user_logged_in()) {
            wp_send_json_error();
        }

        $notif_id = isset($_POST['id']) ? sanitize_text_field(wp_unslash($_POST['id'])) : '';
        if (!$notif_id) {
            wp_send_json_error();
        }

        $user_id = get_current_user_id();
        $success = \MovieEngine\Frontend\Users\Notifications::delete($user_id, $notif_id);

        if ($success) {
            wp_send_json_success();
        } else {
            wp_send_json_error();
        }
    }


    public function ajax_get_notifications() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        if (!is_user_logged_in()) {
            wp_die();
        }

        $_POST['tab'] = isset($_POST['tab']) ? sanitize_text_field(wp_unslash($_POST['tab'])) : 'unread';
        $_POST['limit'] = isset($_POST['limit']) ? intval(wp_unslash($_POST['limit'])) : 10;
        $_POST['paged'] = isset($_POST['paged']) ? intval(wp_unslash($_POST['paged'])) : 1;

        \MovieEngine\Utils\TemplateLoader::get_template_part('dashboard/notifications-list');
        die();
    }

    public function fetch_reviews() {
        check_ajax_referer('movie_engine_nonce', 'nonce');

        $post_id = isset($_REQUEST['post_id']) ? absint($_REQUEST['post_id']) : (isset($_REQUEST['postId']) ? absint($_REQUEST['postId']) : 0);
        $current_page = 1;
        if (isset($_REQUEST['me_paged'])) {
            $current_page = absint($_REQUEST['me_paged']);
        } elseif (isset($_REQUEST['paged'])) {
            $current_page = absint($_REQUEST['paged']);
        } elseif (isset($_REQUEST['page'])) {
            $current_page = absint($_REQUEST['page']);
        }
        $current_page = max(1, $current_page);

        if (!$post_id) {
            wp_send_json_error('Invalid post ID');
        }

        $movie_engine_design_options = get_option('movie_engine_design_settings', []);
        $reviews_per_page = !empty($movie_engine_design_options['archive_items_per_page']) ? intval($movie_engine_design_options['archive_items_per_page']) : (!empty($movie_engine_design_options['movie_engine_archive_items_per_page']) ? intval($movie_engine_design_options['movie_engine_archive_items_per_page']) : 20);
        $reviews_per_page = max(1, $reviews_per_page);
        $pagination_type = $movie_engine_design_options['pagination_type'] ?? ($movie_engine_design_options['movie_engine_pagination_type'] ?? 'numbers');

        if ($reviews_per_page < 1) $reviews_per_page = 20;

        $offset = ($current_page - 1) * $reviews_per_page;

        $all_comments = get_comments([
            'post_id'      => $post_id,
            'status'       => 'approve',
            'number'       => $reviews_per_page,
            'offset'       => $offset,
            'orderby'      => [
                'comment_date' => 'DESC',
                'comment_ID'   => 'DESC'
            ],
            'hierarchical' => false,
        ]);

        $total_comments_count = wp_count_comments($post_id);
        $total_comments = $total_comments_count->approved;
        $total_pages = ceil($total_comments / $reviews_per_page);

        ob_start();
        if ($all_comments) {
            foreach ($all_comments as $comment) {
                $GLOBALS['comment'] = $comment;
            ?>
                <li class="movie-engine-review-item" data-debug-page="<?php echo esc_attr($current_page); ?>">
                    <div class="movie-engine-review-body">
                        <div class="movie-engine-review-author">
                            <?php echo get_avatar($comment, 50); ?>
                        </div>
                        <div class="movie-engine-review-content">
                            <div class="movie-engine-review-meta">
                                <div class="movie-engine-review-author-info">
                                    <cite class="fn"><?php echo esc_html(get_comment_author($comment)); ?></cite>
                                    <span class="movie-engine-review-date"><?php echo esc_html(get_comment_date('', $comment)); ?></span>
                                </div>
                                <div class="movie-engine-review-meta-right">
                                    <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- kses_post sanitizes HTML
                                    echo \MovieEngine\Utils\Helpers::kses_post(\MovieEngine\Frontend\Reviews::render_rating_html($comment)); ?>
                                </div>
                            </div>
                            <div class="movie-engine-comment-text">
                                <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- kses_post sanitizes HTML
                                echo \MovieEngine\Utils\Helpers::kses_post(get_comment_text($comment)); ?>
                            </div>
                        </div>
                    </div>
                </li>
<?php
            }
        }
        $html = ob_get_clean();

        $pagination_html = '';
        if ($total_pages > 1) {
            if ($pagination_type === 'load_more' || $pagination_type === 'infinite') {
                if ($current_page < $total_pages) {
                    $pagination_html .= '<div id="movie-engine-pagination-' . $post_id . '" class="movie-engine-pagination" data-type="' . esc_attr($pagination_type) . '" data-max-pages="' . esc_attr($total_pages) . '" data-paged="' . $current_page . '" data-total-comments="' . esc_attr($total_comments) . '">';
                    $pagination_html .= '<button class="movie-engine-load-more-btn movie-engine-btn movie-engine-btn-primary" data-paged="' . ($current_page + 1) . '" data-total-pages="' . esc_attr($total_pages) . '">' . esc_html__('Load More', 'cine-movie-engine') . '</button>';
                    if ($pagination_type === 'infinite') {
                        $pagination_html .= '<div class="movie-engine-infinite-trigger"></div>';
                    }
                    $pagination_html .= '</div>';
                }
            } else {
                $pagination_html = '<div class="movie-engine-pagination">';
                $pagination_html .= paginate_links(array(
                    'base'      => str_replace('999999999', '%#%', esc_url(add_query_arg(['reviews' => '999999999', 'post_id' => $post_id]))),
                    'format'    => '',
                    'current'   => $current_page,
                    'total'     => $total_pages,
                    'prev_text' => '&larr; ' . esc_html__('Previous', 'cine-movie-engine'),
                    'next_text' => esc_html__('Next', 'cine-movie-engine') . ' &rarr;',
                    'type'      => 'list',
                ));
                $pagination_html .= '</div>';
            }
        }

        wp_send_json_success([
            'html' => $html,
            'pagination' => $pagination_html,
            'max_pages' => $total_pages
        ]);
    }
}
