<?php

namespace Limb_Chatbot\Includes\Integrations\Telegram\Services;

use Limb_Chatbot\Includes\Data_Objects\Chat;
use Limb_Chatbot\Includes\Data_Objects\Chat_Meta;
use Limb_Chatbot\Includes\Data_Objects\Chatbot_User_Meta;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Data_Objects\Message;
use Limb_Chatbot\Includes\Data_Objects\Message_Meta;
use Limb_Chatbot\Includes\Services\Helper;
use Limb_Chatbot\Includes\Services\Live_Agent_Service;

/**
 * Telegram Event Handler Service
 *
 * Processes Telegram webhook updates and synchronizes messages
 * from live agents to the chat system.
 *
 * @package Limb_Chatbot\Includes\Integrations\Telegram\Services
 * @since 1.0.11
 */
class Telegram_Event_Handler_Service {

	/**
	 * Handle incoming Telegram update.
	 *
	 * @param array  $update Update data from Telegram.
	 * @param Config $config Telegram configuration.
	 *
	 * @return bool True if handled successfully.
	 * @since 1.0.11
	 */
	public function handle_update( array $update, Config $config ): bool {
		// Handle message updates
		if ( isset( $update['message'] ) ) {
			return $this->handle_message( $update['message'], $config );
		}

		// Handle my_chat_member updates (bot added/removed from groups)
		if ( isset( $update['my_chat_member'] ) ) {
			return $this->handle_chat_member_update( $update['my_chat_member'], $config );
		}

		return true;
	}

	/**
	 * Handle message from Telegram.
	 *
	 * Saves agent messages to the database for display in the chat.
	 * Also detects special closure commands and stores group info.
	 *
	 * @param array  $message Message data from Telegram.
	 * @param Config $config  Telegram configuration.
	 *
	 * @return bool True if handled successfully.
	 * @since 1.0.11
	 */
	private function handle_message( array $message, Config $config ): bool {
		$chat_data = $message['chat'] ?? [];
		$chat_type = $chat_data['type'] ?? '';
		$from      = $message['from'] ?? [];

		// Store user info from message if it's a private chat
		if ( ! empty( $chat_data ) && $chat_type === 'private' ) {
			$this->store_user_from_message( $chat_data, $from, $config );
		}

		// Ignore messages from bots
		if ( isset( $message['from']['is_bot'] ) && $message['from']['is_bot'] ) {
			return true;
		}

		$chat_id_tg = $chat_data['id'] ?? '';
		$text       = $message['text'] ?? '';
		$msg_id     = $message['message_id'] ?? '';
		$user_id    = $from['id'] ?? ''; // Agent ID

		if ( empty( $chat_id_tg ) || empty( $text ) || empty( $msg_id ) ) {
			return false;
		}

		$chat = null;

		// Find chat by private chat ID (Agent direct message)
		if ( $chat_type === 'private' ) {
			$chat = $this->find_chat_by_private_chat_id( $chat_id_tg );
		}

		if ( ! $chat ) {
			return true; // No relevant active chat found
		}

		// Check for special closure commands (alternative to button)
		if ( $this->is_closure_command( $text ) ) {
			$this->handle_closure_command( $chat, $user_id, $from );
			return true;
		}

		// Check if message already exists
		if ( $this->message_exists( $chat, $msg_id ) ) {
			return true; // Already processed
		}

		// Create and save agent message
		$this->save_agent_message( $chat, $text, $msg_id, $user_id, $from, $config );

		return true;
	}


	/**
	 * Store private chat user info from incoming message.
	 *
	 * Updates the saved users list in config params when receiving messages from private chats.
	 * User data is compatible with Telegram_Agent_Service for WordPress user creation.
	 *
	 * @param array  $chat_data Chat data from message.
	 * @param array  $from      Sender data from message.
	 * @param Config $config    Telegram configuration.
	 *
	 * @return void
	 * @since 1.0.11
	 */
	private function store_user_from_message( array $chat_data, array $from, Config $config ): void {
		$user_id = $from['id'] ?? $chat_data['id'] ?? '';
		if ( empty( $user_id ) ) {
			return;
		}

		// Skip bots
		if ( ! empty( $from['is_bot'] ) ) {
			return;
		}

		$params = $config->get_params();
		$users  = $params['users'] ?? [];

		// Check if user already exists
		foreach ( $users as $user ) {
			if ( ( $user['id'] ?? '' ) == $user_id ) {
				return; // Already stored
			}
		}

		// Add new user (compatible with Telegram_Agent_Service)
		$users[] = [
			'id'            => $user_id,
			'chat_id'       => $chat_data['id'] ?? $user_id,
			'first_name'    => $from['first_name'] ?? $chat_data['first_name'] ?? '',
			'last_name'     => $from['last_name'] ?? $chat_data['last_name'] ?? '',
			'username'      => $from['username'] ?? $chat_data['username'] ?? '',
			'language_code' => $from['language_code'] ?? '',
			'type'          => 'private',
		];

		$params['users'] = $users;
		$config->params  = $params;
		$config->encrypt_params();
		$config->save();
	}

	/**
	 * Handle chat member update (users starting/blocking bot).
	 *
	 * Updates the saved users list in config params.
	 *
	 * @param array  $chat_member Chat member update data.
	 * @param Config $config      Telegram configuration.
	 *
	 * @return bool True if handled successfully.
	 * @since 1.0.11
	 */
	private function handle_chat_member_update( array $chat_member, Config $config ): bool {
		$chat       = $chat_member['chat'] ?? [];
		$from       = $chat_member['from'] ?? [];
		$new_status = $chat_member['new_chat_member']['status'] ?? '';
		$chat_type  = $chat['type'] ?? '';

		// Handle private chat updates (user started/blocked the bot)
		if ( $chat_type === 'private' ) {
			return $this->handle_private_chat_member_update( $chat, $from, $new_status, $config );
		}


		return true;
	}

	/**
	 * Handle private chat member update (user started/blocked the bot).
	 *
	 * @param array  $chat       Chat data.
	 * @param array  $from       User data.
	 * @param string $new_status New member status.
	 * @param Config $config     Telegram configuration.
	 *
	 * @return bool True if handled successfully.
	 * @since 1.0.11
	 */
	private function handle_private_chat_member_update( array $chat, array $from, string $new_status, Config $config ): bool {
		$params = $config->get_params();
		$users  = $params['users'] ?? [];

		$user_id = $from['id'] ?? $chat['id'] ?? '';

		if ( empty( $user_id ) ) {
			return true;
		}

		// Skip bots
		if ( ! empty( $from['is_bot'] ) ) {
			return true;
		}

		// User started the bot (or unblocked)
		if ( in_array( $new_status, [ 'member' ], true ) ) {
			// Check if user already exists
			$found = false;
			foreach ( $users as $user ) {
				if ( ( $user['id'] ?? '' ) == $user_id ) {
					$found = true;
					break;
				}
			}

			if ( ! $found ) {
				$users[] = [
					'id'            => $user_id,
					'chat_id'       => $chat['id'] ?? $user_id,
					'first_name'    => $from['first_name'] ?? $chat['first_name'] ?? '',
					'last_name'     => $from['last_name'] ?? $chat['last_name'] ?? '',
					'username'      => $from['username'] ?? $chat['username'] ?? '',
					'language_code' => $from['language_code'] ?? '',
					'type'          => 'private',
				];

				$params['users'] = $users;
				$config->params  = $params;
				$config->encrypt_params();
				$config->save();
			}
		}

		// User blocked the bot
		if ( in_array( $new_status, [ 'kicked' ], true ) ) {
			$users = array_filter( $users, function ( $user ) use ( $user_id ) {
				return ( $user['id'] ?? '' ) != $user_id;
			} );

			$params['users'] = array_values( $users );
			$config->params  = $params;
			$config->encrypt_params();
			$config->save();
		}

		return true;
	}

	/**
	 * Find active chat by private Telegram chat ID (Agent ID).
	 *
	 * Scans for chats where the live agent is connected via this Telegram user ID
	 * and the live agent session is currently active.
	 *
	 * @param string|int $telegram_chat_id Telegram Chat/User ID.
	 *
	 * @return Chat|null Active chat or null.
	 * @since 1.0.11
	 */
	private function find_chat_by_private_chat_id( $telegram_chat_id ): ?Chat {
		// Find chat metas where this Telegram user is assigned
		$chat_metas = Chat_Meta::where( [
			'meta_key'   => Telegram_Live_Agent_Service::META_TELEGRAM_CHAT_ID,
			'meta_value' => $telegram_chat_id,
		] );

		if ( $chat_metas->is_empty() ) {
			return null;
		}

		$metas = $chat_metas->get();

		// Sort by ID descending to check most recent assignments first
		if ( is_array( $metas ) ) {
			usort( $metas, function( $a, $b ) {
				return $b->get_id() - $a->get_id();
			} );
		}

		$live_agent_service = new Live_Agent_Service();

		// Iterate through chats to find the active one
		foreach ( $metas as $meta ) {
			$chat = Chat::find( $meta->get_chat_id() );

			// Must be valid chat and currently active live agent session
			if ( $chat && $live_agent_service->is_live_agent_active( $chat ) ) {
				return $chat;
			}
		}

		return null;
	}

	/**
	 * Check if message already exists.
	 *
	 * @param Chat       $chat   Chat object.
	 * @param string|int $msg_id Telegram message ID.
	 *
	 * @return bool True if message exists.
	 * @since 1.0.11
	 */
	private function message_exists( Chat $chat, $msg_id ): bool {
		$existing = Message_Meta::where( [
			'meta_key'   => 'telegram_msg_id',
			'meta_value' => $msg_id
		] );

		if ( ! $existing->is_empty() ) {
			foreach ( $existing->get() as $item ) {
				$message = $item->message();
				if ( $message instanceof Message && $message->get_chat_uuid() === $chat->get_uuid() ) {
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * Save agent message to database.
	 *
	 * @param Chat       $chat    Chat object.
	 * @param string     $text    Message text.
	 * @param string|int $msg_id  Telegram message ID.
	 * @param string|int $user_id Telegram user ID.
	 * @param array      $from    User info from Telegram.
	 * @param Config     $config  Telegram configuration.
	 *
	 * @return Message|null Saved message or null on failure.
	 * @since 1.0.11
	 */
	private function save_agent_message( Chat $chat, string $text, $msg_id, $user_id, array $from, Config $config ): ?Message {
		try {
			$message = Message::make( [
				'chat_uuid' => $chat->get_uuid(),
				'role'      => Message::ROLE_ASSISTANT,
				'content'   => [
					[
						'type' => 'text',
						'text' => [ 'value' => $text ]
					]
				]
			] );

			$message->save();

			// Store Telegram metadata for ordering and deduplication
			$message->update_meta( 'telegram_msg_id', $msg_id );
			$message->update_meta( 'telegram_user_id', $user_id );
			$message->update_meta( 'source', 'telegram_agent' );

			// Store agent name from Telegram user info
			$agent_name = trim( ( $from['first_name'] ?? '' ) . ' ' . ( $from['last_name'] ?? '' ) );
			if ( $agent_name ) {
				$message->update_meta( 'agent_name', $agent_name );
				$message->update_meta( 'telegram_agent_name', $agent_name );
			}
			if ( ! empty( $from['username'] ) ) {
				$message->update_meta( 'telegram_agent_username', $from['username'] );
			}

			// Get or create agent and link message to Chatbot_User (similar to Slack integration)
			$agent_service = new Telegram_Agent_Service();
			$chatbot_user  = $agent_service->get_or_create_agent_from_telegram_user( $from, $config );
			if ( $chatbot_user ) {
				$message->update_meta( 'agent_id', $chatbot_user->get_id() );

				// Get cached avatar from WordPress user
				$wp_user_id = $chatbot_user->get_wp_user_id();
				if ( $wp_user_id ) {
					$avatar_url = get_user_meta( $wp_user_id, 'telegram_avatar_url', true );
					if ( $avatar_url ) {
						$message->update_meta( 'telegram_agent_avatar', $avatar_url );
					}
				}
			}

			return $message;
		} catch ( \Exception $e ) {
			Helper::log( $e, __METHOD__ . ' - Failed to save agent message' );
			return null;
		}
	}

	/**
	 * Check if message is a closure command.
	 *
	 * Detects special commands that agents can type to close sessions:
	 * - #close
	 * - #end
	 * - #disconnect
	 * - #done
	 *
	 * @param string $text Message text.
	 *
	 * @return bool True if message is a closure command.
	 * @since 1.0.11
	 */
	private function is_closure_command( string $text ): bool {
		$text = trim( strtolower( $text ) );
		$closure_commands = [ '#close', '#end', '#disconnect', '#done' ];

		return in_array( $text, $closure_commands, true );
	}

	/**
	 * Handle closure command from agent.
	 *
	 * @param Chat       $chat    Chat object.
	 * @param string|int $user_id Telegram user ID who sent command.
	 * @param array      $from    User info from Telegram.
	 *
	 * @return void
	 * @since 1.0.11
	 */
	private function handle_closure_command( Chat $chat, $user_id, array $from ): void {
		try {
			$live_agent_service = new Live_Agent_Service();

			// Check if session is active
			if ( ! $live_agent_service->is_live_agent_active( $chat ) ) {
				return; // Already closed
			}

			// Store who closed the session
			$chat->update_meta( 'live_agent_closed_by_telegram_id', $user_id );
			$chat->update_meta( 'live_agent_closed_at', current_time( 'mysql' ) );
			$chat->update_meta( 'live_agent_closed_via', 'webhook' );

			// Store agent name
			$agent_name = trim( ( $from['first_name'] ?? '' ) . ' ' . ( $from['last_name'] ?? '' ) );
			if ( $agent_name ) {
				$chat->update_meta( 'live_agent_closed_by_name', $agent_name );
			}

			// Disconnect and send message to user
			$message = $live_agent_service->disconnect_live_agent( $chat );
			$message->set_content(
				array_merge( $message->get_content(), array(
					array( 'type' => Message::CONTENT_TYPE_LIVE_AGENT_DISCONNECTION )
				) )
			);
			$message->update_meta( 'source', 'telegram_agent' );
			$message->update_meta( 'telegram_user_id', $user_id );
		} catch ( \Exception $e ) {
			Helper::log( $e, __METHOD__ . ' - Failed to handle closure command' );
		}
	}
}

