<?php

namespace Limb_Chatbot\Includes\AI_Providers\Open_Ai\Endpoints;

use Limb_Chatbot\Includes\AI_Providers\Open_Ai\Utilities\Fine_Tuning_Utility;
use Limb_Chatbot\Includes\Data_Objects\AI_Model;
use Limb_Chatbot\Includes\AI_Providers\Open_Ai\Endpoints\Fine_Tuning\Handlers\Fine_Tuning_Response_Handler;
use Limb_Chatbot\Includes\AI_Providers\Open_Ai\Open_Ai;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Utilities\File_Utility;

/**
 * Class Fine_Tuning_Endpoint
 *
 * Handles fine-tuning job creation and retrieval for OpenAI models.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Open_Ai\Endpoints
 * @since 1.0.0
 */
class Fine_Tuning_Endpoint extends Open_Ai_Endpoint {

	/**
	 * Fine_Tuning_Endpoint constructor.
	 *
	 * @param Fine_Tuning_Utility $utility Utility object containing configuration and model info.
	 * @since 1.0.0
	 */
	public function __construct( Fine_Tuning_Utility $utility ) {
		parent::__construct( $utility );
	}

	/**
	 * Creates a new fine-tuning job for the specified model.
	 *
	 * @return array Metadata returned by the fine-tuning response handler.
	 * @throws Exception If file upload or model metadata is invalid.
	 * @since 1.0.0
	 */
	public function create() {
		$model = $this->utility->global_utility->model;
		$this->maybe_upload_file( $model );
		$body        = json_encode( array(
			'training_file' => $model->get_meta( Open_Ai::$id . "_file_id" ),
			'model'         => AI_Model::find( $model->get_meta( 'parent_model_id' ) )->get_name(),
			'suffix'        => $model->get_meta( 'suffix' ),
		) );
		$http_client = $this->http_client_factory();
		$response    = $http_client->post( parent::API_BASE_URL . '/fine_tuning/jobs', array( 'headers' => $this->get_header(), 'body' => $body ) );

		return ( new Fine_Tuning_Response_Handler( $response, $http_client, $this ) )->get_metas();
	}

	/**
	 * Uploads the fine-tuning training file if not already uploaded.
	 *
	 * @param AI_Model $model  The AI model to fine-tune.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	private function maybe_upload_file( AI_Model $model ): void {
		if ( empty( $model->get_meta( Open_Ai::$id . "_file_id" ) ) ) {
			$res = ( new File_Utility( 'fine-tune', $model->get_fine_tuning_file(), Open_Ai::$id, $this->config ) )->create();
			$model->add_meta( Open_Ai::$id . '_file_id', $res->id );
		}
	}

	/**
	 * Retrieves the metadata of an existing fine-tuning job.
	 *
	 * @return array Metadata returned by the fine-tuning response handler.
	 * @throws Exception If the fine-tuning job ID is not found.
	 * @since 1.0.0
	 */
	public function retrieve() {
		if ( ! ( $external_id = $this->utility->global_utility->model->get_meta( Open_Ai::$id . "_id" ) ) ) {
			throw new Exception( Error_Codes::NOT_FOUND, __( 'Fine tuning job is not created', 'limb-chatbot' ) );
		}
		$http_client = $this->http_client_factory();
		$response    = $http_client->get( parent::API_BASE_URL . '/fine_tuning/jobs/' . $external_id, [
			'headers' => $this->get_header()
		] );

		return ( new Fine_Tuning_Response_Handler( $response, $http_client, $this ) )->get_metas();
	}
}