<?php

namespace Limb_Chatbot\Includes\Services\Actions;

use Limb_Chatbot\Includes\Data_Objects\Parameter;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;

/**
 * Handles attachment parameter uploads to WordPress native media library.
 *
 * @package Limb_Chatbot\Includes\Services\Actions
 * @since 1.0.0
 */
class Attachment_Media_Upload_Service {

	/**
	 * Upload files for an attachment parameter and return normalized metadata.
	 *
	 * @param  Parameter  $parameter
	 * @param  array  $file_params
	 *
	 * @return array
	 * @throws Exception
	 */
	public function upload_for_parameter( Parameter $parameter, array $file_params ): array {
		$config             = is_array( $parameter->get_config() ) ? $parameter->get_config() : [];
		$allowed_mime_types = isset( $config['allowed_mime_types'] ) && is_array( $config['allowed_mime_types'] ) ? array_values( array_filter( array_map( 'sanitize_mime_type', $config['allowed_mime_types'] ) ) ) : [ 'application/pdf', 'image/jpeg', 'image/png', 'image/webp' ];
		$max_file_size      = isset( $config['max_file_size'] ) ? max( 1, absint( $config['max_file_size'] ) ) : ( 20 * 1024 * 1024 );
		$max_files_count    = isset( $config['max_files_count'] ) ? max( 1, absint( $config['max_files_count'] ) ) : 5;
		$multiple           = ! isset( $config['multiple'] ) || in_array( $config['multiple'], [ 1, '1', true ], true );

		$files = $this->normalize_uploaded_files( $file_params );
		if ( empty( $files ) ) {
			throw new Exception( Error_Codes::DATASET_FILE_UPLOAD_MISSING_FILE, __( 'No files provided for upload.', 'limb-chatbot' ) );
		}

		if ( ! $multiple && count( $files ) > 1 ) {
			throw new Exception( Error_Codes::VALIDATION_INVALID_VALUE, __( 'Only one file is allowed for this parameter.', 'limb-chatbot' ) );
		}
		if ( count( $files ) > $max_files_count ) {
			throw new Exception( Error_Codes::VALIDATION_FILE_SIZE_LIMIT, sprintf( __( 'Maximum %d files are allowed.', 'limb-chatbot' ), $max_files_count ) );
		}

		$attachments = [];
		foreach ( $files as $file ) {
			$attachment_id = $this->upload_single_file_to_media( $file, $allowed_mime_types, $max_file_size );
			$url           = wp_get_attachment_url( $attachment_id );
			$path          = get_attached_file( $attachment_id );
			$size          = ( $path && file_exists( $path ) ) ? filesize( $path ) : 0;

			if ( empty( $url ) || empty( $size ) ) {
				throw new Exception( Error_Codes::FILE_FAILED_TO_CREATE, __( 'Failed to finalize media upload.', 'limb-chatbot' ) );
			}

			$attachments[] = [
				'title'      => get_the_title( $attachment_id ) ?: sanitize_file_name( $file['name'] ?? '' ),
				'mime_type'  => sanitize_mime_type( (string) get_post_mime_type( $attachment_id ) ),
				'value'      => esc_url_raw( $url ),
				'media_id'   => $attachment_id,
				'file_size'  => (int) $size,
				'file_name'  => sanitize_file_name( basename( (string) $path ) ),
			];
		}

		return $attachments;
	}

	/**
	 * Normalize $_FILES-like array to flat file entries.
	 *
	 * @param  array  $file_params
	 *
	 * @return array
	 */
	private function normalize_uploaded_files( array $file_params ): array {
		$files = [];

		foreach ( $file_params as $file_data ) {
			if ( ! is_array( $file_data ) ) {
				continue;
			}

			$is_multi = isset( $file_data['name'] ) && is_array( $file_data['name'] );
			if ( ! $is_multi ) {
				$files[] = $file_data;
				continue;
			}

			$count = count( $file_data['name'] );
			for ( $i = 0; $i < $count; $i ++ ) {
				$files[] = [
					'name'     => $file_data['name'][ $i ] ?? '',
					'type'     => $file_data['type'][ $i ] ?? '',
					'tmp_name' => $file_data['tmp_name'][ $i ] ?? '',
					'error'    => $file_data['error'][ $i ] ?? UPLOAD_ERR_NO_FILE,
					'size'     => $file_data['size'][ $i ] ?? 0,
				];
			}
		}

		return array_values( array_filter( $files, static function ( $file ) {
			return is_array( $file ) && ! empty( $file['tmp_name'] ) && (int) ( $file['error'] ?? UPLOAD_ERR_OK ) === UPLOAD_ERR_OK;
		} ) );
	}

	/**
	 * Upload one file into WP native media library.
	 *
	 * @param  array  $file
	 * @param  array  $allowed_mime_types
	 * @param  int  $max_file_size
	 *
	 * @return int
	 * @throws Exception
	 */
	private function upload_single_file_to_media( array $file, array $allowed_mime_types, int $max_file_size ): int {
		if ( empty( $file['tmp_name'] ) || ! is_uploaded_file( $file['tmp_name'] ) ) {
			throw new Exception( Error_Codes::DATASET_FILE_UPLOAD_MISSING_FILE, __( 'Invalid or missing uploaded file.', 'limb-chatbot' ) );
		}
		if ( (int) ( $file['size'] ?? 0 ) > $max_file_size ) {
			throw new Exception( Error_Codes::VALIDATION_FILE_SIZE_LIMIT, __( 'Uploaded file exceeds maximum allowed size.', 'limb-chatbot' ) );
		}

		$detected = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'] );
		$mime     = ! empty( $detected['type'] ) ? sanitize_mime_type( $detected['type'] ) : sanitize_mime_type( (string) ( $file['type'] ?? '' ) );
		if ( empty( $mime ) ) {
			throw new Exception( Error_Codes::VALIDATION_UNSUPPORTED_MIME_TYPE, __( 'Could not detect file mime type.', 'limb-chatbot' ) );
		}
		if ( ! empty( $allowed_mime_types ) && ! in_array( $mime, $allowed_mime_types, true ) ) {
			throw new Exception( Error_Codes::VALIDATION_UNSUPPORTED_MIME_TYPE, sprintf( __( 'File type "%s" is not allowed.', 'limb-chatbot' ), $mime ) );
		}

		if ( ! function_exists( 'media_handle_sideload' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
			require_once ABSPATH . 'wp-admin/includes/media.php';
			require_once ABSPATH . 'wp-admin/includes/image.php';
		}

		$sideload = [
			'name'     => sanitize_file_name( $file['name'] ?? 'attachment' ),
			'type'     => $mime,
			'tmp_name' => $file['tmp_name'],
			'error'    => 0,
			'size'     => (int) ( $file['size'] ?? 0 ),
		];

		$attachment_id = media_handle_sideload( $sideload, 0, null );
		if ( is_wp_error( $attachment_id ) || empty( $attachment_id ) ) {
			$message = is_wp_error( $attachment_id ) ? $attachment_id->get_error_message() : __( 'Failed to upload file to media.', 'limb-chatbot' );
			throw new Exception( Error_Codes::FILE_FAILED_TO_CREATE, $message );
		}

		return (int) $attachment_id;
	}
}
