<?php 
/**
 * 
 * SSQ Media Uploads
 * 
 */

/**
 * Register dynamic post meta for allowed image types so they show in REST.
 */
add_action( 'init', function() {
    register_post_meta('ssq-media', 'frames', array(
        'type'         => 'object',
        'single'       => true,
        'show_in_rest' => array(
            'schema' => array(
                'type' => 'object',

                // keys must be digits only ("0", "1", "2", ...)
                'patternProperties' => array(
                    '^[0-9]+$' => array(
                        'type'   => 'string',
                        'format' => 'uri',
                    ),
                ),

                // disallow random non-numeric keys
                'additionalProperties' => false,
            ),
        ),
        'auth_callback' => function() {
            return current_user_can('edit_posts');
        },
        'description'  => 'Sparse numeric index → frame metadata map',
    ));

} );

/**
 * REST: Upload single image to existing ssq-media post
 *
 * POST /wp-json/scroll-sequence/v2/upload-single
 * Fields:
 *  - ssq_post_id (int) REQUIRED
 *  - index (int) REQUIRED
 *  - slug (string) REQUIRED (a-z0-9- max 20 chars)
 *  - image (file) REQUIRED (multipart/form-data file field named "image")
 */
add_action( 'rest_api_init', function() {
	register_rest_route( 'scroll-sequence/v2', '/upload-single', array(
		'methods'             => 'POST',
		'permission_callback' => function () {
			return current_user_can( 'upload_files' );
		},
		'callback'            => function ( WP_REST_Request $request ) {

			// Validate required params
			$ssq_post_id = $request->get_param( 'ssq_post_id' );
			$index_raw   = $request->get_param( 'index' );
			$slug_raw    = $request->get_param( 'slug' );

			if ( empty( $ssq_post_id ) ) {
				return new WP_Error( 'ssq_missing_post_id', 'ssq_post_id is required', array( 'status' => 400 ) );
			}
			$ssq_post_id = intval( $ssq_post_id );
			$post = get_post( $ssq_post_id );
			if ( ! $post || $post->post_type !== 'ssq-media' ) {
				return new WP_Error( 'ssq_invalid_post', 'ssq_post_id does not reference an ssq-media post', array( 'status' => 400 ) );
			}


			if ( ! isset( $index_raw ) || ! is_numeric( $index_raw ) ) {
				return new WP_Error( 'ssq_bad_index', 'index is required and must be an integer', array( 'status' => 400 ) );
			}
			$index = intval( $index_raw );
			if ( $index < 0 ) {
				return new WP_Error( 'ssq_bad_index_range', 'index must be >= 0', array( 'status' => 400 ) );
			}

			if ( empty( $slug_raw ) || ! is_string( $slug_raw ) ) {
				return new WP_Error( 'ssq_missing_slug', 'slug is required', array( 'status' => 400 ) );
			}
			$slug = sanitize_file_name( $slug_raw );
			if ( ! preg_match( '/^[a-z0-9-]{1,20}$/', $slug ) ) {
				return new WP_Error( 'ssq_bad_slug', 'slug may contain only a-z, 0-9 and -, max 20 chars', array( 'status' => 400 ) );
			}

			// Ensure file exists in $_FILES under 'image'
			// phpcs:ignore WordPress.Security.NonceVerification.Missing -- REST API handles authentication
			if ( empty( $_FILES ) || empty( $_FILES['image'] ) ) {
				return new WP_Error( 'ssq_no_file', 'No file uploaded in field "image"', array( 'status' => 400 ) );
			}

			// Build target filename: 4-digit padded index
			$index_4d = str_pad( (string) $index, 4, '0', STR_PAD_LEFT );

			// Work with the uploaded file array
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- File validation happens via wp_handle_sideload
			// phpcs:ignore WordPress.Security.NonceVerification.Missing -- REST API handles authentication
			$file_array = $_FILES['image'];


			// SECURITY: Enforce file size limit (10MB)
			$max_size = 10 * 1024 * 1024; // 10MB
			if ( $file_array['size'] > $max_size ) {
				return new WP_Error( 'ssq_file_too_large', 'File size must be less than 10MB', array( 'status' => 400 ) );
			}

			// SECURITY: Validate file type BEFORE processing
			$allowed_mime_types = array(
				'image/jpeg',
				'image/jpg', 
				'image/png',
				'image/webp',
				'image/gif'
			);

			// Check tmp_name exists and is uploaded file
			if ( empty( $file_array['tmp_name'] ) || ! is_uploaded_file( $file_array['tmp_name'] ) ) {
				return new WP_Error( 'ssq_invalid_upload', 'Invalid file upload', array( 'status' => 400 ) );
			}

			// Get MIME type from actual file content (not from user input!)
			$finfo = finfo_open( FILEINFO_MIME_TYPE );
			$detected_mime = finfo_file( $finfo, $file_array['tmp_name'] );
			finfo_close( $finfo );

			if ( ! in_array( $detected_mime, $allowed_mime_types, true ) ) {
				return new WP_Error( 
					'ssq_invalid_file_type', 
					'Only image files (JPEG, PNG, WebP, GIF) are allowed', 
					array( 'status' => 400 ) 
				);
			}

			// SECURITY: Get extension from WordPress validation, not user input
			$wp_filetype = wp_check_filetype_and_ext( 
				$file_array['tmp_name'], 
				$file_array['name'], 
				array(
					'jpg|jpeg|jpe' => 'image/jpeg',
					'png'          => 'image/png',
					'webp'         => 'image/webp',
					'gif'          => 'image/gif',
				)
			);

			if ( ! $wp_filetype['ext'] || ! $wp_filetype['type'] ) {
				return new WP_Error( 'ssq_invalid_file', 'File type validation failed', array( 'status' => 400 ) );
			}

			$ext = $wp_filetype['ext']; // Safe extension from WordPress

			// SECURITY: Sanitize slug to prevent directory traversal
			$slug = preg_replace( '/[^a-z0-9-]/', '', strtolower( $slug ) );
			if ( empty( $slug ) ) {
				return new WP_Error( 'ssq_invalid_slug', 'Invalid slug after sanitization', array( 'status' => 400 ) );
			}

			$forced_name = $slug . '_' . $index_4d . '.' . $ext;

			// Normalize array for sideload handling (single file)
			$sideload = array(
				'name'     => $forced_name,
				'type'     => $wp_filetype['type'], // Use validated MIME type
				'tmp_name' => $file_array['tmp_name'],
				'error'    => $file_array['error'],
				'size'     => $file_array['size'],
			);

			if ( $sideload['error'] !== UPLOAD_ERR_OK ) {
				return new WP_Error( 'ssq_upload_error', 'File upload error', array( 'status' => 400 ) );
			}














			// Use upload_dir filter to place file into:
			// uploads/scrollsequence/{ssq_media_id}/
			$override = array(
				'ssq_post_id' => $ssq_post_id,
				'slug'        => $slug,
			);

			// Stash override in a global var referenced by the filter
			global $ssq_custom_upload_override;
			$ssq_custom_upload_override = $override;

			add_filter( 'upload_dir', 'ssq_custom_upload_dir_for_single_image' );

			require_once ABSPATH . 'wp-admin/includes/file.php';

			// Override to allow only images and set size limits
			$overrides = array(
				'test_form' => false,
				'mimes'     => array(
					'jpg|jpeg|jpe' => 'image/jpeg',
					'png'          => 'image/png',
					'webp'         => 'image/webp',
					'gif'          => 'image/gif',
				),
			);
			$handled = wp_handle_sideload( $sideload, $overrides );

			remove_filter( 'upload_dir', 'ssq_custom_upload_dir_for_single_image' );
			$ssq_custom_upload_override = null;

			if ( isset( $handled['error'] ) ) {
				return new WP_Error( 'ssq_handle_error', $handled['error'], array( 'status' => 500 ) );
			}

			// $handled['url'] = public URL
			$url = $handled['url'];

			// Merge into post meta. Preserve holes by using index as the array key.
			$existing = get_post_meta( $ssq_post_id, 'frames', true );
			if ( ! is_array( $existing ) ) {
				$existing = array();
			}
			// Ensure index is stored as integer key
			$existing[ $index ] = $url;

			update_post_meta( $ssq_post_id, 'frames', $existing );

			return array(
				'success'      => true,
				'ssq_post_id'  => $ssq_post_id,
				'index'        => $index,
				'filename'     => $handled['file'],
				'url'          => $url,
				'all_images'   => $existing,
			);
		},
		'args'                => array(
			'ssq_post_id' => array( 'required' => true, 'type' => 'integer' ),
			'index'       => array( 'required' => true, 'type' => 'integer' ),
			'slug'        => array( 'required' => true, 'type' => 'string' ),
		),
	) );
} );

/**
 * upload_dir filter callback to construct the custom path:
 * uploads/scrollsequence/{ssq_media_id}/
 */
function ssq_custom_upload_dir_for_single_image( $uploads ) {
	global $ssq_custom_upload_override;

	if ( empty( $ssq_custom_upload_override ) ) {
		return $uploads;
	}

	$sequence_id = intval( $ssq_custom_upload_override['ssq_post_id'] );
	$slug = sanitize_file_name( $ssq_custom_upload_override['slug'] );

	$basedir = $uploads['basedir']; // .../wp-content/uploads
	$baseurl = $uploads['baseurl']; // https://example.com/wp-content/uploads

	$subdir = '/scrollsequence/' . $sequence_id . '-' . $slug ;

	$target_path = $basedir . $subdir;

	// Ensure directory exists
	if ( ! wp_mkdir_p( $target_path ) ) {
		// If cannot create, return default uploads dir so wp_handle_* can surface error
		return $uploads;
	}

    // SECURITY: Add index.php to prevent directory listing 
    $index_file = $target_path . '/index.php';
    if ( ! file_exists( $index_file ) ) {
        $index_content = "<?php\n// Silence is golden.\n";
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
        @file_put_contents( $index_file, $index_content );
    }


	$uploads['path']   = $target_path;
	$uploads['url']    = $baseurl . $subdir;
	$uploads['subdir'] = $subdir;

	return $uploads;
}


















/**
 * Admin CPT List view (thumbnail column)
 * - thumbnail src comes from 'frames' meta, index 0 if exists
 * - Add a count of frames column
 */
add_filter( 'manage_ssq-media_posts_columns', function( $columns ) {
	$columns_before = array();
	foreach ( $columns as $key => $value ) {
		if ( $key === 'title' ) {
			// Insert our column before the title
			$columns_before['ssq_media_thumbnail'] = esc_html__( 'Thumbnail', 'scrollsequence' );
			$columns_before['ssq_media_frame_count'] = esc_html__( 'Frame Count', 'scrollsequence' );
		}
		$columns_before[ $key ] = $value;
	}
	return $columns_before;
} );
add_action( 'manage_ssq-media_posts_custom_column', function( $column, $post_id ) {
	if ( $column === 'ssq_media_thumbnail' ) {
		$frames = get_post_meta( $post_id, 'frames', true );
		$thumbnail_url = '';
		if ( is_array( $frames ) && isset( $frames[0] ) ) {
			$thumbnail_url = $frames[0];
		}
		if ( $thumbnail_url ) {
			echo '<img src="' . esc_url( $thumbnail_url ) . '" alt="" style="max-width:100px;height:auto;" />';
		} else {
			echo esc_html__( 'No thumbnail', 'scrollsequence' );
		}
	} elseif ( $column === 'ssq_media_frame_count' ) {
		$frames = get_post_meta( $post_id, 'frames', true );
		$frame_count = 0;
		if ( is_array( $frames ) ) {
			$frame_count = count( $frames );
		}
		echo intval( $frame_count );
	}
}, 10, 2 );





/**
 * Admin meta box: display ssq-media images meta in a readable format
 */
add_action( 'add_meta_boxes', function() {
	add_meta_box(
		'ssq_media_images',
		'SSQ Media — Images',
		'ssq_media_images_meta_box_callback',
		'ssq-media',
		'normal',
		'default'
	);
} );

/**
 * Render callback for the SSQ Media images meta box.
 * Shows 'images' meta and any per-type arrays (e.g. 'image', 'depth_map') in a readable list/JSON.
 */
function ssq_media_images_meta_box_callback( $post ) {
	if ( ! current_user_can( 'edit_post', $post->ID ) ) {
		echo '<p>' . esc_html__( 'Insufficient permissions to view this data.', 'scrollsequence' ) . '</p>';
		return;
	}

	$val = get_post_meta( $post->ID, 'frames', true );
	echo '<h4>Frames</h4>';
	if ( is_array( $val ) && count( $val ) ) {
		// Determine max index to display holes
		$keys = array_keys( $val );
		$numeric_keys = array();
		foreach ( $keys as $k ) {
			if ( is_numeric( $k ) ) $numeric_keys[] = intval( $k );
		}
		$max = $numeric_keys ? max( $numeric_keys ) : -1;
		if ( $max >= 0 ) {
			echo '<ol style="word-break:break-all">';
			for ( $i = 0; $i <= $max; $i++ ) {
				echo '<li>';
				$display_index = $i;
				if ( isset( $val[ $i ] ) && $val[ $i ] ) {
					echo '<strong>' . esc_html( $display_index ) . ':</strong> ';
					echo '<a href="' . esc_url( $val[ $i ] ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $val[ $i ] ) . '</a>';
				} else {
					echo '<em>' . esc_html__( 'empty', 'scrollsequence' ) . '</em>';
				}
				echo '</li>';
			}
			echo '</ol>';
		} else {
			// Non-numeric keyed array - just print JSON
			echo '<pre style="white-space:pre-wrap;max-width:100%;">' . esc_html( wp_json_encode( $val, JSON_PRETTY_PRINT ) ) . '</pre>';
		}
	} else {
		echo '<p><em>' . esc_html__( 'No entries.', 'scrollsequence' ) . '</em></p>';
	}
	

	// For debugging, optionally show the raw meta as JSON (commented out by default)
	echo '<h4>Raw meta attached to this post id (debug)</h4>';
	echo '<pre style="white-space:pre-wrap;max-width:100%;">' . esc_html( wp_json_encode( get_post_meta( $post->ID ), JSON_PRETTY_PRINT ) ) . '</pre>';
	//echo '<pre>' . esc_html( wp_json_encode( get_post_meta( $post->ID, 'frames', true ) ) ) . '</pre>';
}

