<?php
if (!defined('ABSPATH')) exit;

/**
 * Video — AV1 WebM sidecar via ffmpeg (Pro, optional).
 */
class AIIO_Video_Optimizer {

    const VIDEO_MIMES = [
        'video/mp4',
        'video/webm',
        'video/quicktime',
        'video/x-msvideo',
        'video/ogg',
    ];

    public static function init() {
        add_action('add_attachment', [__CLASS__, 'maybe_auto_optimize'], 35);
    }

    public static function maybe_auto_optimize($attachment_id) {
        if (!self::is_enabled()) {
            return;
        }
        $s = aiio_get_settings();
        if (empty($s['auto_optimize_upload'])) {
            return;
        }
        if (!self::is_optimizable($attachment_id, $reason)) {
            return;
        }
        self::apply($attachment_id);
    }

    public static function is_enabled() {
        return !empty(aiio_get_settings()['video_av1_enabled']);
    }

    public static function is_video_attachment($attachment_id) {
        $attachment_id = (int) $attachment_id;
        if (!$attachment_id || get_post_type($attachment_id) !== 'attachment') {
            return false;
        }
        return in_array(get_post_mime_type($attachment_id), self::VIDEO_MIMES, true);
    }

    public static function is_optimizable($attachment_id, &$reason = '') {
        if (!self::is_video_attachment($attachment_id)) {
            $reason = __('Not a supported video file.', 'pewit-ai-image-optimizer');
            return false;
        }
        if (!self::is_enabled()) {
            $reason = __('Video AV1 sidecar is disabled in settings.', 'pewit-ai-image-optimizer');
            return false;
        }
        if (!self::find_ffmpeg()) {
            $reason = __('ffmpeg is not available on this server.', 'pewit-ai-image-optimizer');
            return false;
        }
        $file = get_attached_file($attachment_id);
        if (!$file || !is_file($file)) {
            $reason = __('Video file not found on disk.', 'pewit-ai-image-optimizer');
            return false;
        }
        return true;
    }

    public static function find_ffmpeg() {
        static $cached = null;
        if ($cached !== null) {
            return $cached ?: '';
        }

        $paths = apply_filters('aiio_ffmpeg_paths', [
            'ffmpeg',
            '/usr/bin/ffmpeg',
            '/usr/local/bin/ffmpeg',
            '/opt/homebrew/bin/ffmpeg',
        ]);

        foreach ($paths as $path) {
            if ($path === 'ffmpeg') {
                if (self::command_exists('ffmpeg')) {
                    $cached = 'ffmpeg';
                    return $cached;
                }
                continue;
            }
            if (is_executable($path)) {
                $cached = $path;
                return $cached;
            }
        }

        $cached = false;
        return '';
    }

    private static function command_exists($cmd) {
        $disabled = array_map('trim', explode(',', (string) ini_get('disable_functions')));
        if (in_array('shell_exec', $disabled, true)) {
            return false;
        }
        $out = @shell_exec('command -v ' . escapeshellarg($cmd) . ' 2>/dev/null');
        return is_string($out) && trim($out) !== '';
    }

    /**
     * @return array|WP_Error
     */
    public static function apply($attachment_id, $args = []) {
        if (!self::is_optimizable($attachment_id, $reason)) {
            return new WP_Error('aiio_video_not_optimizable', $reason);
        }

        $file = get_attached_file($attachment_id);
        $before = filesize($file);

        if (class_exists('AIIO_Backup') && empty($args['skip_backup'])) {
            $backup = AIIO_Backup::backup($attachment_id);
            if (is_wp_error($backup)) {
                return $backup;
            }
        }

        $sidecar = self::sidecar_path($file);
        $encoded = self::encode_av1_webm($file, $sidecar);
        if (is_wp_error($encoded)) {
            return $encoded;
        }

        $after_sidecar = is_file($sidecar) ? filesize($sidecar) : 0;
        self::store_sidecar_meta($attachment_id, $sidecar);

        update_post_meta($attachment_id, '_aiio_last_optimized', current_time('mysql'));
        update_post_meta($attachment_id, '_aiio_saved_bytes', max(0, $before - $after_sidecar));
        update_post_meta($attachment_id, '_aiio_video_optimized', 1);

        return [
            'attachment_id'  => (int) $attachment_id,
            'type'           => 'video',
            'before_bytes'   => $before,
            'sidecar_bytes'  => $after_sidecar,
            'saved_bytes'    => max(0, $before - $after_sidecar),
            'saved_percent'  => $before > 0 ? round((max(0, $before - $after_sidecar) / $before) * 100, 1) : 0,
            'av1_webm'       => [
                'path'  => $sidecar,
                'bytes' => $after_sidecar,
                'url'   => self::path_to_upload_url($sidecar),
            ],
        ];
    }

    public static function sidecar_path($source_file) {
        $base = preg_replace('/\.(mp4|webm|mov|avi|ogv|m4v)$/i', '', $source_file);
        if ($base === $source_file) {
            $base = $source_file;
        }
        return $base . '.av1.webm';
    }

    /**
     * @return true|WP_Error
     */
    private static function encode_av1_webm($input, $output) {
        $ffmpeg = self::find_ffmpeg();
        if (!$ffmpeg) {
            return new WP_Error('aiio_ffmpeg_missing', __('ffmpeg is not available on this server.', 'pewit-ai-image-optimizer'));
        }

        $crf = max(20, min(50, (int) (aiio_get_settings()['video_av1_crf'] ?? 32)));
        $input_q = escapeshellarg($input);
        $output_q = escapeshellarg($output);

        $codecs = [
            " -c:v libsvtav1 -crf {$crf} -preset 6 -an ",
            " -c:v libaom-av1 -crf {$crf} -cpu-used 6 -an ",
        ];

        $errors = [];
        foreach ($codecs as $codec_args) {
            $cmd = escapeshellcmd($ffmpeg) . ' -y -i ' . $input_q . $codec_args . $output_q . ' 2>&1';
            $disabled = array_map('trim', explode(',', (string) ini_get('disable_functions')));
            if (in_array('exec', $disabled, true)) {
                return new WP_Error('aiio_ffmpeg_exec', __('exec() is disabled — cannot run ffmpeg.', 'pewit-ai-image-optimizer'));
            }
            $output_lines = [];
            exec($cmd, $output_lines, $code);
            if ($code === 0 && is_file($output) && filesize($output) > 0) {
                return true;
            }
            $errors[] = implode("\n", array_slice($output_lines, -8));
        }

        return new WP_Error(
            'aiio_ffmpeg_failed',
            __('Could not encode AV1 WebM sidecar. Ensure ffmpeg is built with libsvtav1 or libaom-av1.', 'pewit-ai-image-optimizer'),
            ['log' => implode("\n---\n", $errors)]
        );
    }

    public static function store_sidecar_meta($attachment_id, $path) {
        update_post_meta($attachment_id, '_aiio_av1_webm_file', wp_normalize_path($path));
        update_post_meta($attachment_id, '_aiio_av1_webm_url', self::path_to_upload_url($path));
    }

    public static function path_to_upload_url($path) {
        $upload = wp_get_upload_dir();
        if (empty($upload['basedir']) || empty($upload['baseurl'])) {
            return '';
        }
        $rel = str_replace(wp_normalize_path($upload['basedir']), '', wp_normalize_path($path));
        return $upload['baseurl'] . str_replace('\\', '/', $rel);
    }

    public static function remove_sidecar($attachment_id) {
        $path = get_post_meta($attachment_id, '_aiio_av1_webm_file', true);
        if ($path && is_file($path)) {
            wp_delete_file($path);
        }
        delete_post_meta($attachment_id, '_aiio_av1_webm_file');
        delete_post_meta($attachment_id, '_aiio_av1_webm_url');
        delete_post_meta($attachment_id, '_aiio_video_optimized');
    }
}
