<?php

namespace Limb_Chatbot\Includes\Migrations;

use Limb_Chatbot\Includes\Data_Objects\Chatbot;
use Limb_Chatbot\Includes\Data_Objects\Lead_Field;
use Limb_Chatbot\Includes\Data_Objects\Setting;
use Limb_Chatbot\Includes\Data_Schemas\Setting as Setting_Schema;

/**
 * Migration for version 1.0.14
 *
 * Updates custom_instructions and default_custom_instructions parameters
 * for the default chatbot with new concise response guidelines.
 *
 * @since 1.0.14
 */
class Migration_1_0_14 extends Abstract_Migration {

	/**
	 * Setting key prefix for notification type opt-in: lbaic.notifications.notification_type.{type_key}.
	 * Value 1 = enabled (send), 0 = disabled.
	 */
	const SETTING_NOTIFICATION_TYPE_PREFIX = 'lbaic.notifications.notification_type.';
	/**
	 * Notification type keys to enable by default (global opt-in settings).
	 *
	 * @var string[]
	 * @since 1.0.15
	 */
	private static array $default_notification_types = [ 'chat_created', 'lead_captured' ];

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

	/**
	 * Get migration description.
	 *
	 * @return string
	 * @since 1.0.14
	 */
	public function get_description(): string {
		return 'Update custom_instructions and migrate lead capture widgets to config-based field mapping';
	}

	/**
	 * Execute the migration.
	 *
	 * Updates the custom_instructions and default_custom_instructions parameters
	 * for the default chatbot with new guidelines emphasizing concise responses.
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.0.14
	 */
	public function up(): bool {
		$this->log( 'Starting migration 1.0.14 - Updating custom instructions and migrating lead capture widgets' );

		try {
			$chatbot = Chatbot::make();

			// Update custom instructions (role + guidelines; same as schema default)
			$custom_instructions = Setting_Schema::get_default_custom_instructions();

			$chatbot->update_parameter( 'custom_instructions', $custom_instructions );
			$chatbot->update_parameter( 'default_custom_instructions', $custom_instructions );

			// Migrate lead capture widgets to config-based format
			$this->migrate_lead_capture_widgets( $chatbot );

			if ( ! $this->create_notification_log_table() ) {
				return false;
			}

			$this->add_default_notification_opt_in_settings();

			$this->log( 'Migration 1.0.14 completed successfully' );

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

			return false;
		}
	}

	/**
	 * Migrate lead capture widgets to config-based field mapping
	 *
	 * Updates existing lead capture widgets to use config.lead_capture_map_field.
	 * Maps fields by name to Lead_Field field_key, removes fields without matches.
	 *
	 * @param  Chatbot  $chatbot  The chatbot instance
	 *
	 * @return void
	 * @since 1.0.14
	 */
	private function migrate_lead_capture_widgets( Chatbot $chatbot ): void {
		$widgets = Setting::find( 'lbaic.utilities.chatbot.widgets' )->get_value() ?? [];

		if ( empty( $widgets ) || ! is_array( $widgets ) ) {
			$this->log( 'No widgets found to migrate' );

			return;
		}

		$updated = false;

		foreach ( $widgets as &$widget ) {
			if ( ! is_array( $widget ) || ( $widget['type'] ?? '' ) !== 'lead_capture' ) {
				continue;
			}

			$fields = $widget['data']['fields'] ?? [];
			if ( empty( $fields ) || ! is_array( $fields ) ) {
				continue;
			}

			$migrated_fields = [];
			$fields_updated  = false;

			foreach ( $fields as $field ) {
				if ( ! is_array( $field ) ) {
					continue;
				}

				// If field already has config, keep it as is
				if ( isset( $field['config']['lead_capture_map_field'] ) ) {
					$migrated_fields[] = $field;
					continue;
				}

				// Try to find matching Lead_Field by field name
				$field_name = $field['name'] ?? '';
				$lead_field = $this->find_lead_field_by_name( $field_name );

				if ( $lead_field instanceof Lead_Field ) {
					// Add config with Lead_Field ID
					$field['config']   = [
						'lead_capture_map_field' => $lead_field->id,
					];
					$migrated_fields[] = $field;
					$fields_updated    = true;
					$this->log( sprintf( 'Mapped field "%s" to Lead_Field ID %d', $field_name, $lead_field->id ) );
				} else {
					// Remove field if no matching Lead_Field found
					$this->log( sprintf( 'Removed field "%s" - no matching Lead_Field found', $field_name ),
						'warning' );
					$fields_updated = true;
				}
			}

			if ( $fields_updated ) {
				$widget['data']['fields'] = $migrated_fields;
				$updated                  = true;
			}
		}

		if ( $updated ) {
			$chatbot->update_parameter( 'widgets', $widgets );
			$this->log( 'Successfully migrated lead capture widgets to config-based format' );
		} else {
			$this->log( 'No lead capture widgets needed migration' );
		}
	}

	/**
	 * Find Lead_Field by widget field name
	 *
	 * Maps common field names to Lead_Field field_keys.
	 *
	 * @param  string  $field_name  The widget field name
	 *
	 * @return Lead_Field|null
	 * @since 1.0.14
	 */
	private function find_lead_field_by_name( string $field_name ): ?Lead_Field {
		$normalized_name = strtolower( trim( $field_name ) );

		// Map common field names to Lead_Field field_keys
		$field_key_mapping = [
			'name'          => 'full_name',
			'full_name'     => 'full_name',
			'fullname'      => 'full_name',
			'email'         => 'email',
			'user_email'    => 'email',
			'email_address' => 'email',
		];

		$field_key = $field_key_mapping[ $normalized_name ] ?? null;

		if ( empty( $field_key ) ) {
			return null;
		}

		return Lead_Field::find_by_key( $field_key );
	}

	/**
	 * Create the lbaic_notification_log table.
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.0.15
	 */
	private function create_notification_log_table(): bool {
		$table_name = $this->wpdb->prefix . 'lbaic_notification_log';

		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,
			chatbot_user_id bigint(20) unsigned NOT NULL,
			type_key varchar(100) NOT NULL,
			channel varchar(50) NOT NULL,
			status varchar(20) NOT NULL DEFAULT 'pending',
			sent_at datetime NULL DEFAULT NULL,
			fail_reason TEXT NULL DEFAULT NULL,
			content_type varchar(100) NULL DEFAULT NULL,
			content LONGTEXT NULL DEFAULT NULL,
			PRIMARY KEY (id),
			KEY chatbot_user_id (chatbot_user_id),
			KEY type_key (type_key),
			KEY channel (channel),
			KEY status (status),
			KEY sent_at (sent_at)
		) {$collate};";

		$this->db_delta( $sql );

		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;
	}

	/**
	 * Add default (global) settings to enable all notification types for opt-in.
	 * When a chatbot user has no meta preference, these settings control whether to send.
	 *
	 * @return void
	 * @since 1.0.15
	 */
	private function add_default_notification_opt_in_settings(): void {
		foreach ( self::$default_notification_types as $type_key ) {
			$key = self::SETTING_NOTIFICATION_TYPE_PREFIX . $type_key;
			$this->maybe_add_setting( $key, 1 );
		}
		$this->log( 'Default notification opt-in settings added' );
	}
}
