<?php
declare(strict_types=1);

namespace App\Lib;

use Aws\S3\S3Client;
use Aws\MediaConvert\MediaConvertClient;
use Aws\Exception\AwsException;
use Aws\S3\Exception\S3Exception;
use App\Lib\Ffmpeg;
use App\Lib\Utility;
use Aws\S3\S3Client;
use Cake\Utility\Text;

require_once ROOT . DS . 'vendor' . DS . 'autoload.php';

class Regular
{
	public static function local_video_upload(int $user_id, string $param, array $sound_details, array $video_details, mixed $duet): array
	{
		$self = new self();
		$original_video_file_path = $self->uploadOriginalVideoFileIntoTemporaryFolder($param, $user_id);
		if (!$original_video_file_path) {
			$error = [
				'code' => 201,
				'msg' => 'Something went wrong in uploading file into the folder. Check your max upload size or check if fileupload is On in your php.ini file'
			];
			echo json_encode($error);
			exit();
		}

		$video_black = $self->addBlackBackgroundInTheVideo($original_video_file_path);
		$final_video = (filesize($video_black) > 0) ? $video_black : $original_video_file_path;

		if (!empty($video_details)) {
			$original_video_file_path = $self->duet($final_video, $video_details['Video']['video'], $duet);
			$final_video = $original_video_file_path;
		}

		$gif = $self->videoToGif($original_video_file_path, $user_id);
		$thumb = $self->videoToThumb($original_video_file_path, $user_id);

		if (empty($sound_details)) {
			$mp3_file = $self->convertVideoToAudio($final_video, $user_id);
			$mp3_file_name = $mp3_file ? "audio/" . basename($mp3_file) : "";
			$output['audio'] = $mp3_file_name;
			$final_video_file_path = $final_video;
		} else {
			$video_path_with_audio = $self->mergeVideoWithSound($user_id, $final_video, $sound_details['Sound']['audio']);
			$output['audio'] = "";
			$final_video_file_path = $video_path_with_audio;
		}

		$final_output = [
			'audio' => $mp3_file ?? "",
			'video' => $final_video_file_path,
			'gif' => $gif,
			'thum' => $thumb
		];

		$self->unlinkFile($original_video_file_path);
		return $final_output;
	}

	public static function unlinkFile(string $file_path): bool
	{
		if (file_exists($file_path)) {
			unlink($file_path);
		}
		return true;
	}

	public function uploadOriginalVideoFileIntoTemporaryFolder(string $param, int $user_id): string|false
	{
		$fileName = uniqid((string) $user_id, true);
		$folder = UPLOADS_FOLDER_URI;

		if (!file_exists($folder)) {
			mkdir($folder, 0777, true);
		}

		$ext = match ($param) {
			'image' => '.png',
			'video' => '.mp4',
			'audio' => '.mp3',
			default => ''
		};

		$filePath = $folder . "/" . $fileName . $ext;

		return move_uploaded_file($_FILES[$param]['tmp_name'], $filePath) ? $filePath : false;
	}

	public static function multipartFileUpload(int $user_id, string $param, array $sound_details): array
	{
		$self = new self();
		$original_video_file_path = $self->uploadOriginalVideoFileIntoTemporaryFolder($param, $user_id);
		$gif = $self->videoToGif($original_video_file_path, $user_id);
		$thumb = $self->videoToThumb($original_video_file_path, $user_id);

		if (empty($sound_details)) {
			$mp3_file = $self->convertVideoToAudio($original_video_file_path, $user_id);
			$output['audio'] = $mp3_file;
		} else {
			$video_path_with_audio = $self->mergeVideoWithSound($user_id, $original_video_file_path, $sound_details['Sound']['audio']);
			$output['audio'] = $video_path_with_audio;
		}

		$optimized_file_path = $self->optimizeVideoSize($original_video_file_path);
		$final_video = $self->addBlackBackgroundInTheVideo($optimized_file_path);

		$output['video'] = $final_video;
		$output['thum'] = $thumb;
		$output['gif'] = $gif;
		$output['error'] = 0;

		unlink($original_video_file_path);
		return $output;
	}

	public function optimizeVideoSize(string $original_video_path): string
	{
		$without_extension_file_name = pathinfo($original_video_path, PATHINFO_FILENAME);
		$dir = dirname($original_video_path);
		$optimizeResultFile = "$dir/{$without_extension_file_name}_optimize.mp4";
		$cmd_new = "ffmpeg -i \"$original_video_path\" -c:v libx264 -crf 28 \"$optimizeResultFile\"";
		exec($cmd_new);
		return $optimizeResultFile;
	}

	public function addBlackBackgroundInTheVideo(string $optimizeResultFile): string
	{
		$without_extension_file_name = pathinfo($optimizeResultFile, PATHINFO_FILENAME);
		$dir = dirname($optimizeResultFile);
		$black_background = "$dir/{$without_extension_file_name}black.mp4";
		$cmd = "ffmpeg -i \"$optimizeResultFile\" -vf 'scale=720:1280:force_original_aspect_ratio=decrease,pad=720:1280:(ow-iw)/2:(oh-ih)/2,setsar=1' \"$black_background\"";
		exec($cmd);
		return $black_background;
	}

	public function convertVideoToAudio(string $original_video_file_path, int $user_id): ?string
	{
		$fileName = uniqid((string) $user_id, true);
		$folder = UPLOADS_FOLDER_URI . '/audio/';
		$mp3_file = $folder . $fileName . ".mp3";

		if (!file_exists($folder)) {
			mkdir($folder, 0777, true);
		}

		$cmd = "ffprobe -i \"$original_video_file_path\" -show_streams -select_streams a -loglevel error";
		exec($cmd, $output);

		if (!empty($output)) {
			$cmd_new = "ffmpeg -i \"$original_video_file_path\" -b:a 192K -vn \"$mp3_file\"";
			exec($cmd_new);
			return $mp3_file;
		}

		return null;
	}

	public function videoToGif(string $original_video_file_path, int $user_id): string
	{
		$fileName = uniqid((string) $user_id, true);
		$folder = UPLOADS_FOLDER_URI . '/gif/';
		$genrateGifPath = $folder . $fileName . ".gif";

		if (!file_exists($folder)) {
			mkdir($folder, 0777, true);
		}

		$gif = "ffmpeg -ss 3 -t 2 -i \"$original_video_file_path\" -vf 'fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse' -loop 0 \"$genrateGifPath\"";
		exec($gif);
		return $genrateGifPath;
	}

	public function videoToThumb(string $original_video_file_path, int $user_id): string
	{
		$without_extension_file_name = pathinfo($original_video_file_path, PATHINFO_FILENAME);
		$dir = dirname($original_video_file_path);
		$thumb_path = "$dir/{$without_extension_file_name}thumb.png";
		$thumb_cmd = "ffmpeg -i \"$original_video_file_path\" -vf fps=3 \"$thumb_path\"";
		exec($thumb_cmd);
		return $thumb_path;
	}

	public static function duet(string $video1_path, string $video2_path, mixed $duet): string
	{
		$without_extension_file_name = pathinfo($video1_path, PATHINFO_FILENAME);
		$dir = dirname($video1_path);
		$duetMergePathOutput = "$dir/{$without_extension_file_name}duet.mp4";
		$cmd = "ffmpeg -i \"$video1_path\" -i \"$video2_path\" -filter_complex '[0:v]pad=iw*2:ih[int];[int][1:v]overlay=W/2:0[vid]' -map '[vid]' -c:v libx264 -crf 23 -preset veryfast \"$duetMergePathOutput\"";
		exec($cmd);
		return $duetMergePathOutput;
	}

	public function mergeVideoWithSound(int $user_id, string $video_path, string $audio): string
	{
		$fileName = uniqid((string) $user_id, true);
		$folder = UPLOADS_FOLDER_URI . '/' . $user_id;
		$with_new_audio = $folder . $fileName . "audio.mp4";

		if (!file_exists($folder)) {
			mkdir($folder, 0777, true);
		}

		$cmd = "ffprobe -i \"$video_path\" -show_streams -select_streams a -loglevel error";
		exec($cmd, $if_audio_exist);

		if (!empty($if_audio_exist)) {
			$cmd_new = "ffmpeg -i \"$video_path\" -i \"$audio\" -c:v copy -c:a aac -shortest -map 0:v:0 -map 1:a:0 \"$with_new_audio\"";
		} else {
			$cmd_new = "ffmpeg -i \"$video_path\" -i \"$audio\" -c:v copy -c:a aac -shortest \"$with_new_audio\"";
		}

		exec($cmd_new);
		return $with_new_audio;
	}
}
