<?php

namespace Limb_Chatbot\Includes\Services;

use Exception;
use Limb_Chatbot\Includes\Data_Objects\Chatbot_User;
use Limb_Chatbot\Includes\Data_Objects\Widget;
use Limb_Chatbot\Includes\Repositories\Chatbot_Repository;
use Limb_Chatbot\Includes\Services\Preview_State;

class Chatbot_Payload {
	const FRONTEND_SETTINGS = [
		'lbaic.utilities.chatbot.icon_bg_shape'       => 'squircle',
		'lbaic.utilities.chatbot.avatar_visibility'   => 1,
		'lbaic.utilities.chatbot.icon'                => 1,
		'lbaic.utilities.chatbot.avatar'              => 11,
		'lbaic.utilities.chatbot.stream'              => 1,
		'lbaic.utilities.chatbot.title'               => 'AI Agent',
		'lbaic.utilities.chatbot.theme'               => 'system',
		'lbaic.utilities.chatbot.color'               => '#458cf5',
		'lbaic.utilities.chatbot.show_in_side'        => 'right',
		'lbaic.utilities.chatbot.appearing_animation' => 'scale-smooth',
		'lbaic.utilities.chatbot.shadow_dom'          => '1',
	];
	private Chatbot_Repository $chatbot_repository;

	public function __construct() {
		$this->chatbot_repository = new Chatbot_Repository();
	}

	public function prepare( bool $preview = false ) {
		$settings = $this->chatbot_repository->get_settings( array_keys( self::FRONTEND_SETTINGS ) );
		$preview_parameters = array();
		$preview_widgets    = array();
		$widgets_override   = false;
		if ( $preview ) {
			$preview_state     = Preview_State::load();
			$preview_parameters = $preview_state->get_parameters();
			$preview_widgets    = $preview_state->get_widgets();
			$widgets_override   = $preview_state->widgets_override_enabled();
		}
		foreach ( self::FRONTEND_SETTINGS as $key => $value ) {
			$key_arg = str_replace( 'lbaic.utilities.chatbot.', '', $key );
			if ( $preview && array_key_exists( $key, $preview_parameters ) ) {
				$value_arg = $preview_parameters[ $key ];
			} else {
				if ( ! isset( $settings[ $key ] ) ) {
					$value_arg = self::FRONTEND_SETTINGS[ $key ];
				} else {
					$value_arg = $settings[ $key ];
				}
			}
			if ( is_numeric( $value_arg ) ) {
				$value_arg = (int) $value_arg;
			}
			if ( is_string( $value_arg ) && 'lbaic.utilities.chatbot.title' === $key ) {
				$value_arg = apply_filters(
					'lbaic_translate_dynamic_string',
					$value_arg,
					'chatbot.title',
					[
						'scope' => 'chatbot_title',
					]
				);
			}
			$settings_response[ $key_arg ] = $value_arg;
		}

		if ( $preview && $widgets_override && is_array( $preview_widgets ) ) {
			$widgets = array_map(
				function ( $widget_item ) {
					// Preview-state widgets may be stored as sanitized arrays.
					if ( is_array( $widget_item ) ) {
						$widget = new Widget( $widget_item );
					} elseif ( $widget_item instanceof Widget ) {
						$widget = $widget_item;
					} else {
						return $widget_item;
					}

					// The JSON serializer only includes `meta_properties` when present
					// in `$widget->included`, so we explicitly attach it here.
					if ( empty( $widget->included['dependencies'] ) ) {
						$widget->included['dependencies'] = $widget->dependencies();
					}

					return $widget;
				},
				$preview_widgets
			);
		} else {
			$widgets = $this->get_payload_widgets_for_current_user();
		}
		if ( isset( $settings_response['shadow_dom'] ) && $settings_response['shadow_dom'] == 1 ) {
			$limb_chatbot                            = Limb_Chatbot();
			$plugin_dir_url                          = $limb_chatbot->get_plugin_dir_url();
			$plugin_version                          = $limb_chatbot->get_version();
			$settings_response['shadow_dom_css_url'] = $plugin_dir_url . 'dist/public/lbaic-chatbot.css?ver=' . $plugin_version;
		}

		$widgets = $this->translate_widget_payload_strings( $widgets );

		return array_merge( ( $settings_response ?? [] ), [ 'widgets' => $widgets ] );
	}

	/**
	 * Translate widget config strings for frontend rendering.
	 *
	 * @param array<int,mixed> $widgets Widget payload.
	 *
	 * @return array<int,mixed>
	 */
	private function translate_widget_payload_strings( array $widgets ): array {
		foreach ( $widgets as $index => $widget ) {
			if ( ! $widget instanceof Widget ) {
				continue;
			}

			$widget_ref      = '' !== trim( $widget->get_uuid() ) ? $widget->get_uuid() : (string) $widget->get_id();
			$translated_data = apply_filters(
				'lbaic_translate_widget_config',
				$widget->get_config(),
				$widget_ref,
				$widget->get_type()
			);
			if ( is_array( $translated_data ) ) {
				$widget->set_config( $translated_data );
			}

			$widgets[ $index ] = $widget;
		}

		return $widgets;
	}

	/**
	 * Load published widgets ordered by `order` and filter by current user roles.
	 *
	 * @return array<int,array<string,mixed>>
	 * @throws Exception
	 * @since 2.0.0
	 */
	private function get_payload_widgets_for_current_user(): array {
		$items = Widget::where( [ 'published' => 1 ], - 1, 1, '`order`', 'ASC' )->get();
		if ( empty( $items ) ) {
			return [];
		}
		$widgets = [];

		foreach ( $items as $widget ) {
			if ( ! $widget instanceof Widget ) {
				continue;
			}
			if ( ! $widget->is_visible_for_current_user() ) {
				continue;
			}

			// JSON serialization only includes `meta_properties` from `$widget->included`.
			if ( empty( $widget->included['dependencies'] ) ) {
				$widget->included['dependencies'] = $widget->dependencies();
			}

			$widgets[] = $widget;
		}

		return $widgets;
	}
}
