<?php

namespace Alexr\Whatsapp;

use Alexr\Models\Restaurant;
use Alexr\Models\WhatsappMessage;
use Alexr\Models\WhatsappConversation;
use Alexr\Settings\WhatsappAction;
use Alexr\Settings\WhatsappCustomAction;

class WhatsappKeywordHandler
{
	public static function register(): void
	{
		add_action('alexr_whatsapp_incoming_message', [self::class, 'handleIncomingMessage'], 10, 4);
	}

	/**
	 * Handle an incoming WhatsApp message and check against configured keyword actions
	 *
	 * Matching order:
	 * 1. Default actions (Reserve, Menu, Schedule, Human) — from WhatsappAction
	 * 2. Custom actions — from WhatsappCustomAction
	 * 3. Fallback — from WhatsappAction, only if nothing else matched
	 *    a) Try to detect language via fallback keywords (e.g. "hola", "hello")
	 *    b) If no keyword match, use restaurant's default language
	 *    c) If restaurant language has no response, use first language with a response
	 *
	 * @param array $parsed
	 * @param int $restaurantId
	 * @param WhatsappMessage $message
	 * @param WhatsappConversation $conversation
	 * @return void
	 */
	public static function handleIncomingMessage(
		array $parsed,
		int $restaurantId,
		WhatsappMessage $message,
		WhatsappConversation $conversation
	): void {

		// ---------------------------------------------------------------
		// Respect customer_status: skip auto-replies when:
		// - HUMAN_INTERACTION: an agent is actively handling this conversation
		// - AWAITING_REPLY: a template was sent and we're waiting for the
		//   customer's response — don't send auto-reply on that response.
		//   The status will transition to IDLE after this hook, so the
		//   NEXT incoming message will trigger auto-replies normally.
		// ---------------------------------------------------------------
		if ($conversation->isHumanInteraction() || $conversation->isAwaitingReply()) {
			return;
		}

		$body = strtolower(trim($message->body ?? ''));

		if (empty($body)) {
			return;
		}

		// Load default actions setting (single record, SettingSimpleGrouped)
		$defaultActions = WhatsappAction::where('restaurant_id', $restaurantId)->first();

		// ---------------------------------------------------------------
		// 1. Check default actions (Reserve, Menu, Schedule, Human)
		// ---------------------------------------------------------------
		if ($defaultActions) {
			$match = self::findMatchingDefaultAction($defaultActions, $body);

			if ($match) {
				self::sendDefaultActionResponse(
					$defaultActions, $match['key'], $match['lang'],
					$restaurantId, $message, $conversation
				);
				return;
			}
		}

		// ---------------------------------------------------------------
		// 2. Check custom actions (SettingListing, multiple records)
		// ---------------------------------------------------------------
		$customActions = WhatsappCustomAction::where('restaurant_id', $restaurantId)
		                                     ->orderBy('date_created', 'ASC')
		                                     ->get()
		                                     ->filter(function ($action) {
			                                     return $action->whatsapp_active;
		                                     });

		foreach ($customActions as $customAction) {
			$matchedLang = self::findMatchingLanguageInConfig($customAction->whatsapp_action, $body);

			if ($matchedLang !== null) {
				self::sendCustomActionResponse($customAction, $matchedLang, $restaurantId, $message, $conversation);
				return;
			}
		}

		// ---------------------------------------------------------------
		// 3. Fallback — only if nothing else matched
		// ---------------------------------------------------------------
		if ($defaultActions && $defaultActions->isActionEnabled('action_fallback')) {
			$fallbackLang = self::resolveFallbackLanguage($defaultActions, $body, $restaurantId);

			if ($fallbackLang) {
				self::sendDefaultActionResponse(
					$defaultActions, 'action_fallback', $fallbackLang,
					$restaurantId, $message, $conversation
				);
				return;
			}
		}
	}

	// ---------------------------------------------------------------
	// Matching: Default actions (except fallback)
	// ---------------------------------------------------------------

	/**
	 * Find matching default action across all languages.
	 * Skips fallback — that is handled separately.
	 *
	 * @param WhatsappAction $defaultActions
	 * @param string $body
	 * @return array|null ['key' => string, 'lang' => string]
	 */
	protected static function findMatchingDefaultAction(WhatsappAction $defaultActions, string $body): ?array
	{
		$keys = $defaultActions->getActionKeys();

		foreach ($keys as $key) {
			if ($key === 'action_fallback') {
				continue;
			}

			if (!$defaultActions->isActionEnabled($key)) {
				continue;
			}

			$lang = self::findMatchingLanguageInConfig($defaultActions->{$key}, $body);

			if ($lang !== null) {
				return ['key' => $key, 'lang' => $lang];
			}
		}

		return null;
	}

	// ---------------------------------------------------------------
	// Matching: Fallback language resolution
	// ---------------------------------------------------------------

	/**
	 * Resolve the language for the fallback action.
	 *
	 * 1. Try to match fallback keywords to detect language (e.g. "hola" -> es, "hello" -> en)
	 * 2. If no keyword match, use restaurant's default language
	 * 3. If restaurant language has no response configured, use first language with a response
	 *
	 * @param WhatsappAction $defaultActions
	 * @param string $body
	 * @param int $restaurantId
	 * @return string|null
	 */
	protected static function resolveFallbackLanguage(WhatsappAction $defaultActions, string $body, int $restaurantId): ?string
	{
		//ray('resolveFallbackLanguage:'.$restaurantId);

		$config = $defaultActions->action_fallback;

		if (!is_array($config) || empty($config)) {
			return null;
		}

		// 1. Try keyword match to detect language
		$matchedLang = self::findMatchingLanguageInConfig($config, $body);

		if ($matchedLang !== null) {
			return $matchedLang;
		}

		// 2. No keyword match — use restaurant's default language
		$restaurant = Restaurant::find($restaurantId);
		$restaurant_language = $restaurant->language ?? null;

		if ($restaurant && !empty($restaurant_language) && isset($config[$restaurant_language])) {
			if (self::hasResponseConfigured($config[$restaurant_language])) {
				return $restaurant_language;
			}
		}

		// 3. Use first language that has a response configured
		foreach ($config as $lang => $langConfig) {
			if (self::hasResponseConfigured($langConfig)) {
				return $lang;
			}
		}

		return null;
	}

	// ---------------------------------------------------------------
	// Shared matching helpers
	// ---------------------------------------------------------------

	/**
	 * Search for a keyword match across all languages in an action config array.
	 * Works for both default actions, custom actions, and fallback.
	 *
	 * @param mixed $config The per-language config array
	 * @param string $body The lowercased message body
	 * @return string|null The language code that matched, or null
	 */
	protected static function findMatchingLanguageInConfig($config, string $body): ?string
	{
		if (!is_array($config)) {
			return null;
		}

		foreach ($config as $lang => $langConfig) {
			if (empty($langConfig['keywords'])) {
				continue;
			}

			$keywords = array_map('trim', array_filter(explode(',', $langConfig['keywords'])));

			foreach ($keywords as $keyword) {
				$keywordLower = mb_strtolower(trim($keyword));
				if (!empty($keywordLower) && mb_strpos($body, $keywordLower) !== false) {
					return $lang;
				}
			}
		}

		return null;
	}

	/**
	 * Check if a language config has a response configured (template or custom message)
	 *
	 * @param array $langConfig
	 * @return bool
	 */
	protected static function hasResponseConfigured(array $langConfig): bool
	{
		return !empty($langConfig['template_sid']) || !empty($langConfig['custom_message']);
	}

	// ---------------------------------------------------------------
	// Response senders
	// ---------------------------------------------------------------

	/**
	 * Send response for a matched default action (from WhatsappAction / SettingSimpleGrouped)
	 *
	 * @param WhatsappAction $defaultActions
	 * @param string $actionKey e.g. 'action_reserve', 'action_fallback'
	 * @param string $lang
	 * @param int $restaurantId
	 * @param WhatsappMessage $message
	 * @param WhatsappConversation $conversation
	 * @return void
	 */
	protected static function sendDefaultActionResponse(
		WhatsappAction $defaultActions,
		string $actionKey,
		string $lang,
		int $restaurantId,
		WhatsappMessage $message,
		WhatsappConversation $conversation
	): void {

		$responseType = $defaultActions->getResponseType($actionKey, $lang);

		if ($responseType === 'template') {
			$templateConfig = $defaultActions->getTemplateConfig($actionKey, $lang);

			if (!$templateConfig || empty($templateConfig['template_sid'])) {
				return;
			}

			self::sendTemplateResponse(
				$templateConfig,
				$restaurantId,
				$message,
				$conversation,
				'whatsapp_action',
				$actionKey
			);
		} else {
			$customMessage = $defaultActions->getCustomMessage($actionKey, $lang);
			$actionConfig = $defaultActions->getActionConfig($actionKey, $lang);
			$bookNowWidgetId = $actionConfig['book_now_widget_id'] ?? null;

			self::sendCustomMessageResponse(
				$customMessage,
				$restaurantId,
				$message,
				$conversation,
				$bookNowWidgetId
			);
		}
	}

	/**
	 * Send response for a matched custom action (from WhatsappCustomAction / SettingListing)
	 *
	 * @param WhatsappCustomAction $action
	 * @param string $lang
	 * @param int $restaurantId
	 * @param WhatsappMessage $message
	 * @param WhatsappConversation $conversation
	 * @return void
	 */
	protected static function sendCustomActionResponse(
		WhatsappCustomAction $action,
		string $lang,
		int $restaurantId,
		WhatsappMessage $message,
		WhatsappConversation $conversation
	): void {

		$responseType = $action->getResponseType($lang);

		if ($responseType === 'template') {
			$templateConfig = $action->getTemplateConfig($lang);

			if (!$templateConfig || empty($templateConfig['template_sid'])) {
				return;
			}

			self::sendTemplateResponse(
				$templateConfig,
				$restaurantId,
				$message,
				$conversation,
				'whatsapp_custom_action',
				(string) $action->id
			);
		} else {
			$actionConfig = $action->getActionConfig($lang);
			$bookNowWidgetId = $actionConfig['book_now_widget_id'] ?? null;

			self::sendCustomMessageResponse(
				$action->getCustomMessage($lang),
				$restaurantId,
				$message,
				$conversation,
				$bookNowWidgetId
			);
		}
	}

	// ---------------------------------------------------------------
	// Shared response logic
	// ---------------------------------------------------------------

	/**
	 * Send a template response.
	 * If the conversation has a booking, delegate to the Booking model.
	 * If no booking, send directly via WhatsappManager with restaurant-level variables.
	 *
	 * @param array $templateConfig
	 * @param int $restaurantId
	 * @param WhatsappMessage $message
	 * @param WhatsappConversation $conversation
	 * @param string $sourceType
	 * @param string $sourceId
	 * @return void
	 */
	protected static function sendTemplateResponse(
		array $templateConfig,
		int $restaurantId,
		WhatsappMessage $message,
		WhatsappConversation $conversation,
		string $sourceType,
		string $sourceId
	): void {

		$templateSid = $templateConfig['template_sid'];
		$templateName = $templateConfig['template_name'] ?? '';
		$fieldMapping = $templateConfig['field_mapping'] ?? [];
		$bookNowWidgetId = $templateConfig['book_now_widget_id'] ?? null;

		// If there is an active booking linked, delegate to the Booking model
		$booking = null;
		if ($conversation->active_booking_id) {
			$booking = \Alexr\Models\Booking::find($conversation->active_booking_id);
		}

		if ($booking) {
			$booking->sendWhatsappTemplateBySid(
				$templateSid,
				$templateName,
				$fieldMapping,
				null,
				$sourceType,
				$sourceId,
				$bookNowWidgetId,
				['sender_type' => 'bot'] // Bot auto-reply: do NOT set AWAITING_REPLY
			);
			return;
		}

		// No booking context - send directly via WhatsappManager
		$manager = WhatsappManager::forRestaurant($restaurantId);

		if (!$manager->isConfigured()) {
			return;
		}

		$restaurant = Restaurant::find($restaurantId);

		if (!$restaurant) {
			return;
		}

		$variables = self::resolveRestaurantVariables($fieldMapping, $restaurant, $bookNowWidgetId);

		$manager->sendTemplate(
			$message->phone,
			$templateSid,
			$variables,
			null,
			$conversation->customer_id,
			$templateName,
			[],                  // senderInfo
			$conversation->id    // conversationId - reuse existing conversation
		);
	}

	/**
	 * Send a custom text message response.
	 *
	 * @param string $customMessage
	 * @param int $restaurantId
	 * @param WhatsappMessage $message
	 * @param WhatsappConversation $conversation
	 * @param string|null $bookNowWidgetId
	 * @return void
	 */
	protected static function sendCustomMessageResponse(
		string $customMessage,
		int $restaurantId,
		WhatsappMessage $message,
		WhatsappConversation $conversation,
		$bookNowWidgetId = null
	): void {

		if (empty($customMessage)) {
			return;
		}

		$customMessage = self::replaceRestaurantTags($customMessage, $restaurantId, $bookNowWidgetId);

		$manager = WhatsappManager::forRestaurant($restaurantId);

		if (!$manager->isConfigured()) {
			return;
		}

		$manager->sendMessage(
			$message->phone,
			$customMessage,
			$conversation->active_booking_id,
			$conversation->customer_id,
			$conversation->id
		);
	}

	// ---------------------------------------------------------------
	// Variable resolution helpers
	// ---------------------------------------------------------------

	/**
	 * Resolve template variables using only restaurant-level fields.
	 *
	 * @param array $fieldMapping
	 * @param Restaurant $restaurant
	 * @param string|null $bookNowWidgetId
	 * @return array
	 */
	protected static function resolveRestaurantVariables(array $fieldMapping, Restaurant $restaurant, $bookNowWidgetId = null): array
	{
		$variables = [];

		foreach ($fieldMapping as $templateVar => $fieldKey) {
			if (empty($fieldKey)) {
				continue;
			}

			$value = self::resolveRestaurantField($fieldKey, $restaurant, $bookNowWidgetId);

			if ($value !== null && $value !== '') {
				$variables[$fieldKey] = (string) $value;
			}
		}

		return $variables;
	}

	/**
	 * Resolve a single restaurant-level field value.
	 *
	 * @param string $fieldKey
	 * @param Restaurant $restaurant
	 * @param string|null $bookNowWidgetId
	 * @return string
	 */
	protected static function resolveRestaurantField(string $fieldKey, Restaurant $restaurant, $bookNowWidgetId = null): string
	{
		switch ($fieldKey) {
			case 'restaurant':
				return $restaurant->name ?? '';

			case 'restaurant_phone':
				$dialCode = $restaurant->dial_code ?? '';
				$phone = $restaurant->phone ?? '';
				return trim($dialCode . ' ' . $phone);

			case 'book_now':
				return self::getBookNowLink($restaurant, $bookNowWidgetId);

			case 'current_date':
				$timezone = $restaurant->timezone ?? 'UTC';
				return evavel_now_timezone_formatted($timezone, 'Y-m-d');

			case 'site_link':
				return evavel_site_url();

			case 'restaurant_link':
				return $restaurant->link_web ?? '';

			case 'restaurant_facebook':
				return $restaurant->link_facebook ?? '';

			case 'restaurant_instagram':
				return $restaurant->link_instagram ?? '';

			case 'menu_link':
				return $restaurant->link_menu ?? '';

			case 'opening_link':
				return $restaurant->link_opening ?? '';

			default:
				return '';
		}
	}

	/**
	 * Replace {tag} placeholders in a custom message with restaurant values
	 *
	 * @param string $message
	 * @param int $restaurantId
	 * @param string|null $bookNowWidgetId
	 * @return string
	 */
	protected static function replaceRestaurantTags(string $message, int $restaurantId, $bookNowWidgetId = null): string
	{
		$restaurant = Restaurant::find($restaurantId);

		if (!$restaurant) {
			return $message;
		}

		$dialCode = $restaurant->dial_code ?? '';
		$phone = $restaurant->phone ?? '';
		$timezone = $restaurant->timezone ?? 'UTC';

		$replacements = [
			'{restaurant}'           => $restaurant->name ?? '',
			'{restaurant_phone}'     => trim($dialCode . ' ' . $phone),
			'{book_now}'             => self::getBookNowLink($restaurant, $bookNowWidgetId),
			'{current_date}'         => evavel_now_timezone_formatted($timezone, 'Y-m-d'),
			'{site_link}'            => evavel_site_url(),
			'{restaurant_link}'      => $restaurant->link_web ?? '',
			'{restaurant_facebook}'  => $restaurant->link_facebook ?? '',
			'{restaurant_instagram}' => $restaurant->link_instagram ?? '',
			'{menu_link}'            => $restaurant->link_menu ?? '',
			'{opening_link}'         => $restaurant->link_opening ?? '',
		];

		return str_replace(
			array_keys($replacements),
			array_values($replacements),
			$message
		);
	}

	/**
	 * Get the booking link for the restaurant
	 *
	 * @param Restaurant $restaurant
	 * @param string|null $bookNowWidgetId
	 * @return string
	 */
	protected static function getBookNowLink(Restaurant $restaurant, $bookNowWidgetId = null): string
	{
		return evavel_action_book_now($restaurant->id, $bookNowWidgetId);
	}
}

WhatsappKeywordHandler::register();
