<?php

namespace Limb_Chatbot\Includes\Services;

use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Data_Objects\File;
use Limb_Chatbot\Includes\Data_Objects\Meta_Data_Object;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Utilities\File_Utility;

/**
 * File Service for AI Provider File Operations
 *
 * Handles the upload and management of files to AI providers (OpenAI, Gemini, DeepSeek)
 * for knowledge generation and other AI-related purposes. This service acts as a bridge
 * between the File data object and the provider-specific file upload utilities.
 *
 * Supported Providers:
 * - OpenAI: Full support for file uploads and management
 * - Gemini: Basic support for file operations
 * - DeepSeek: Not yet implemented
 *
 * @package Limb_Chatbot\Includes\Services
 * @since 1.0.0
 */
class File_Service {

	/**
	 * Purpose constant for knowledge generation uploads.
	 *
	 * Files uploaded with this purpose are used for RAG (Retrieval Augmented Generation)
	 * and vector store operations.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	const PURPOSE_KNOWLEDGE_GENERATION = 'knowledge';

	/**
	 * Refreshes multiple files by their UUIDs.
	 *
	 * Retrieves fresh metadata from the AI provider for multiple files
	 * and updates their local records. Used for batch synchronization.
	 *
	 * @param array $uuids Array of file UUIDs to refresh.
	 * @return Data_Object_Collection Collection of refreshed File objects.
	 * @throws Exception If any file refresh fails.
	 * @since 1.0.0
	 */
	public function refresh_files( $uuids ) {
		$files = new Data_Object_Collection( [] );
		foreach ( $uuids as $uuid ) {
			$file = File::find_by_uuid( $uuid );
			$files->push_item( $this->refresh( $file ) );
		}

		return $files;
	}

	/**
	 * Refreshes a single file's metadata from the AI provider.
	 *
	 * Retrieves the latest metadata for a file from the AI provider
	 * and updates the local File object. This is useful for checking
	 * upload status, file availability, or other provider-specific data.
	 *
	 * @param File|null $file The File object to refresh.
	 * @return File The updated File object with fresh metadata.
	 * @throws Exception If file doesn't exist, config is missing, or refresh fails.
	 * @since 1.0.0
	 */
	public function refresh( ?File $file ) {
		$config_id = $file->get_meta( 'config_id' );
		$config    = Config::find( $config_id );
		$file_path = Helper::get_wp_uploaded_file_dir( $file->get_file_path() );

		$file_utility = new File_Utility(
			File_Service::PURPOSE_KNOWLEDGE_GENERATION,
			$file_path,
			$config->get_related_to_instance()->get_id(),
			$config
		);
		$metadata     = $file_utility->refresh( $file );
		if ( ! is_array( $metadata ) || empty( $metadata ) ) {
			throw new Exception( Error_Codes::UNEXPECTED_RESPONSE_FORMAT,
				'Failed to refresh file metadata. Invalid response received.' );
		}

		// Process and store new metadata (same as upload method)
		foreach ( $metadata as $key => $value ) {
			if ( $value instanceof Meta_Data_Object ) {
				$file->add_meta( $value->get_meta_key(), $value->get_meta_value() );
			}
		}

		// Update file status and save
		File::update( $file->get_uuid(), [ 'status' => File::STATUS_ACTIVE ] );
		$file->save();

		return $file;
	}

	/**
	 * Uploads a file to an AI provider.
	 *
	 * This method handles the complete upload process:
	 * 1. Validates the file exists on disk
	 * 2. Creates a File_Utility instance with proper configuration
	 * 3. Delegates to provider-specific upload handler
	 * 4. Processes returned metadata
	 * 5. Saves metadata to the File object
	 * 6. Updates file status to 'active'
	 *
	 * @param  File  $file  The File object to upload.
	 * @param  Config  $config  The AI provider configuration to use.
	 *
	 * @return File The updated File object with provider metadata.
	 * @throws Exception If file doesn't exist, upload fails, or provider doesn't support uploads.
	 * @since 1.0.0
	 */
	public function upload_to_provider( File $file, Config $config ): File {
		// Validate file exists on disk
		$file_path = Helper::get_wp_uploaded_file_dir( $file->get_file_path() );
		try {
			// Create File_Utility instance
			$file_utility = new File_Utility(
				self::PURPOSE_KNOWLEDGE_GENERATION,
				$file_path,
				$config->get_related_to_instance()->get_id(),
				$config
			);
			// Upload to provider and get metadata
			$metadata = $file_utility->upload( $file );
			if ( ! is_array( $metadata ) || empty( $metadata ) ) {
				throw new Exception( Error_Codes::TECHNICAL_ERROR,
					__( 'Failed to upload file to provider. Invalid response received.', 'limb-chatbot' ) );
			}

			// Process and store metadata
			foreach ( $metadata as $key => $value ) {
				if ( $value instanceof Meta_Data_Object ) {
					$file->add_meta( $value->get_meta_key(), $value->get_meta_value() );
				}
			}
			// Add the common configs
			$file->add_meta( 'config_id', $config->get_id() );
			File::update( $file->get_uuid(), [ 'status' => File::STATUS_ACTIVE ] );
			$file->save();

			return $file;
		} catch ( Exception $e ) {
			// Re-throw the exception
			throw $e;
		}
	}
}