<?php

namespace Limb_Chatbot\Includes\Services\Automations;

use Limb_Chatbot\Includes\Data_Objects\AI_Model;
use Limb_Chatbot\Includes\Data_Objects\Chatbot;
use Limb_Chatbot\Includes\Data_Objects\Dataset;
use Limb_Chatbot\Includes\Data_Objects\Job;
use Limb_Chatbot\Includes\Data_Objects\Vector_Index;
use Limb_Chatbot\Includes\Data_Objects\WP_Post_Data_Object;
use Limb_Chatbot\Includes\Services\Dataset_Service;
use Limb_Chatbot\Includes\Services\Helper;
use Limb_Chatbot\Includes\Services\Knowledge\Dataset_Builders\Informational_Dataset_Builder;
use Limb_Chatbot\Includes\Services\Knowledge\Dataset_Builders\Actionable_Dataset_Builder;
use Limb_Chatbot\Includes\Vector_Dbs\Local\Local;
use WP_Post;

/**
 * Handles dataset creation when a post is published.
 *
 * Creates both informational and actionable datasets for newly published posts
 * using the official dataset builders.
 *
 * @since 1.0.11
 */
class Post_Creation_Handler {

	/**
	 * Dataset service.
	 *
	 * @var Dataset_Service
	 * @since 1.0.11
	 */
	private Dataset_Service $dataset_service;

	/**
	 * Constructor.
	 *
	 * @param  Dataset_Service  $dataset_service  Dataset service instance.
	 *
	 * @since 1.0.11
	 */
	public function __construct( Dataset_Service $dataset_service ) {
		$this->dataset_service = $dataset_service;
	}

	/**
	 * Handle post creation by creating datasets.
	 *
	 * When a post is published and auto-sync is enabled, creates both informational
	 * and actionable datasets using the official builders.
	 *
	 * @param  int  $post_id  Post ID.
	 * @param  WP_Post  $post  The post object.
	 *
	 * @return void
	 * @since 1.0.11
	 */
	public function handle( int $post_id, WP_Post $post ): void {
		try {
			// Ignore auto-saves and revisions
			if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
				return;
			}

			// Get all chatbots (default + custom)
			$chatbots = Chatbot::where( [ 'status' => WP_Post_Data_Object::STATUS_PUBLISHED ] );
			$chatbots->push_item( Chatbot::make() );

			// Check each chatbot for auto_sync setting
			foreach ( $chatbots as $chatbot ) {
				try {
					if ( ! $chatbot instanceof Chatbot ) {
						continue;
					}

					$auto_sync = $chatbot->get_parameter( "auto_sync_for_post_{$post->post_type}" );
					if ( ! $auto_sync ) {
						continue;
					}

					// Create both dataset types using the official builders
					$this->create_informational_dataset( $post, $chatbot );
					$this->create_actionable_dataset( $post, $chatbot );
				} catch ( \Exception $e ) {
					Helper::log( $e );
				}
			}
		} catch ( \Exception $e ) {
			Helper::log( $e );
		}
	}

	/**
	 * Create informational and actionable datasets using official builders.
	 *
	 * @param  WP_Post  $post  The published post object.
	 * @param  Chatbot  $chatbot  The chatbot instance.
	 *
	 * @return void
	 * @since 1.0.11
	 */
	private function create_informational_dataset( WP_Post $post, Chatbot $chatbot ): void {
		try {
			// Prepare job with KB configuration
			$informational_job = $this->prepare_job( $post, $chatbot, Job::SUB_TYPE_INFORMATIONAL_DATASET_GENERATION );

			if ( $informational_job ) {
				// Prepare dataset data
				$data = [
					'source_type'     => Dataset::SOURCE_POST,
					'source_sub_type' => $post->post_type,
					'source'          => $post->ID,
				];

				// Create informational dataset using official builder
				$informational_builder = new Informational_Dataset_Builder();
				$informational_dataset = $informational_builder->build( $data, $informational_job );

				if ( $informational_dataset instanceof Dataset ) {
					$this->dataset_service->regenerate_dataset_entries( $informational_dataset );
				}
			}
		} catch ( \Exception $e ) {
			Helper::log( $e );
		}
	}

	/**
	 * Prepare a Job object with configuration from chatbot KB settings.
	 *
	 * @param  WP_Post  $post  The post being indexed.
	 * @param  Chatbot  $chatbot  The chatbot with KB settings.
	 *
	 * @return Job|null The prepared job or null if configuration is incomplete.
	 * @since 1.0.11
	 */
	private function prepare_job( WP_Post $post, Chatbot $chatbot, $sub_type ): ?Job {
		try {
			// Get KB settings from chatbot
			$kb_ai_model_id       = $chatbot->get_parameter( 'kb_ai_model_id' );
			$kb_config_id         = $chatbot->get_parameter( 'kb_config_id' );
			$kb_vector_index_type = $chatbot->get_parameter( 'kb_vector_index_type' ) ?? 'local';
			$kb_vector_config_id  = $chatbot->get_parameter( 'kb_vector_config_id' );
			$dimension            = $chatbot->get_parameter( 'kb_dimension' ) ?? 1536;

			if ( $sub_type === Job::SUB_TYPE_ACTIONABLE_DATASET_GENERATION ) {
				$name         = 'lbaiccpt' . Helper::underscore_to_hyphen( $post->post_type ) . 'index';
				$is_local     = $kb_vector_index_type === Local::$id;
				$where        = [
					'name'         => $name,
					'vector_db_id' => $is_local ? null : $kb_vector_index_type,
					'config_id'    => $is_local ? null : $kb_config_id,
				];
				$vector_index = Vector_Index::where( $where );
				if ( $vector_index->is_empty() ) {
					return null;
				}
			}

			// Apply default fallbacks if settings missing
			if ( empty( $kb_ai_model_id ) || empty( $kb_config_id ) ) {
				$config      = $chatbot->get_config();
				$ai_provider = $config ? $config->get_related_to_instance() : null;

				if ( ! $ai_provider ) {
					return null;
				}

				// Get default embedding model from provider
				if ( empty( $kb_ai_model_id ) ) {
					$default_model  = $ai_provider->get_default_embedding_model();
					$kb_ai_model_id = $default_model instanceof AI_Model ? $default_model->get_id() : null;
				}

				// Use main config if KB config not set
				if ( empty( $kb_config_id ) ) {
					$kb_config_id = $config->get_id();
				}
			}

			if ( empty( $kb_ai_model_id ) || empty( $kb_config_id ) ) {
				return null;
			}

			// Create Job with configuration
			$job = new Job();
			$job->set_type( Job::TYPE_DATASET_GENERATING );
			$job->set_chatbot_uuid( $chatbot->uuid ?? Job::CHATBOT_DEFAULT );
			$job->set_sub_type( $sub_type );

			// Build configuration for builders
			$config = [
				'indexing_ai_model_id'            => $kb_ai_model_id,
				'indexing_config_id'              => $kb_config_id,
				'indexing_vector_index_type'      => $kb_vector_index_type,
				'indexing_vector_index_config_id' => $kb_vector_config_id,
				'indexing_dimension'              => $dimension,
			];
			$job->set_config( $config );

			return $job;
		} catch ( \Exception $e ) {
			Helper::log( $e );

			return null;
		}
	}

	private function create_actionable_dataset( WP_Post $post, Chatbot $chatbot ) {
		// Prepare job with KB configuration
		$actionable_job = $this->prepare_job( $post, $chatbot, Job::SUB_TYPE_ACTIONABLE_DATASET_GENERATION );

		if ( $actionable_job ) {
			// Prepare dataset data
			$data = [
				'source_type'     => Dataset::SOURCE_CPT,
				'source_sub_type' => $post->post_type,
				'source'          => $post->ID,
			];

			// Create informational dataset using official builder
			$informational_builder = new Actionable_Dataset_Builder();
			$informational_dataset = $informational_builder->build( $data, $actionable_job );

			if ( $informational_dataset instanceof Dataset ) {
				$this->dataset_service->regenerate_dataset_entries( $informational_dataset );
			}
		}
	}
}
