<?php
/**
 * WooCommerce Widget Manager for BoostBot.
 *
 * Handles the lifecycle of auto-managed WooCommerce widgets based on
 * preset configuration. When a WooCommerce preset is linked to a bot,
 * this service creates/deletes per-bot widget instances and junction
 * entries according to the preset's capability toggles.
 *
 * Self-healing: on every sync, cleans up legacy shared widgets and
 * deduplicates managed widgets so each bot has exactly one managed
 * WC widget per type (or zero if no preset).
 *
 * @package BoostBot
 * @since   1.2.0
 */

// Prevent direct access.
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class BoostBot_WooCommerce_Widget_Manager
 */
class BoostBot_WooCommerce_Widget_Manager {

	/**
	 * WooCommerce widget types that are auto-managed.
	 */
	const MANAGED_TYPES = array( 'product_card', 'coupon', 'bundle_builder' );

	/**
	 * Synchronize a bot's WooCommerce widgets with its linked preset.
	 *
	 * Self-healing: finds ALL WC widgets (managed + legacy shared),
	 * keeps exactly one managed widget per desired type, unassigns
	 * everything else, and deletes orphans.
	 *
	 * @param int      $bot_id    The bot ID.
	 * @param int|null $preset_id The preset ID, or null to unlink.
	 */
	public function sync_bot_widgets( int $bot_id, ?int $preset_id ): void {
		global $wpdb;

		$widget_model = new BoostBot_Widget_Model();

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$all_wc_widgets = $wpdb->get_results( $wpdb->prepare(
			"SELECT w.id, w.type, w.name, w.language, w.is_system_managed
			 FROM {$wpdb->prefix}boostbot_widgets w
			 JOIN {$wpdb->prefix}boostbot_chatbot_widgets cw ON w.id = cw.widget_id
			 WHERE cw.chatbot_id = %d
			 AND w.type IN ('product_card', 'coupon', 'bundle_builder')",
			$bot_id
		) );

		$managed_count = 0;
		$legacy_count  = 0;
		foreach ( $all_wc_widgets as $w ) {
			if ( $w->is_system_managed ) {
				$managed_count++;
			} else {
				$legacy_count++;
			}
		}

		if ( class_exists( 'BoostBot_Logger' ) ) {
			BoostBot_Logger::debug( '[WC Widget Manager] Sync started for bot ' . $bot_id, array(
				'preset_id'    => $preset_id,
				'total_wc'     => count( $all_wc_widgets ),
				'managed'      => $managed_count,
				'legacy'       => $legacy_count,
			) );
		}

		if ( null === $preset_id ) {
			$this->remove_all_wc_widgets_for_bot( $bot_id, $all_wc_widgets, $widget_model );
			return;
		}

		$preset_model = new BoostBot_WooCommerce_Preset_Model();
		$preset       = $preset_model->get( $preset_id );

		if ( ! $preset ) {
			return;
		}

		$bot_language = $this->resolve_bot_language( $bot_id, $preset );
		$desired_types = $this->get_desired_types( $preset );

		$by_type = array();
		foreach ( $all_wc_widgets as $w ) {
			$by_type[ $w->type ][] = $w;
		}

		$unassigned_count = 0;
		$deleted_count    = 0;
		$created_count    = 0;

		foreach ( self::MANAGED_TYPES as $type ) {
			$widgets_of_type = $by_type[ $type ] ?? array();

			if ( ! in_array( $type, $desired_types, true ) ) {
				// Type not desired — remove all widgets of this type from this bot.
				foreach ( $widgets_of_type as $widget ) {
					$widget_model->unassign_from_chatbot( (int) $widget->id, $bot_id );
					$unassigned_count++;
					if ( $this->delete_widget_if_orphaned( (int) $widget->id, $widget_model, (bool) $widget->is_system_managed ) ) {
						$deleted_count++;
					}
				}
				continue;
			}

			// Type is desired — separate managed vs legacy.
			$managed_widgets = array();
			$legacy_widgets  = array();
			foreach ( $widgets_of_type as $widget ) {
				if ( $widget->is_system_managed ) {
					$managed_widgets[] = $widget;
				} else {
					$legacy_widgets[] = $widget;
				}
			}

			// Unassign all legacy widgets from this bot.
			foreach ( $legacy_widgets as $widget ) {
				$widget_model->unassign_from_chatbot( (int) $widget->id, $bot_id );
				$unassigned_count++;
				if ( $this->delete_widget_if_orphaned( (int) $widget->id, $widget_model, false ) ) {
					$deleted_count++;
				}
			}

			$desired_name = $this->get_managed_widget_name( $type, $preset, $bot_language );

			if ( empty( $managed_widgets ) ) {
				$need_create = true;
			} else {
				// Keep the first managed widget, unassign and delete extras.
				$keep = $managed_widgets[0];

				for ( $i = 1, $cnt = count( $managed_widgets ); $i < $cnt; $i++ ) {
					$extra = $managed_widgets[ $i ];
					$widget_model->unassign_from_chatbot( (int) $extra->id, $bot_id );
					$unassigned_count++;
					if ( $this->delete_widget_if_orphaned( (int) $extra->id, $widget_model, true ) ) {
						$deleted_count++;
					}
				}

				// If the kept widget is shared with other bots, replace it with a dedicated one.
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$assignment_count = (int) $wpdb->get_var( $wpdb->prepare(
					"SELECT COUNT(*) FROM {$wpdb->prefix}boostbot_chatbot_widgets WHERE widget_id = %d",
					(int) $keep->id
				) );

				if ( $assignment_count > 1 ) {
					$widget_model->unassign_from_chatbot( (int) $keep->id, $bot_id );
					$unassigned_count++;
					$need_create = true;

					if ( class_exists( 'BoostBot_Logger' ) ) {
						BoostBot_Logger::info( '[WC Widget Manager] Replacing shared managed widget with dedicated one', array(
							'widget_id'        => (int) $keep->id,
							'type'             => $type,
							'bot_id'           => $bot_id,
							'assignment_count' => $assignment_count,
						) );
					}
				} else {
					$need_create = false;
					$updates     = array();
					if ( ( $keep->name ?? '' ) !== $desired_name ) {
						$updates['name'] = $desired_name;
					}
					if ( ( $keep->language ?? '' ) !== $bot_language ) {
						$updates['language'] = $bot_language;
					}
					if ( ! empty( $updates ) ) {
						$widget_model->update( (int) $keep->id, $updates );
					}
				}
			}

			if ( $need_create ) {
				$widget_id = $widget_model->create( array(
					'name'              => $desired_name,
					'type'              => $type,
					'config'            => wp_json_encode( array( 'managed_by_preset' => (int) $preset_id ) ),
					'is_active'         => 1,
					'is_system_managed' => 1,
					'language'          => $bot_language,
				) );

				if ( $widget_id ) {
					$widget_model->assign_to_chatbot( $widget_id, $bot_id );
					$created_count++;
				}
			}
		}

		if ( class_exists( 'BoostBot_Logger' ) ) {
			BoostBot_Logger::info( '[WC Widget Manager] Sync complete for bot ' . $bot_id, array(
				'preset_id'       => $preset_id,
				'unassigned'      => $unassigned_count,
				'deleted_orphans' => $deleted_count,
				'created_new'     => $created_count,
			) );
		}
	}

	/**
	 * Remove ALL WooCommerce widgets for a bot (managed + legacy).
	 *
	 * Used when a bot has no preset (or preset is unlinked).
	 *
	 * @param int                  $bot_id         The bot ID.
	 * @param array                $all_wc_widgets Pre-fetched WC widgets for this bot.
	 * @param BoostBot_Widget_Model $widget_model   Widget model instance.
	 */
	private function remove_all_wc_widgets_for_bot( int $bot_id, array $all_wc_widgets, BoostBot_Widget_Model $widget_model ): void {
		$unassigned_count = 0;
		$deleted_count    = 0;

		foreach ( $all_wc_widgets as $w ) {
			$widget_model->unassign_from_chatbot( (int) $w->id, $bot_id );
			$unassigned_count++;
			if ( $this->delete_widget_if_orphaned( (int) $w->id, $widget_model, (bool) $w->is_system_managed ) ) {
				$deleted_count++;
			}
		}

		if ( class_exists( 'BoostBot_Logger' ) ) {
			BoostBot_Logger::info( '[WC Widget Manager] Removed all WC widgets for bot ' . $bot_id . ' (no preset)', array(
				'unassigned'      => $unassigned_count,
				'deleted_orphans' => $deleted_count,
			) );
		}
	}

	/**
	 * Delete a widget if it has no remaining bot assignments.
	 *
	 * Managed widgets are always deleted when orphaned.
	 * Legacy widgets are also deleted when orphaned to avoid accumulating stale rows.
	 *
	 * @param int                   $widget_id     Widget ID.
	 * @param BoostBot_Widget_Model $widget_model  Widget model instance.
	 * @param bool                  $is_managed    Whether the widget is system-managed.
	 * @return bool True if the widget was deleted.
	 */
	private function delete_widget_if_orphaned( int $widget_id, BoostBot_Widget_Model $widget_model, bool $is_managed ): bool {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$remaining = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$wpdb->prefix}boostbot_chatbot_widgets WHERE widget_id = %d",
			$widget_id
		) );

		if ( 0 === $remaining ) {
			if ( class_exists( 'BoostBot_Logger' ) ) {
				BoostBot_Logger::info( '[WC Widget Manager] Deleting orphaned widget', array(
					'widget_id'  => $widget_id,
					'is_managed' => $is_managed,
				) );
			}
			$widget_model->delete_with_fields( $widget_id );
			return true;
		}

		return false;
	}

	/**
	 * Resolve the bot's language.
	 *
	 * @param int    $bot_id The bot ID.
	 * @param object $preset The preset object (fallback).
	 * @return string Language code.
	 */
	private function resolve_bot_language( int $bot_id, $preset ): string {
		$bot_language = 'he';
		if ( class_exists( 'BoostBot_Bot_Model' ) ) {
			$bot = ( new BoostBot_Bot_Model() )->get( $bot_id );
			if ( ! empty( $bot->language ) ) {
				$bot_language = (string) $bot->language;
			}
		}
		if ( empty( $bot_language ) ) {
			$bot_language = $preset->language ?? 'he';
		}
		return $bot_language;
	}

	/**
	 * Determine which WC widget types the preset wants enabled.
	 *
	 * @param object $preset The preset object.
	 * @return array<string> Desired widget types.
	 */
	private function get_desired_types( $preset ): array {
		$desired_types = array();

		if ( ! isset( $preset->product_card_enabled ) || ! empty( $preset->product_card_enabled ) ) {
			$desired_types[] = 'product_card';
		}
		if ( ! empty( $preset->coupon_enabled ) ) {
			$desired_types[] = 'coupon';
		}
		if ( ! empty( $preset->bundle_enabled ) ) {
			$desired_types[] = 'bundle_builder';
		}

		return $desired_types;
	}

	/**
	 * Generate a descriptive name for a managed widget.
	 *
	 * @param string $type     Widget type.
	 * @param object $preset   Preset object.
	 * @param string $language Language code.
	 * @return string Widget name.
	 */
	private function get_managed_widget_name( string $type, $preset, string $language = 'he' ): string {
		$is_english = 'en' === strtolower( $language );
		$names      = array(
			'product_card'   => $is_english ? 'Product Card' : 'כרטיס מוצר',
			'coupon'         => $is_english ? 'Coupon' : 'קופון',
			'bundle_builder' => $is_english ? 'Bundle Builder' : 'בונה חבילות',
		);
		$suffix     = $preset->name ?? ( $is_english ? 'Managed' : 'מנוהל' );

		return ( $names[ $type ] ?? $type ) . ' (' . $suffix . ')';
	}
}
