<?php

namespace App\Services\FileTools\VideoDescriptor;

use App\Services\FileTools\VideoDescriptor\IVideoDescriptor;
use Log;

abstract class AbstractLLMVideoDescriptor implements IVideoDescriptor
{
    public const MAX_FRAMES = 5;

    abstract public function getDescription(string $filePath): ?string;

    /**
     * Cut the video into screenshots.
     * Using ffmpeg to cut the video into screenshots at regular intervals.
     * The screenshots will be saved in a temporary directory.
     * @param string $filePath
     * @return array array with timestamps as key and screenshot file paths as values.
     */
    protected function cutVideoIntoScreenshots(string $filePath): array
    {
        $tempDir = sys_get_temp_dir() . '/video_screenshots';
        if (!is_dir($tempDir)) {
            mkdir($tempDir, 0777, true);
        }
        else {
            // Clear the directory if it already exists
            array_map('unlink', glob($tempDir . '/*'));
        }

        Log::info("Cutting video into screenshots: $filePath");

        $videoDuration = shell_exec("ffprobe -v error -show_entries format=duration -of csv=p=0 " . escapeshellarg($filePath));
        if ($videoDuration === null) {
            Log::error("Failed to get video duration for file: $filePath");
            return [];
        }
        $videoDuration = floatval($videoDuration);

        $framesInterval = ceil($videoDuration / self::MAX_FRAMES);
        $fps = 1/$framesInterval; // Frames per second for the screenshots

        $outputPattern = $tempDir . '/screenshot_%d.png';
        $command = "ffmpeg -i " . escapeshellarg($filePath) . " -vf fps={$fps} " . escapeshellarg($outputPattern);
        exec($command);

        // Collect all screenshots
        $screenshots = glob($tempDir . '/screenshot_*.png');
        $array = [];
        foreach ($screenshots as $screenshot) {
            $array[] = [
                "screenshot" => $screenshot,
                "timestamp" => floor(sizeof($array) * $framesInterval),
            ];
        }
        return $array;
    }

    /**
     * Extract audio from the video file.
     * Using ffmpeg to extract audio from the video file.
     * The audio will be saved in a temporary directory as an MP3 file.
     * If the audio extraction fails, it will return null.
     * @param string $filePath
     * @return string|null
     */
    protected function extractAudioFromVideo(string $filePath): ?string
    {
        $tempDir = sys_get_temp_dir() . '/video_audio';
        if (!is_dir($tempDir)) {
            mkdir($tempDir, 0777, true);
        }
        else {
            // Clear the directory if it already exists
            array_map('unlink', glob($tempDir . '/*'));
        }

        $outputFile = $tempDir . '/audio.mp3';
        $command = "ffmpeg -i " . escapeshellarg($filePath) . " " . escapeshellarg($outputFile);
        exec($command);

        if (file_exists($outputFile)) {
            return $outputFile;
        }
        return null;
    }
}
