<?php

namespace MovieEngine\Api;

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

use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use MovieEngine\Frontend\Player;

class Stream_Controller extends WP_REST_Controller {

    public function __construct() {
        $this->namespace = 'movie-engine/v1';
        $this->rest_base = 'stream';
    }

    public function register_routes() {
        register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [$this, 'stream_video'],
                'permission_callback' => '__return_true',
                'args'                => [
                    'index' => [
                        'default' => 0,
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ],
        ]);
        register_rest_route($this->namespace, '/subtitle/(?P<id>[\d]+)/(?P<index>[\d]+)', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [$this, 'stream_subtitle'],
                'permission_callback' => '__return_true',
            ],
        ]);
    }

    public function stream_video($request) {
        $post_id = absint($request['id']);
        $server_index = absint($request['index']);

        $player_settings = get_option('movie_engine_player_settings', []);
        $secure_tokens = !empty($player_settings['movie_engine_secure_tokens']) || !empty($player_settings['secure_tokens']);

        $referer = isset($_SERVER['HTTP_REFERER']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_REFERER'])) : '';
        $site_url = site_url();
        $parsed_site = wp_parse_url($site_url);
        $host = $parsed_site['host'] ?? '';
        $origin = isset($_SERVER['HTTP_ORIGIN']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_ORIGIN'])) : '';

        $is_same_origin = (!empty($referer) && strpos($referer, $host) !== false)
            || (!empty($origin) && strpos($origin, $host) !== false);

        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
            header('Access-Control-Allow-Origin: *');
            header('Access-Control-Allow-Methods: GET, OPTIONS');
            header('Access-Control-Allow-Headers: Authorization, Content-Type, X-WP-Nonce');
            exit;
        }

        if (!$is_same_origin) {
            return new \WP_Error('forbidden', __('This video can only be played on our website.', 'cine-movie-engine'), ['status' => 403]);
        }

        $nonce = $request->get_param('_wpnonce');
        if (!wp_verify_nonce($nonce, 'wp_rest')) {
            return new \WP_Error('forbidden', 'Invalid security token', ['status' => 403]);
        }

        $sources = get_post_meta($post_id, '_movie_engine_sources', true);

        if (empty($sources) || !is_array($sources) || !isset($sources[$server_index])) {
            return new \WP_Error('not_found', 'Video source not found', ['status' => 404]);
        }

        $video_url = esc_url_raw($sources[$server_index]['url']);
        if (empty($video_url)) {
            return new \WP_Error('not_found', 'Video URL is empty', ['status' => 404]);
        }

        if (strpos($video_url, '<iframe') !== false || strpos($video_url, 'youtube.com') !== false) {
            $video_host = wp_parse_url($video_url, PHP_URL_HOST);
            if ($video_host) {
                add_filter('allowed_redirect_hosts', function ($hosts) use ($video_host) {
                    $hosts[] = $video_host;
                    return $hosts;
                });
            }
            wp_safe_redirect($video_url);
            exit;
        }

        if ($secure_tokens) {
            $video_url = $this->add_signed_token($video_url, $post_id);
        }

        if (preg_match('/\.m3u8($|\?)/', $video_url) || (strpos($video_url, 'm3u8') !== false && strpos($video_url, '.mp4') === false)) {
            $response = wp_remote_get($video_url, [
                'timeout' => 15,
                'sslverify' => false,
                'headers' => [
                    'User-Agent' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : 'Mozilla/5.0'
                ]
            ]);

            if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
                $content = wp_remote_retrieve_body($response);

                $url_parts = wp_parse_url($video_url);
                $host_url = $url_parts['scheme'] . '://' . $url_parts['host'] . (isset($url_parts['port']) ? ':' . $url_parts['port'] : '');

                $path = $url_parts['path'] ?? '/';
                $last_slash_pos = strrpos($path, '/');
                $base_path = ($last_slash_pos !== false) ? substr($path, 0, $last_slash_pos + 1) : '/';
                $base_url = $host_url . $base_path;

                $content = str_replace("\r\n", "\n", $content);
                $lines = explode("\n", $content);
                $new_content = "";

                foreach ($lines as $line) {
                    $line = trim($line);
                    if (empty($line)) continue;

                    if (strpos($line, '#') === 0) {
                        if (preg_match('/(URI|KEYURI|LICENSE-URL)=["\']?([^"\',]+)["\']?/', $line, $matches)) {
                            $uri = $matches[2];
                            if (strpos($uri, 'http') !== 0) {
                                $absolute_uri = (strpos($uri, '/') === 0) ? $host_url . $uri : $base_url . $uri;
                                $line = str_replace($uri, $absolute_uri, $line);
                            }
                        }
                    } else {
                        if (strpos($line, 'http') !== 0) {
                            $line = (strpos($line, '/') === 0) ? $host_url . $line : $base_url . $line;
                        }
                    }
                    $new_content .= $line . "\n";
                }

                header('Content-Type: application/vnd.apple.mpegurl');
                header('Access-Control-Allow-Origin: *');
                header('Cache-Control: no-cache, no-store, must-revalidate');
                echo $new_content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
                exit;
            }
        }

        $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']);
        $is_direct_file = (strpos($video_url, '.mp4') !== false || strpos($video_url, '.webm') !== false || strpos($video_url, '.ogg') !== false);

        if ($hide_video_url && $is_direct_file) {
            $this->stream_proxy_chunked($video_url);
            return;
        }

        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: GET, OPTIONS');

        $video_host = wp_parse_url($video_url, PHP_URL_HOST);
        if ($video_host) {
            add_filter('allowed_redirect_hosts', function ($hosts) use ($video_host) {
                $hosts[] = $video_host;
                return $hosts;
            });
        }

        wp_safe_redirect($video_url);
        exit;
    }

    private function stream_proxy_chunked($video_url) {
        $range_header = isset($_SERVER['HTTP_RANGE']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_RANGE'])) : '';
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : 'Mozilla/5.0';

        // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_init
        $ch = curl_init($video_url);
        if ($ch === false) {
            status_header(502);
            exit;
        }

        $response_headers = [];
        $headers_sent = false;

        // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt_array
        curl_setopt_array($ch, [
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 3,
            CURLOPT_TIMEOUT => 300,
            CURLOPT_CONNECTTIMEOUT => 15,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_USERAGENT => $user_agent,
            CURLOPT_HEADERFUNCTION => function ($curl, $header_line) use (&$response_headers) {
                $len = strlen($header_line);
                $header_line = trim($header_line);
                if ($header_line === '') {
                    return $len;
                }
                if (stripos($header_line, 'HTTP/') === 0) {
                    $response_headers['status'] = $header_line;
                    return $len;
                }
                $parts = explode(':', $header_line, 2);
                if (count($parts) === 2) {
                    $name = strtolower(trim($parts[0]));
                    $value = trim($parts[1]);
                    $response_headers[$name] = $value;
                }
                return $len;
            },
            CURLOPT_WRITEFUNCTION => function ($curl, $chunk) use (&$headers_sent, &$response_headers) {
                if (!$headers_sent) {
                    $headers_sent = true;
                    header('Access-Control-Allow-Origin: *');
                    header('Access-Control-Allow-Methods: GET, HEAD, OPTIONS');
                    header('Accept-Ranges: bytes');
                    if (!empty($response_headers['status'])) {
                        if (preg_match('/\d{3}/', $response_headers['status'], $m)) {
                            status_header((int) $m[0]);
                        }
                    }
                    foreach (['content-type', 'content-length', 'content-range', 'accept-ranges'] as $key) {
                        if (!empty($response_headers[$key])) {
                            header($key . ': ' . $response_headers[$key]);
                        }
                    }
                }
                echo $chunk; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
                if (ob_get_level()) {
                    ob_flush();
                }
                flush();
                return strlen($chunk);
            },
        ]);

        if ($range_header) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt
            curl_setopt($ch, CURLOPT_HTTPHEADER, ['Range: ' . $range_header]);
        }

        // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_exec
        curl_exec($ch);
        // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_errno
        $err = curl_errno($ch);
        // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_close
        curl_close($ch);

        if (!$headers_sent) {
            header('Access-Control-Allow-Origin: *');
            header('Access-Control-Allow-Methods: GET, HEAD, OPTIONS');
            if ($err) {
                status_header(502);
            } elseif (!empty($response_headers['status']) && preg_match('/\d{3}/', $response_headers['status'], $m)) {
                status_header((int) $m[0]);
                header('Accept-Ranges: bytes');
                foreach (['content-type', 'content-length', 'content-range', 'accept-ranges'] as $key) {
                    if (!empty($response_headers[$key])) {
                        header($key . ': ' . $response_headers[$key]);
                    }
                }
            }
        }
        exit;
    }

    /**
     * Proxy subtitle (VTT) so external URLs are served from same origin (avoids cross-origin block).
     */
    public function stream_subtitle($request) {
        $post_id = absint($request['id']);
        $index   = absint($request['index']);

        $nonce = $request->get_param('_wpnonce');
        if (! $nonce || ! wp_verify_nonce($nonce, 'wp_rest')) {
            return new \WP_Error('forbidden', __('Invalid security token.', 'cine-movie-engine'), ['status' => 403]);
        }

        $subtitles = get_post_meta($post_id, '_movie_engine_subtitles', true);
        if (empty($subtitles) || ! is_array($subtitles) || ! isset($subtitles[$index]) || empty($subtitles[$index]['src'])) {
            return new \WP_Error('not_found', __('Subtitle not found.', 'cine-movie-engine'), ['status' => 404]);
        }

        $subtitle_url = esc_url_raw($subtitles[$index]['src']);
        if (empty($subtitle_url)) {
            return new \WP_Error('not_found', __('Subtitle URL is empty.', 'cine-movie-engine'), ['status' => 404]);
        }

        $response = wp_remote_get($subtitle_url, [
            'timeout'   => 15,
            'sslverify' => false,
            'headers'   => [
                'User-Agent' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : 'Mozilla/5.0',
            ],
        ]);

        if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
            return new \WP_Error('proxy_error', __('Could not load subtitle.', 'cine-movie-engine'), ['status' => 502]);
        }

        $body = wp_remote_retrieve_body($response);
        header('Content-Type: text/vtt; charset=utf-8');
        header('Access-Control-Allow-Origin: *');
        header('Cache-Control: public, max-age=3600');
        echo $body; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        exit;
    }

    private function add_signed_token($url, $post_id) {
        $expires = time() + (2 * 60 * 60);
        $ip = $this->get_client_ip();
        $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() {
        $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);
    }
}
