<?php
/**
 * Video Upload Handler
 *
 * Handles chunked video uploads and forwards to Video-Service.
 *
 * @package KursBooking
 * @since   1.3.0
 */

declare(strict_types=1);

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class Kurs_Booking_Video_Upload
 *
 * Handles video upload processing via AJAX.
 */
class Kurs_Booking_Video_Upload {

	/**
	 * Temp directory for chunked uploads
	 */
	private const TEMP_DIR = 'kurs-booking-video-uploads';

	/**
	 * Allowed MIME types
	 */
	private const ALLOWED_TYPES = array(
		'video/mp4',
		'video/quicktime',
		'video/x-msvideo',
		'video/x-matroska',
	);

	/**
	 * Max file size (2GB)
	 */
	private const MAX_FILE_SIZE = 2147483648;

	/**
	 * Initialize upload handlers
	 */
	public static function init(): void {
		// AJAX handlers.
		add_action( 'wp_ajax_kurs_video_upload_chunk', array( __CLASS__, 'handle_chunk_upload' ) );
		add_action( 'wp_ajax_kurs_video_upload_complete', array( __CLASS__, 'handle_upload_complete' ) );
		add_action( 'wp_ajax_kurs_video_upload_cancel', array( __CLASS__, 'handle_upload_cancel' ) );

		// Cleanup old temp files daily.
		add_action( 'kurs_booking_cleanup_temp_uploads', array( __CLASS__, 'cleanup_temp_files' ) );
		if ( ! wp_next_scheduled( 'kurs_booking_cleanup_temp_uploads' ) ) {
			wp_schedule_event( time(), 'daily', 'kurs_booking_cleanup_temp_uploads' );
		}
	}

	/**
	 * Handle chunk upload
	 */
	public static function handle_chunk_upload(): void {
		// Verify nonce.
		if ( ! check_ajax_referer( 'kurs_video_upload', 'nonce', false ) ) {
			wp_send_json_error( array( 'message' => __( 'Sicherheitspruefung fehlgeschlagen.', 'kurs-booking' ) ), 403 );
		}

		// Check permissions.
		if ( ! current_user_can( 'upload_kurs_videos' ) ) {
			wp_send_json_error( array( 'message' => __( 'Keine Berechtigung.', 'kurs-booking' ) ), 403 );
		}

		// Validate required fields.
		$upload_id    = isset( $_POST['upload_id'] ) ? sanitize_text_field( wp_unslash( $_POST['upload_id'] ) ) : '';
		$chunk_index  = isset( $_POST['chunk_index'] ) ? absint( $_POST['chunk_index'] ) : 0;
		$total_chunks = isset( $_POST['total_chunks'] ) ? absint( $_POST['total_chunks'] ) : 0;
		$filename     = isset( $_POST['filename'] ) ? sanitize_file_name( wp_unslash( $_POST['filename'] ) ) : '';

		if ( empty( $upload_id ) || empty( $filename ) || $total_chunks < 1 ) {
			wp_send_json_error( array( 'message' => __( 'Ungueltige Upload-Parameter.', 'kurs-booking' ) ), 400 );
		}

		// Check file.
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- $_FILES tmp_name is validated by is_uploaded_file() and sanitized by move_uploaded_file().
		if ( ! isset( $_FILES['chunk']['tmp_name'] ) || ! is_uploaded_file( $_FILES['chunk']['tmp_name'] ) ) {
			wp_send_json_error( array( 'message' => __( 'Keine Chunk-Daten empfangen.', 'kurs-booking' ) ), 400 );
		}

		// Validate file extension.
		$ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
		if ( ! in_array( $ext, array( 'mp4', 'mov', 'avi', 'mkv' ), true ) ) {
			wp_send_json_error( array( 'message' => __( 'Ungueltige Dateiendung.', 'kurs-booking' ) ), 400 );
		}

		// Get temp directory.
		$temp_dir = self::get_temp_dir( $upload_id );
		if ( ! $temp_dir ) {
			wp_send_json_error( array( 'message' => __( 'Temp-Verzeichnis konnte nicht erstellt werden.', 'kurs-booking' ) ), 500 );
		}

		// Save chunk.
		$chunk_file = $temp_dir . '/chunk_' . str_pad( (string) $chunk_index, 5, '0', STR_PAD_LEFT );

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_move_uploaded_file,WordPress.Security.ValidatedSanitizedInput.InputNotValidated,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- $_FILES tmp_name validated above, sanitized by move_uploaded_file().
		if ( ! move_uploaded_file( $_FILES['chunk']['tmp_name'], $chunk_file ) ) {
			wp_send_json_error( array( 'message' => __( 'Chunk konnte nicht gespeichert werden.', 'kurs-booking' ) ), 500 );
		}

		// Save metadata.
		$meta_file = $temp_dir . '/meta.json';
		$meta      = array(
			'filename'     => $filename,
			'total_chunks' => $total_chunks,
			'created_at'   => time(),
			'user_id'      => get_current_user_id(),
		);
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
		file_put_contents( $meta_file, wp_json_encode( $meta ) );

		// Count received chunks.
		$chunks_received = count( glob( $temp_dir . '/chunk_*' ) );

		wp_send_json_success(
			array(
				'chunk_index'     => $chunk_index,
				'chunks_received' => $chunks_received,
				'total_chunks'    => $total_chunks,
			)
		);
	}

	/**
	 * Handle upload completion - combine chunks and send to video service
	 */
	public static function handle_upload_complete(): void {
		// Verify nonce.
		if ( ! check_ajax_referer( 'kurs_video_upload', 'nonce', false ) ) {
			wp_send_json_error( array( 'message' => __( 'Sicherheitspruefung fehlgeschlagen.', 'kurs-booking' ) ), 403 );
		}

		// Check permissions.
		if ( ! current_user_can( 'upload_kurs_videos' ) ) {
			wp_send_json_error( array( 'message' => __( 'Keine Berechtigung.', 'kurs-booking' ) ), 403 );
		}

		$upload_id = isset( $_POST['upload_id'] ) ? sanitize_text_field( wp_unslash( $_POST['upload_id'] ) ) : '';
		$kurs_id   = isset( $_POST['kurs_id'] ) ? absint( $_POST['kurs_id'] ) : 0;
		$title     = isset( $_POST['title'] ) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : '';

		if ( empty( $upload_id ) ) {
			wp_send_json_error( array( 'message' => __( 'Upload-ID fehlt.', 'kurs-booking' ) ), 400 );
		}

		// Get temp directory.
		$temp_dir = self::get_temp_dir( $upload_id, false );
		if ( ! $temp_dir || ! is_dir( $temp_dir ) ) {
			wp_send_json_error( array( 'message' => __( 'Upload-Daten nicht gefunden.', 'kurs-booking' ) ), 404 );
		}

		// Read metadata.
		$meta_file = $temp_dir . '/meta.json';
		if ( ! file_exists( $meta_file ) ) {
			wp_send_json_error( array( 'message' => __( 'Upload-Metadaten nicht gefunden.', 'kurs-booking' ) ), 404 );
		}

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
		$meta = json_decode( file_get_contents( $meta_file ), true );

		// Verify all chunks received.
		$chunks = glob( $temp_dir . '/chunk_*' );
		sort( $chunks, SORT_NATURAL );

		if ( count( $chunks ) !== $meta['total_chunks'] ) {
			wp_send_json_error(
				array(
					'message' => sprintf(
					 /* translators: 1: received chunks, 2: total chunks */
						__( 'Nicht alle Chunks empfangen (%1$d von %2$d).', 'kurs-booking' ),
						count( $chunks ),
						$meta['total_chunks']
					),
				),
				400
			);
		}

		// Combine chunks into final file.
		$filename   = $meta['filename'];
		$final_file = $temp_dir . '/' . $filename;

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
		$final_handle = fopen( $final_file, 'wb' );
		if ( ! $final_handle ) {
			wp_send_json_error( array( 'message' => __( 'Datei konnte nicht erstellt werden.', 'kurs-booking' ) ), 500 );
		}

		foreach ( $chunks as $chunk_file ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
			$chunk_content = file_get_contents( $chunk_file );
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
			fwrite( $final_handle, $chunk_content );
			// phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
			unlink( $chunk_file );
		}

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
		fclose( $final_handle );

		// Validate file size.
		$file_size = filesize( $final_file );
		if ( $file_size > self::MAX_FILE_SIZE ) {
			self::cleanup_upload( $upload_id );
			wp_send_json_error( array( 'message' => __( 'Datei ist zu gross (max. 2GB).', 'kurs-booking' ) ), 400 );
		}

		// Validate MIME type.
		$finfo     = finfo_open( FILEINFO_MIME_TYPE );
		$mime_type = finfo_file( $finfo, $final_file );
		finfo_close( $finfo );

		if ( ! in_array( $mime_type, self::ALLOWED_TYPES, true ) ) {
			self::cleanup_upload( $upload_id );
			wp_send_json_error(
				array(
					'message' => sprintf(
					 /* translators: %s: detected MIME type */
						__( 'Ungueltiger Dateityp: %s', 'kurs-booking' ),
						$mime_type
					),
				),
				400
			);
		}

		// Generate title from filename if not provided.
		if ( empty( $title ) ) {
			$title = pathinfo( $filename, PATHINFO_FILENAME );
			$title = str_replace( array( '-', '_' ), ' ', $title );
			$title = ucwords( $title );
		}

		// Create WordPress video post first.
		$video_post_id = wp_insert_post(
			array(
				'post_type'   => Kurs_Booking_Video::POST_TYPE,
				'post_title'  => $title,
				'post_status' => 'publish',
				'post_author' => get_current_user_id(),
			)
		);

		if ( is_wp_error( $video_post_id ) ) {
			self::cleanup_upload( $upload_id );
			wp_send_json_error( array( 'message' => $video_post_id->get_error_message() ), 500 );
		}

		// Set initial status.
		update_post_meta( $video_post_id, '_video_status', Kurs_Booking_Video::STATUS_UPLOADING );
		update_post_meta( $video_post_id, '_video_uploaded_at', current_time( 'mysql' ) );

		// Assign to kurs if provided.
		if ( $kurs_id > 0 ) {
			Kurs_Booking_Video::assign_to_kurs( $video_post_id, $kurs_id );
		}

		// Upload to video service.
		$result = Kurs_Booking_Video_Service::upload( $final_file, $kurs_id, $title );

		if ( is_wp_error( $result ) ) {
			// Update status to error.
			update_post_meta( $video_post_id, '_video_status', Kurs_Booking_Video::STATUS_ERROR );
			update_post_meta( $video_post_id, '_video_error_message', $result->get_error_message() );

			self::cleanup_upload( $upload_id );

			wp_send_json_error(
				array(
					'message'       => $result->get_error_message(),
					'video_post_id' => $video_post_id,
				),
				500
			);
		}

		// Store external video ID.
		$external_id = $result['id'] ?? $result['video_id'] ?? '';
		if ( $external_id ) {
			update_post_meta( $video_post_id, '_video_external_id', $external_id );
		}

		// Update status to processing.
		update_post_meta( $video_post_id, '_video_status', Kurs_Booking_Video::STATUS_PROCESSING );

		// Cleanup temp files.
		self::cleanup_upload( $upload_id );

		wp_send_json_success(
			array(
				'video_post_id' => $video_post_id,
				'external_id'   => $external_id,
				'edit_url'      => get_edit_post_link( $video_post_id, 'raw' ),
				'message'       => __( 'Video erfolgreich hochgeladen. Verarbeitung laeuft...', 'kurs-booking' ),
			)
		);
	}

	/**
	 * Handle upload cancellation
	 */
	public static function handle_upload_cancel(): void {
		// Verify nonce.
		if ( ! check_ajax_referer( 'kurs_video_upload', 'nonce', false ) ) {
			wp_send_json_error( array( 'message' => __( 'Sicherheitspruefung fehlgeschlagen.', 'kurs-booking' ) ), 403 );
		}

		$upload_id = isset( $_POST['upload_id'] ) ? sanitize_text_field( wp_unslash( $_POST['upload_id'] ) ) : '';

		if ( empty( $upload_id ) ) {
			wp_send_json_error( array( 'message' => __( 'Upload-ID fehlt.', 'kurs-booking' ) ), 400 );
		}

		self::cleanup_upload( $upload_id );

		wp_send_json_success( array( 'message' => __( 'Upload abgebrochen.', 'kurs-booking' ) ) );
	}

	/**
	 * Get or create temp directory for upload
	 *
	 * @param string $upload_id Upload identifier.
	 * @param bool   $create    Whether to create directory if not exists.
	 * @return string|false Directory path or false on failure.
	 */
	private static function get_temp_dir( string $upload_id, bool $create = true ): string|false {
		$upload_dir = wp_upload_dir();
		$base_dir   = $upload_dir['basedir'] . '/' . self::TEMP_DIR;
		$temp_dir   = $base_dir . '/' . sanitize_file_name( $upload_id );

		if ( ! $create ) {
			return is_dir( $temp_dir ) ? $temp_dir : false;
		}

		// Create base directory if needed.
		if ( ! is_dir( $base_dir ) ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_mkdir
			if ( ! mkdir( $base_dir, 0755, true ) ) {
				return false;
			}
			// Add index.php for security.
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
			file_put_contents( $base_dir . '/index.php', '<?php // Silence is golden' );
		}

		// Create upload directory if needed.
		if ( ! is_dir( $temp_dir ) ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_mkdir
			if ( ! mkdir( $temp_dir, 0755, true ) ) {
				return false;
			}
		}

		return $temp_dir;
	}

	/**
	 * Cleanup upload temp files
	 *
	 * @param string $upload_id Upload identifier.
	 */
	private static function cleanup_upload( string $upload_id ): void {
		$temp_dir = self::get_temp_dir( $upload_id, false );

		if ( ! $temp_dir || ! is_dir( $temp_dir ) ) {
			return;
		}

		// Remove all files in directory.
		$files = glob( $temp_dir . '/*' );
		foreach ( $files as $file ) {
			if ( is_file( $file ) ) {
				// phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
				unlink( $file );
			}
		}

		// Remove directory.
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_rmdir
		rmdir( $temp_dir );
	}

	/**
	 * Cleanup old temp files (scheduled task)
	 */
	public static function cleanup_temp_files(): void {
		$upload_dir = wp_upload_dir();
		$base_dir   = $upload_dir['basedir'] . '/' . self::TEMP_DIR;

		if ( ! is_dir( $base_dir ) ) {
			return;
		}

		$dirs = glob( $base_dir . '/*', GLOB_ONLYDIR );
		$now  = time();

		foreach ( $dirs as $dir ) {
			$meta_file = $dir . '/meta.json';

			// Check age.
			if ( file_exists( $meta_file ) ) {
				// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
				$meta = json_decode( file_get_contents( $meta_file ), true );
				$age  = $now - ( $meta['created_at'] ?? 0 );
			} else {
				// No meta file, check directory age.
				$age = $now - filemtime( $dir );
			}

			// Remove if older than 24 hours.
			if ( $age > 86400 ) {
				$upload_id = basename( $dir );
				self::cleanup_upload( $upload_id );
			}
		}
	}
}
