<?php

namespace Limb_Chatbot\Includes\Migrations;

use Limb_Chatbot\Includes\AI_Providers\Claude\Claude;
use Limb_Chatbot\Includes\AI_Providers\Claude\Seeders\AI_Models_Seeder as Claude_AI_Models_Seeder;
use Limb_Chatbot\Includes\AI_Providers\Deep_Seek\Deep_Seek;
use Limb_Chatbot\Includes\AI_Providers\Deep_Seek\Seeders\AI_Models_Seeder as Deep_Seek_AI_Models_Seeder;
use Limb_Chatbot\Includes\Data_Objects\AI_Model;
use Limb_Chatbot\Includes\Data_Objects\Chatbot;
use Limb_Chatbot\Includes\Data_Objects\Setting;

/**
 * Migration for version 1.1.0
 *
 * Seeds DeepSeek and Claude AI models and their default settings.
 * Ensures all models and provider settings are properly initialized.
 *
 * @since 1.1.0
 */
class Migration_1_0_10 extends Abstract_Migration {

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

	/**
	 * Get migration description.
	 *
	 * @return string
	 * @since 1.1.0
	 */
	public function get_description(): string {
		return 'Seed DeepSeek and Claude AI models and initialize provider settings';
	}

	/**
	 * Execute the migration.
	 *
	 * Seeds AI models for DeepSeek and Claude providers, and ensures
	 * their default settings are created if they don't exist.
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.1.0
	 */
	public function up(): bool {
		$this->log( 'Starting migration 1.1.0 - Seeding DeepSeek and Claude models' );

		// Seed DeepSeek AI models
		if ( ! $this->seed_deep_seek_models() ) {
			$this->log( 'Failed to seed DeepSeek models', 'error' );
			return false;
		}

		// Seed Claude AI models
		if ( ! $this->seed_claude_models() ) {
			$this->log( 'Failed to seed Claude models', 'error' );
			return false;
		}

		// Seed provider settings if they don't exist
		if ( ! $this->seed_provider_settings() ) {
			$this->log( 'Failed to seed provider settings', 'error' );
			return false;
		}

		// Seed kb settings problem
		if ( ! $this->seed_kb_settings() ) {
			$this->log( 'Failed to seed KB settings problem', 'error' );

			return false;
		}

		$this->log( 'Migration 1.1.0 completed successfully - DeepSeek and Claude models seeded' );

		return true;
	}

	/**
	 * Seed DeepSeek AI models.
	 *
	 * Runs the DeepSeek AI models seeder to create or update models.
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.1.0
	 */
	private function seed_deep_seek_models(): bool {
		try {
			$this->log( 'Seeding DeepSeek AI models' );

			$seeder = new Deep_Seek_AI_Models_Seeder();
			$seeder->run();

			$this->log( 'DeepSeek AI models seeded successfully' );

			return true;
		} catch ( \Exception $e ) {
			$this->log( sprintf( 'Error seeding DeepSeek models: %s', $e->getMessage() ), 'error' );

			return false;
		}
	}

	/**
	 * Seed Claude AI models.
	 *
	 * Runs the Claude AI models seeder to create or update models.
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.1.0
	 */
	private function seed_claude_models(): bool {
		try {
			$this->log( 'Seeding Claude AI models' );

			$seeder = new Claude_AI_Models_Seeder();
			$seeder->run();

			$this->log( 'Claude AI models seeded successfully' );

			return true;
		} catch ( \Exception $e ) {
			$this->log( sprintf( 'Error seeding Claude models: %s', $e->getMessage() ), 'error' );

			return false;
		}
	}

	/**
	 * Seed provider settings from data schemas.
	 *
	 * Ensures all default settings for DeepSeek and Claude providers
	 * are created if they don't already exist. Settings are re-evaluated
	 * after models are seeded to ensure defaults that depend on models work correctly.
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.1.0
	 */
	private function seed_provider_settings(): bool {
		try {
			$this->log( 'Seeding provider settings from data schemas' );

			// Get all AI provider rules which includes DeepSeek and Claude settings
			// This is called after models are seeded, so defaults that depend on models will work
			$provider_rules = [];
			foreach ( [
				new Deep_Seek(),
				new Claude(),
			] as $ai_provider ) {
				$settings = "Limb_Chatbot\\Includes\\AI_Providers\\{$ai_provider::$name}\\Data_Schemas\\Setting";
				if ( class_exists( $settings ) ) {
					$provider_rules = array_merge( $provider_rules, $settings::rules() );
				}
			}

			$settings_created = 0;
			foreach ( $provider_rules as $key => $rule ) {
				// Only create settings that have defaults and don't exist
				if ( isset( $rule['default'] ) && ! Setting::exists( $key ) ) {
					$default_value = $rule['default'];

					// Default values are evaluated when the schema is loaded,
					// so they should already be the correct values after models are seeded
					if ( $default_value !== null ) {
						$this->maybe_add_setting( $key, $default_value );
						$settings_created++;
					}
				}
			}

			if ( $settings_created > 0 ) {
				$this->log( sprintf( 'Created %d provider settings', $settings_created ) );
			} else {
				$this->log( 'All provider settings already exist' );
			}

			$this->log( 'Provider settings seeded successfully' );

			return true;
		} catch ( \Exception $e ) {
			$this->log( sprintf( 'Error seeding provider settings: %s', $e->getMessage() ), 'error' );

			return false;
		}
	}

	private function seed_kb_settings() {
		try {
			$chatbot = Chatbot::make();
			$chatbot->update_parameter( 'avatar_visibility', 0 );

			$kb_config_id = $chatbot->get_parameter( 'kb_config_id' );
			$ai_model_id  = $chatbot->get_parameter( 'kb_ai_model_id' );
			if ( empty( $kb_config_id ) && empty( $ai_model_id ) ) {
				$config              = $chatbot->get_config();
				$related_to_instance = $config->get_related_to_instance();
				if ( method_exists( $related_to_instance, 'get_default_embedding_model' ) ) {
					$default_embedding_model = $related_to_instance->get_default_embedding_model();
					if ( $default_embedding_model instanceof AI_Model ) {
						$chatbot->update_parameter( 'kb_ai_model_id', $default_embedding_model->get_id() );
						$chatbot->update_parameter( 'kb_config_id', $config->get_id() );
					}
				}
			}
		} catch ( \Exception $e ) {
			$this->log( sprintf( 'Error updating chatbot avatar visibility: %s', $e->getMessage() ), 'error' );
		}

		return true;
	}
}

