<?php

namespace Limb_Chatbot\Includes\Services\Knowledge;

use Limb_Chatbot\Includes\Data_Objects\Dataset;
use Limb_Chatbot\Includes\Data_Objects\Job;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Factories\Knowledge_Generator_Factory;

/**
 * Knowledge_Generator class for creating dataset entries from content.
 *
 * Generates structured Q&A pairs from WordPress posts, terms, or manual input.
 * Processes segment clusters to generate both segment-specific and cross-segment QAs.
 *
 * @since 1.0.0
 */
class Knowledge_Generator {

	/**
	 * Generates dataset entries for a given source (post, term, or manual).
	 *
	 * Enhanced with comprehensive error handling and validation.
	 *
	 * @param  Dataset  $dataset
	 *
	 * @return Dataset
	 * @throws Exception If generation fails with critical errors
	 */
	public function generate( Dataset $dataset, ?Job $job = null ): Dataset {
		// Set status to generating
		$dataset->set_status( Dataset::STATUS_GENERATING );
		$dataset->save();

		try {
			$generator = ( new Knowledge_Generator_Factory() )->make( $dataset->get_source_type() );
			$dataset   = $generator->generate( $dataset );

			// Validate that entries were created
			if ( ! $dataset->has_entries() ) {
				throw new Exception( Error_Codes::EMPTY_VALUE, __( 'No Q&As were generated', 'limb-chatbot' ) );
			}

			$dataset->mark_synced();
			$dataset->set_status( Dataset::STATUS_GENERATED );
			$dataset->save();

			return $dataset;
		} catch ( Exception $e ) {
			// Let the background process handle failure status and error storage
			$errors = $dataset->get_errors();

			// Create error entry
			$error_entry = [
				'stage'       => 'generation',
				'message'     => $e->getMessage(),
				'error_code'  => $e->get_error_code(),
				'is_critical' => $this->is_critical_error( $e ),
				'http_status' => method_exists( $e, 'get_http_status' ) ? $e->get_http_status() : null,
				'error_data'  => method_exists( $e, 'get_error_data' ) ? $e->get_error_data() : null,
			];

			$errors[] = $error_entry;
			$dataset->update_meta( 'errors', wp_json_encode( $errors ) );
			throw $e;
		}
	}

	/**
	 * Determines if an error is critical and should pause the process.
	 *
	 * @param  Exception  $e
	 *
	 * @return bool
	 * @since 1.0.0
	 */
	private function is_critical_error( Exception $e ): bool {
		$error_code = $e->get_error_code();

		// Critical error codes that should always pause
		$critical_codes = [
			Error_Codes::QUOTA_EXCEED,
			Error_Codes::AUTHENTICATION_API_KEY_MISSING,
			Error_Codes::AUTHENTICATION_UNAUTHORIZED,
			Error_Codes::AI_PROVIDER_NOT_SET,
			Error_Codes::AI_MODEL_NOT_SET
		];

		if ( in_array( $error_code, $critical_codes ) ) {
			return true;
		}

		// Check quota flag if available
		if ( method_exists( $e, 'is_related_to_quota' ) && $e->is_related_to_quota() ) {
			return true;
		}

		return false;
	}
}