<?php

namespace Limb_Chatbot\Includes\Services;

use Limb_Chatbot\Includes\Chatbot_Tools\Seeders\Actions_Seeder;
use Limb_Chatbot\Includes\Data_Objects\Lead_Field;
use Limb_Chatbot\Includes\Services\System_Message\Chatbot_System_Message_Generator;
use Exception;
use Limb_Chatbot\Includes\Ai_Providers\AI_Providers;
use Limb_Chatbot\Includes\Data_Objects\Chatbot;
use Limb_Chatbot\Includes\Data_Objects\Setting;
use Limb_Chatbot\Includes\Data_Schemas;
use Limb_Chatbot\Includes\Database_Strategies\WPDB;
use Limb_Chatbot\Includes\Utilities\Chatbot_Utility;

/**
 * Class Seeder_Service
 *
 * Responsible for seeding initial data such as AI models and default settings.
 *
 * @since 1.0.0
 */
class Seeder_Service {
	/**
	 * @var false|mixed
	 */
	private bool $force = false;

	public function __construct( $force = false ) {
		$this->force = $force;
	}
	/**
	 * Runs the seeding process inside a transaction, handling errors gracefully.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function seed(): void {
		$wpdb = WPDB::instance();
		register_shutdown_function( function () {
			$error = error_get_last();
			if ( $error && in_array( $error['type'], [ E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR ] ) ) {
				$this->store_activation_error( $error );
			}
		} );
		try {
			$wpdb->start_transaction();
			$this->seed_ai_models();
			$this->seed_lead_fields();
			$this->seed_setting_defaults();
			$this->seed_system_instructions();
			$this->seed_actions();
			$wpdb->commit_transaction();
		} catch ( Exception $e ) {
			$wpdb->rollback_transaction();
			$this->store_activation_error( $e );
		}
	}

	/**
	 * Adds a setting if it does not already exist.
	 *
	 * @param string $key   Setting key.
	 * @param mixed  $value Setting value.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	private function maybe_add_setting( $key, $value ): void {
		if ( $this->force ) {
			Setting::create( [ 'key' => $key, 'value' => $value ] );
		} else {
			if ( ! Setting::exists( $key ) ) {
				Setting::create( [ 'key' => $key, 'value' => $value ] );
			}
		}
	}

	/**
	 * Stores an activation error in the settings for later inspection.
	 *
	 * @param mixed $error Error object or array describing the error.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	private function store_activation_error( $error ): void {
		$is_object = is_object( $error );
		Setting::update( [ 'key' => 'lbaic.plugins.'.Limb_Chatbot()->get_plugin_name().'.activation_error' ], [
			'value' => json_encode( [
				'type'    => $is_object ? get_class( $error ) : 'fatal',
				'message' => $is_object ? $error->getMessage() : $error,
				'file'    => $is_object ? $error->getFile() : '',
				'line'    => $is_object ? $error->getLine() : '',
				'trace'   => $is_object ? $error->getTraceAsString() : '',
				'time'    => current_time( 'mysql' ),
			] )
		] );
	}

	/**
	 * Seeds AI models by running the seeders provided by all registered AI providers.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	private function seed_ai_models(): void {
		foreach ( AI_Providers::instance()->get_ai_providers() as $ai_provider ) {
			$models_seeder = "Limb_Chatbot\\Includes\\AI_Providers\\{$ai_provider::$name}\\Seeders\\AI_Models_Seeder";
			if ( class_exists( $models_seeder ) ) {
				$models_seeder = new $models_seeder();
				$models_seeder->run();
			}
		}
	}

	/**
	 * Seeds default settings based on rules defined in the data schemas.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	private function seed_setting_defaults(): void {
		foreach (
		( Data_Schemas\Setting::general_rules() + Data_Schemas\Setting::chatbot_rules() + Data_Schemas\Setting::kb_rules() + Data_Schemas\Setting::fine_tuning_rules() + Data_Schemas\Setting::ai_provider_rules() + Data_Schemas\Setting::copilot_rules() + Data_Schemas\Setting::notification_rules()  )
			as $key => $rule
		) {
			if ( isset( $rule['default'] ) ) {
				$this->maybe_add_setting( $key, $rule['default'] );
			}
		}
		$this->maybe_add_setting( 'lbaic.plugin.current_version', Limb_Chatbot()->get_version() );
	}

	/**
	 * Save default system instructions for the default chatbot
	 *
	 * @return void
	 * @throws Exception
	 */
	private function seed_system_instructions() {
		$chatbot                  = Chatbot::make(); // default chatbot
		$system_message_generator = new Chatbot_System_Message_Generator ();
		$chatbot_utility          = new Chatbot_Utility( $chatbot, true );
		$internal_system          = $system_message_generator->generate( $chatbot_utility );
		$chatbot->update_parameter( 'internal_system_message', $internal_system );
	}

	/**
	 * Seeds the actions with callbacks for testing
	 *
	 * @return void
	 */
	private function seed_actions () {
		$forms_seeder = new Actions_Seeder();
		$forms_seeder->seed();
	}

	public function seed_lead_fields() {
		try {
			// Check if default fields already exist
			$name_fields  = Lead_Field::where( [ 'field_key' => 'full_name' ] );
			$email_fields = Lead_Field::where( [ 'field_key' => 'email' ] );

			// Create email field if it doesn't exist
			if ( $email_fields->is_empty() ) {
				Lead_Field::create( [
					'field_key' => 'email',
					'label'     => 'Email Address',
					'data_type' => 'email',
				] );
			}

			// Create full_name field if it doesn't exist
			if ( $name_fields->is_empty() ) {
				Lead_Field::create( [
					'field_key' => 'full_name',
					'label'     => 'Full Name',
					'data_type' => 'string',
				] );
			}

			return true;
		} catch ( \Exception $e ) {
			return false;
		}
	}
}