<?php
declare(strict_types=1);

namespace Help4BuilderSuite\Support;

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

final class VideoPlayer
{
    public const HLS_VERSION = '1.6.16';

    public static function registerAssets(): void
    {
        if (! wp_script_is('h4bs-hls', 'registered')) {
            wp_register_script(
                'h4bs-hls',
                H4BS_URL . 'assets/vendor/hls/hls.min.js',
                [],
                self::HLS_VERSION,
                true
            );
        }
        if (! wp_script_is('h4bs-lms-video', 'registered')) {
            wp_register_script(
                'h4bs-lms-video',
                H4BS_URL . 'assets/js/lms-video.js',
                [],
                H4BS_VERSION,
                true
            );
        }
    }

    public static function enqueueAssets(bool $needsHls): void
    {
        self::registerAssets();
        if ($needsHls) {
            wp_enqueue_script('h4bs-hls');
        }
        wp_enqueue_script('h4bs-lms-video');
    }

    /**
     * @param array<string, mixed> $args
     */
    public static function render(array $args): string
    {
        $primary = esc_url_raw((string) ($args['primary'] ?? ''));
        $hls = esc_url_raw((string) ($args['hls'] ?? ''));
        $fallbackVideo = esc_url_raw((string) ($args['fallback_video'] ?? ''));
        $poster = esc_url_raw((string) ($args['poster'] ?? ''));
        $fallbackImage = esc_url_raw((string) ($args['fallback_image'] ?? ''));
        if ($fallbackImage === '') {
            $fallbackImage = $poster;
        }
        if ($hls === '' && self::isHlsUrl($primary)) {
            $hls = $primary;
            $primary = '';
        }
        if ($primary === '' && $hls === '') {
            return '';
        }

        $autoplay = ! empty($args['autoplay']);
        $muted = $autoplay || ! empty($args['muted']);
        $controls = ! array_key_exists('controls', $args) || ! empty($args['controls']);
        $loop = ! empty($args['loop']);
        $preload = sanitize_key((string) ($args['preload'] ?? 'metadata'));
        if (! in_array($preload, ['none', 'metadata', 'auto'], true)) {
            $preload = 'metadata';
        }
        $title = sanitize_text_field((string) ($args['title'] ?? __('Video player', 'help4-builder-suite')));
        if ($title === '') {
            $title = __('Video player', 'help4-builder-suite');
        }
        $className = trim((string) ($args['class'] ?? 'h4bs-builder-video'));
        $className = implode(
            ' ',
            array_filter(
                array_map(
                    'sanitize_html_class',
                    preg_split('/\s+/', $className) ?: []
                )
            )
        );
        if ($className === '') {
            $className = 'h4bs-builder-video';
        }
        $height = max(180, min(1080, (int) ($args['height'] ?? 360)));
        $aspect = self::aspectRatio((string) ($args['aspect_ratio'] ?? '16:9'));

        self::enqueueAssets($hls !== '');

        $videoAttributes = [
            'class="' . esc_attr($className) . '"',
            'data-h4bs-video-player',
            'playsinline',
            'preload="' . esc_attr($preload) . '"',
            'aria-label="' . esc_attr($title) . '"',
        ];
        if ($hls !== '') {
            $videoAttributes[] = 'data-h4bs-hls="' . esc_url($hls) . '"';
        }
        if (! empty($args['legacy_lms'])) {
            $videoAttributes[] = 'data-h4bs-lms-video';
        }
        if ($primary !== '') {
            $videoAttributes[] = 'data-h4bs-primary-video="' . esc_url($primary) . '"';
        }
        if ($fallbackVideo !== '') {
            $videoAttributes[] = 'data-h4bs-fallback-video="' . esc_url($fallbackVideo) . '"';
            // Retain the original LMS attribute for addon integrations.
            $videoAttributes[] = 'data-h4bs-mp4="' . esc_url($fallbackVideo) . '"';
        }
        if ($fallbackImage !== '') {
            $videoAttributes[] = 'data-h4bs-fallback-image="' . esc_url($fallbackImage) . '"';
        }
        if ($poster !== '') {
            $videoAttributes[] = 'poster="' . esc_url($poster) . '"';
        }
        if ($controls) {
            $videoAttributes[] = 'controls';
        }
        if ($autoplay) {
            $videoAttributes[] = 'autoplay';
        }
        if ($muted) {
            $videoAttributes[] = 'muted';
        }
        if ($loop) {
            $videoAttributes[] = 'loop';
        }

        $downloadUrl = $fallbackVideo !== '' ? $fallbackVideo : ($primary !== '' ? $primary : $hls);
        $style = '--h4bs-video-aspect:' . $aspect . ';--h4bs-video-max-height:' . $height . 'px';
        $html = '<div class="h4bs-video-player-shell" data-h4bs-module="video" data-h4bs-skin="surface" style="' . esc_attr($style) . '">';
        $html .= '<video ' . implode(' ', $videoAttributes) . '>';
        if ($hls !== '') {
            $html .= '<source src="' . esc_url($hls) . '" type="application/vnd.apple.mpegurl">';
        }
        if ($primary !== '') {
            $html .= '<source src="' . esc_url($primary) . '" type="' . esc_attr(self::mimeType($primary)) . '">';
        }
        if ($fallbackVideo !== '' && $fallbackVideo !== $primary) {
            $html .= '<source src="' . esc_url($fallbackVideo) . '" type="' . esc_attr(self::mimeType($fallbackVideo)) . '">';
        }
        $html .= esc_html__('Your browser cannot play this video.', 'help4-builder-suite');
        $html .= '</video>';
        $html .= '<div class="h4bs-video-player-fallback" data-h4bs-video-fallback hidden>';
        if ($fallbackImage !== '') {
            $html .= '<img src="' . esc_url($fallbackImage) . '" alt="" loading="lazy">';
        }
        $html .= '<p role="status">' . esc_html__('Video playback is unavailable.', 'help4-builder-suite') . '</p>';
        if ($downloadUrl !== '') {
            $html .= '<a href="' . esc_url($downloadUrl) . '" target="_blank" rel="noopener">'
                . esc_html__('Open the fallback video', 'help4-builder-suite')
                . '</a>';
        }
        $html .= '</div>';
        if ($downloadUrl !== '') {
            $html .= '<noscript><p><a href="' . esc_url($downloadUrl) . '">'
                . esc_html__('Open the video', 'help4-builder-suite')
                . '</a></p></noscript>';
        }
        $html .= '</div>';

        return $html;
    }

    /**
     * Render a layered Section/Container background using the shared HLS runtime.
     *
     * @param array<string, mixed> $args
     */
    public static function renderBackground(array $args): string
    {
        $primary = esc_url_raw((string) ($args['primary'] ?? ''));
        $hls = esc_url_raw((string) ($args['hls'] ?? ''));
        $fallbackVideo = esc_url_raw((string) ($args['fallback_video'] ?? ''));
        $poster = esc_url_raw((string) ($args['poster'] ?? ''));
        $fallbackImage = esc_url_raw((string) ($args['fallback_image'] ?? ''));
        if ($fallbackImage === '') {
            $fallbackImage = $poster;
        }
        if ($hls === '' && self::isHlsUrl($primary)) {
            $hls = $primary;
            $primary = '';
        }
        if ($primary === '' && $hls === '' && $fallbackVideo === '') {
            return '';
        }

        $autoplay = ! empty($args['autoplay']);
        $muted = $autoplay || ! empty($args['muted']);
        $decorative = ! array_key_exists('decorative', $args) || ! empty($args['decorative']);
        $controls = ! $decorative && ! empty($args['controls']);
        $loop = ! empty($args['loop']);
        $preload = sanitize_key((string) ($args['preload'] ?? 'metadata'));
        if (! in_array($preload, ['none', 'metadata', 'auto'], true)) {
            $preload = 'metadata';
        }
        $fit = sanitize_key((string) ($args['fit'] ?? 'cover'));
        if (! in_array($fit, ['cover', 'contain'], true)) {
            $fit = 'cover';
        }
        $position = self::focalPosition((string) ($args['position'] ?? 'center center'));
        $positionTablet = self::focalPosition((string) ($args['position_tablet'] ?? $position));
        $positionMobile = self::focalPosition((string) ($args['position_mobile'] ?? $positionTablet));
        $overflow = sanitize_key((string) ($args['overflow'] ?? 'hidden'));
        if (! in_array($overflow, ['hidden', 'clip'], true)) {
            $overflow = 'hidden';
        }
        $overlayColor = sanitize_hex_color((string) ($args['overlay_color'] ?? '#000000'));
        $overlayColor = is_string($overlayColor) && $overlayColor !== '' ? $overlayColor : '#000000';
        $overlayOpacity = max(0, min(1, (float) ($args['overlay_opacity'] ?? 0)));
        $overlayGradient = self::safeGradient((string) ($args['overlay_gradient'] ?? ''));
        $title = sanitize_text_field((string) ($args['title'] ?? __('Background video', 'help4-builder-suite')));
        if ($title === '') {
            $title = __('Background video', 'help4-builder-suite');
        }

        self::enqueueAssets($hls !== '');

        $videoAttributes = [
            'class="h4bs-background-video"',
            'data-h4bs-video-player',
            'playsinline',
            'preload="' . esc_attr($preload) . '"',
        ];
        if ($decorative) {
            $videoAttributes[] = 'aria-hidden="true"';
            $videoAttributes[] = 'tabindex="-1"';
        } else {
            $videoAttributes[] = 'aria-label="' . esc_attr($title) . '"';
        }
        if ($hls !== '') {
            $videoAttributes[] = 'data-h4bs-hls="' . esc_url($hls) . '"';
        }
        if ($primary !== '') {
            $videoAttributes[] = 'data-h4bs-primary-video="' . esc_url($primary) . '"';
        }
        if ($fallbackVideo !== '') {
            $videoAttributes[] = 'data-h4bs-fallback-video="' . esc_url($fallbackVideo) . '"';
            $videoAttributes[] = 'data-h4bs-mp4="' . esc_url($fallbackVideo) . '"';
        }
        if ($fallbackImage !== '') {
            $videoAttributes[] = 'data-h4bs-fallback-image="' . esc_url($fallbackImage) . '"';
        }
        if ($poster !== '') {
            $videoAttributes[] = 'poster="' . esc_url($poster) . '"';
        }
        if ($controls) {
            $videoAttributes[] = 'controls';
        }
        if ($autoplay) {
            $videoAttributes[] = 'autoplay';
        }
        if ($muted) {
            $videoAttributes[] = 'muted';
        }
        if ($loop) {
            $videoAttributes[] = 'loop';
        }

        $style = implode(';', [
            '--h4bs-background-video-fit:' . $fit,
            '--h4bs-background-video-position:' . $position,
            '--h4bs-background-video-position-tablet:' . $positionTablet,
            '--h4bs-background-video-position-mobile:' . $positionMobile,
            '--h4bs-background-video-overflow:' . $overflow,
            '--h4bs-background-video-overlay-color:' . $overlayColor,
            '--h4bs-background-video-overlay-opacity:' . (string) $overlayOpacity,
            '--h4bs-background-video-overlay-gradient:' . ($overlayGradient !== '' ? $overlayGradient : 'none'),
        ]);
        $html = '<div class="h4bs-background-video-layer' . ($controls ? ' has-controls' : '') . '" data-h4bs-background-video style="' . esc_attr($style) . '">';
        $html .= '<video ' . implode(' ', $videoAttributes) . '>';
        if ($hls !== '') {
            $html .= '<source src="' . esc_url($hls) . '" type="application/vnd.apple.mpegurl">';
        }
        if ($primary !== '') {
            $html .= '<source src="' . esc_url($primary) . '" type="' . esc_attr(self::mimeType($primary)) . '">';
        }
        if ($fallbackVideo !== '' && $fallbackVideo !== $primary) {
            $html .= '<source src="' . esc_url($fallbackVideo) . '" type="' . esc_attr(self::mimeType($fallbackVideo)) . '">';
        }
        $html .= '</video>';
        $html .= '<div class="h4bs-background-video-fallback" data-h4bs-video-fallback hidden>';
        if ($fallbackImage !== '') {
            $html .= '<img src="' . esc_url($fallbackImage) . '" alt="">';
        }
        $html .= '</div>';
        $html .= '<span class="h4bs-background-video-overlay" aria-hidden="true"></span>';
        $html .= '</div>';

        return $html;
    }

    private static function isHlsUrl(string $url): bool
    {
        $path = (string) wp_parse_url($url, PHP_URL_PATH);
        return preg_match('/\.m3u8?$/i', $path) === 1;
    }

    private static function mimeType(string $url): string
    {
        $path = strtolower((string) wp_parse_url($url, PHP_URL_PATH));
        if (str_ends_with($path, '.webm')) {
            return 'video/webm';
        }
        if (str_ends_with($path, '.ogv') || str_ends_with($path, '.ogg')) {
            return 'video/ogg';
        }
        if (str_ends_with($path, '.m4v')) {
            return 'video/x-m4v';
        }
        return 'video/mp4';
    }

    private static function aspectRatio(string $ratio): string
    {
        $ratios = [
            '16:9' => '16 / 9',
            '4:3' => '4 / 3',
            '1:1' => '1 / 1',
            '9:16' => '9 / 16',
            '21:9' => '21 / 9',
        ];
        return $ratios[$ratio] ?? $ratios['16:9'];
    }

    private static function focalPosition(string $position): string
    {
        $position = strtolower(trim($position));
        if (
            $position === ''
            || preg_match('/^(?:(?:left|center|right|top|bottom)|(?:\d{1,3}(?:\.\d+)?%))(?:\s+(?:(?:left|center|right|top|bottom)|(?:\d{1,3}(?:\.\d+)?%)))?$/', $position) !== 1
        ) {
            return 'center center';
        }
        return $position;
    }

    private static function safeGradient(string $gradient): string
    {
        $gradient = trim(wp_strip_all_tags($gradient));
        if (
            $gradient === ''
            || strlen($gradient) > 600
            || preg_match('/^(?:repeating-)?(?:linear|radial|conic)-gradient\([#(),.%\sa-zA-Z0-9-]+\)$/', $gradient) !== 1
        ) {
            return '';
        }
        return $gradient;
    }
}
