<?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\Services\Helper;

/**
 * Migration for version 1.0.11
 *
 * Migrates widget structure from nested format to flat format.
 * Each widget item becomes a top-level entity with its own locations and notify properties.
 *
 * @since 1.0.11
 */
class Migration_1_0_11 extends Abstract_Migration {

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

	/**
	 * Get migration description.
	 *
	 * @return string
	 * @since 1.0.11
	 */
	public function get_description(): string {
		return 'Migrate widget structure from nested to flat format';
	}

	/**
	 * Execute the migration.
	 *
	 * Converts all widgets from nested structure (widgets containing items)
	 * to flat structure (items as top-level entities with their own locations/notify).
	 *
	 * @return bool True on success, false on failure.
	 * @since 1.0.11
	 */
	public function up(): bool {
		$this->log( 'Starting migration 1.0.11 - Migrating widgets to flat structure' );

		try {
			// Get all chatbots
			$chatbot = Chatbot::make();


			try {
				$this->migrate_chatbot_widgets( $chatbot );
			} catch ( \Exception $e ) {
				$this->log( sprintf( 'Error migrating chatbot %d: %s', $chatbot->get_id(), $e->getMessage() ),
					'error' );
			}

			// Seed lead capture widget for default chatbot
			try {
				$this->seed_lead_capture_widget( $chatbot );
			} catch ( \Exception $e ) {
				$this->log( sprintf( 'Error seeding lead capture widget: %s', $e->getMessage() ), 'error' );
			}

			$this->log( sprintf( 'Migration completed.' ) );

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

			return false;
		}
	}

	/**
	 * Migrate widgets for a specific chatbot.
	 *
	 * @param  Chatbot  $chatbot  The chatbot to migrate.
	 *
	 * @return bool True if migrated, false if already in new format.
	 * @since 1.0.11
	 */
	private function migrate_chatbot_widgets( Chatbot $chatbot ): bool {
		$widgets = Setting::find('lbaic.utilities.chatbot.widgets')->get_value() ?? [];

		if ( empty( $widgets ) ) {
			return false;
		}

		// Check if already in flat format
		if ( ! $this->is_nested_format( $widgets ) ) {
			$this->log( sprintf( 'Chatbot %d already uses flat format, skipping', $chatbot->get_id() ) );

			return false;
		}

		// Perform migration
		$migrated = $this->migrate_widgets( $widgets );

		if ( empty( $migrated ) ) {
			$this->log( sprintf( 'Chatbot %d: Widget migration resulted in empty data', $chatbot->get_id() ),
				'warning' );

			return false;
		}

		// Update chatbot with migrated widgets
		$chatbot->update_parameter( 'widgets', $migrated );

		$this->log( sprintf( 'Migrated %d widgets for chatbot %d', count( $migrated ), $chatbot->get_id() ) );

		return true;
	}

	/**
	 * Check if widgets are in nested format (old structure).
	 *
	 * @param  array  $widgets  Widget data to check.
	 *
	 * @return bool True if nested format, false if already flat.
	 * @since 1.0.11
	 */
	private function is_nested_format( $widgets ): bool {
		if ( ! is_array( $widgets ) || empty( $widgets ) ) {
			return false;
		}

		$first = reset( $widgets );
		if ( ! is_array( $first ) ) {
			return false;
		}

		// Nested format has 'items' array and 'locations' at widget level
		// Flat format has 'type' at top level
		return isset( $first['items'] ) && ! isset( $first['type'] );
	}

	/**
	 * Migrate widgets from nested to flat structure.
	 *
	 * Converts:
	 * From: [{"id":"w1","title":"..","locations":[..],"items":[{"id":"i1",...}]}]
	 * To:   [{"id":"i1","type":"...","locations":[..],...}]
	 *
	 * Widget titles are converted to type="text" widgets.
	 *
	 * @param  array  $old_widgets  Widgets in nested format.
	 *
	 * @return array Migrated widgets in flat format.
	 * @since 1.0.11
	 */
	private function migrate_widgets( array $old_widgets ): array {
		$new_widgets = [];

		foreach ( $old_widgets as $widget ) {
			if ( ! is_array( $widget ) ) {
				continue;
			}

			// Get widget-level properties to inherit to items
			$widget_locations = $widget['locations'] ?? [];
			$widget_notify    = isset( $widget['notify'] ) && $widget['notify'];
			$widget_published = isset( $widget['published'] ) && $widget['published'];
			$widget_title     = $widget['title'] ?? '';

			// If widget has a title, create a text widget for it
			if ( ! empty( $widget_title ) ) {
				$title_widget = [
					'id'        => Helper::random_string(),
					'type'      => 'text',
					'title'     => '',
					'published' => $widget_published,
					'notify'    => $widget_notify,
					'data'      => [
						'content' => $widget_title,
					],
					'locations' => $widget_locations,
				];
				$new_widgets[] = $title_widget;
			}

			// Process each item in the widget
			$items = $widget['items'] ?? [];
			if ( ! is_array( $items ) || empty( $items ) ) {
				continue;
			}

			foreach ( $items as $item ) {
				if ( ! is_array( $item ) ) {
					continue;
				}

				// Create new flat item
				$new_item = [
					'id'        => $item['id'] ?? '',
					'type'      => $item['type'] ?? 'prompt',
					'title'     => $item['title'] ?? '',
					'published' => isset( $item['published'] ) ? (bool) $item['published'] : $widget_published,
					'notify'    => $widget_notify,
					'data'      => $item['data'] ?? [],
					'locations' => $widget_locations,
				];

				// Preserve suggestions if present
				if ( isset( $item['suggestions'] ) ) {
					$new_item['suggestions'] = $item['suggestions'];
				}

				$new_widgets[] = $new_item;
			}
		}

		return $new_widgets;
	}

	/**
	 * Seed a lead capture widget for the default chatbot.
	 *
	 * Adds a lead capture form widget to collect user name and email
	 * when they start a new chat. Uses config-based field mapping.
	 *
	 * @param  Chatbot  $chatbot  The chatbot to seed the widget for.
	 *
	 * @return void
	 * @since 1.0.11
	 */
	private function seed_lead_capture_widget( Chatbot $chatbot ): void {
		// Get existing widgets
		$widgets = Setting::find( 'lbaic.utilities.chatbot.widgets' )->get_value() ?? [];

		// Check if lead capture widget already exists
		foreach ( $widgets as $widget ) {
			if ( isset( $widget['type'] ) && $widget['type'] === 'lead_capture' ) {
				$this->log( 'Lead capture widget already exists, skipping seed' );

				return;
			}
		}

		// Find Lead_Fields for mapping
		$name_field  = Lead_Field::find_by_key( 'full_name' );
		$email_field = Lead_Field::find_by_key( 'email' );

		$fields = [];

		// Add name field with config if Lead_Field exists
		if ( $name_field instanceof Lead_Field ) {
			$fields[] = [
				'type'        => 'text',
				'name'        => 'name',
				'required'    => true,
				'label'       => 'Name',
				'placeholder' => 'Enter your full name',
				'config'      => [
					'lead_capture_map_field' => $name_field->id,
				],
			];
		}

		// Add email field with config if Lead_Field exists
		if ( $email_field instanceof Lead_Field ) {
			$fields[] = [
				'type'        => 'email',
				'name'        => 'email',
				'required'    => true,
				'label'       => 'Email',
				'placeholder' => 'your@email.com',
				'config'      => [
					'lead_capture_map_field' => $email_field->id,
				],
			];
		}

		// Only create widget if we have fields with valid mappings
		if ( empty( $fields ) ) {
			$this->log( 'Cannot seed lead capture widget - no Lead_Fields found', 'warning' );
			return;
		}

		// Create new lead capture widget
		$lead_capture_widget = [
			'id'        => Helper::generate_unique_id(),
			'type'      => 'lead_capture',
			'title'     => '',
			'published' => false,
			'notify'    => false,
			'locations' => [
				[
					[
						'param'    => 'screen',
						'operator' => '===',
						'value'    => 'new_chat',
					],
				],
			],
			'data'      => [
				'heading'            => 'Start Chatting with AI 👋',
				'description'        => 'Please provide your details to begin your conversation with our AI assistant.',
				'submit_button_text' => 'Start chat',
				'fields'             => $fields,
			],
		];

		// Add widget to chatbot
		$widgets[] = $lead_capture_widget;
		$chatbot->update_parameter( 'widgets', $widgets );

		$this->log( 'Seeded lead capture widget for default chatbot' );
	}
}
