<?php

namespace Limb_Chatbot\Includes\Migrations;

use Limb_Chatbot\Includes\Data_Objects\AI_Model;
use Limb_Chatbot\Includes\Data_Objects\Chatbot;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Data_Objects\Vector_Index;
use Limb_Chatbot\Includes\Data_Objects\Vector_Index_Meta;

/**
 * Migration for Job Queue System
 *
 * Creates the job queue system tables:
 * - lbaic_jobs: Stores job metadata, status, progress, and statistics
 * - lbaic_tasks: Stores individual tasks for each job
 *
 * @since 1.0.9
 */
class Migration_1_0_9 extends Abstract_Migration {

	/**
	 * Get the target version this migration upgrades to.
	 *
	 * @return string
	 * @since 1.0.9
	 */
	public function get_version(): string {
		return '1.0.9';
	}

	/**
	 * Get migration description.
	 *
	 * @return string
	 * @since 1.0.9
	 */
	public function get_description(): string {
		return 'Create job queue system tables (jobs, tasks) for reliable background processing';
	}

	/**
	 * Execute the migration.
	 *
	 * Creates two new tables for the job queue system:
	 * 1. lbaic_jobs - Main jobs table with metadata and statistics
	 * 2. lbaic_tasks - Individual tasks for each job
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.0.9
	 */
	public function up(): bool {
		$this->log( 'Starting migration 1.0.9 - Creating job queue system tables' );

		// Create jobs table
		if ( ! $this->create_jobs_table() ) {
			return false;
		}

		// Create tasks table
		if ( ! $this->create_tasks_table() ) {
			return false;
		}

		// Add new KB settings
		if ( ! $this->knowledge_settings() ) {
			return false;
		}

		$this->log( 'Migration 1.0.9 completed successfully - All job queue system tables created' );

		return true;
	}

	/**
	 * Create the lbaic_jobs table.
	 *
	 * Stores job metadata, configuration, status, progress, and statistics.
	 * Supports multiple job types with JSON configuration.
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.0.9
	 */
	private function create_jobs_table(): bool {
		$table_name = $this->wpdb->prefix . 'lbaic_jobs';

		// Check if table already exists
		if ( $this->table_exists( $table_name ) ) {
			$this->log( "Table {$table_name} already exists, skipping creation" );

			return true;
		}

		$collate = $this->wpdb->get_charset_collate();

		$sql = "CREATE TABLE `{$table_name}` (
			id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
			type VARCHAR(100) NOT NULL,
			sub_type VARCHAR(100) NOT NULL,
			status VARCHAR(50) NOT NULL DEFAULT 'pending',
			progress_percent DECIMAL(5,2) DEFAULT 0.00 NOT NULL,
			chatbot_uuid char(36) NULL,
			config LONGTEXT NULL,
			stats LONGTEXT NULL,
			errors LONGTEXT NULL,
			created_at datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
			started_at datetime NULL,
			completed_at datetime NULL,
			PRIMARY KEY (id),
			KEY type (type),
			KEY sub_type (sub_type),
			KEY status (status),
			KEY chatbot_uuid (chatbot_uuid),
			KEY created_at (created_at),
			KEY status_type (status, type)
		) {$collate};";

		$results = $this->db_delta( $sql );

		// Verify table was created
		if ( ! $this->table_exists( $table_name ) ) {
			$this->log( "Failed to create table {$table_name}", 'error' );

			return false;
		}

		$this->log( "Successfully created table {$table_name}" );

		return true;
	}

	/**
	 * Create the lbaic_tasks table.
	 *
	 * Stores individual tasks for each job with payload, status, and error tracking.
	 * Supports retry logic with attempt counting.
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.0.9
	 */
	private function create_tasks_table(): bool {
		$table_name = $this->wpdb->prefix . 'lbaic_job_tasks';

		// Check if table already exists
		if ( $this->table_exists( $table_name ) ) {
			$this->log( "Table {$table_name} already exists, skipping creation" );

			return true;
		}

		$collate = $this->wpdb->get_charset_collate();

		$sql = "CREATE TABLE `{$table_name}` (
			id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
			job_id bigint(20) unsigned NOT NULL,
			parent_task_id bigint(20) unsigned NULL,
			payload LONGTEXT NOT NULL,
			status VARCHAR(50) NOT NULL DEFAULT 'pending',
			attempt_count INT DEFAULT 0 NOT NULL,
			error TEXT NULL,
			task_started_at datetime NULL,
			task_completed_at datetime NULL,
			PRIMARY KEY (id),
			KEY job_id (job_id),
			KEY parent_task_id (parent_task_id),
			KEY status (status),
			KEY job_status (job_id, status),
			KEY job_parent_status (job_id, parent_task_id, status)
		) {$collate};";

		$results = $this->db_delta( $sql );

		// Verify table was created
		if ( ! $this->table_exists( $table_name ) ) {
			$this->log( "Failed to create table {$table_name}", 'error' );

			return false;
		}

		$this->log( "Successfully created table {$table_name}" );

		return true;
	}

	private function knowledge_settings() {
		$default_chatbot = Chatbot::make();
		$config          = $default_chatbot->get_config();
		if ( ! $config instanceof Config ) {
			// This means that the chatbot is not set-up yet
			return true;
		}
		$this->maybe_add_setting( 'lbaic.utilities.chatbot.kb_config_id', $config->get_id() );
		$default_embedding_model = $config->get_related_to_instance()->get_default_embedding_model();
		if ( $default_embedding_model instanceof AI_Model ) {
			$this->maybe_add_setting( 'lbaic.utilities.chatbot.kb_ai_model_id', $default_embedding_model->get_id() );
		}
		$this->maybe_add_setting( 'lbaic.utilities.chatbot.kb_sources_section_items_count', 3 );

		$vector_indexes = Vector_Index::where( [], - 1, - 1 );
		if ( ! $vector_indexes->is_empty() ) {
			$vector_indexes->each( function ( Vector_Index $index ) {
				if ( ! $index->get_meta( 'chatbot_uuid' ) instanceof Vector_Index_Meta ) {
					Vector_Index_Meta::create( [
						'vector_index_id' => $index->get_id(),
						'meta_key'        => 'chatbot_uuid',
						'meta_value'      => null
					] );
				}
			} );
		}

		return true;
	}
}

