<?php

namespace Limb_Chatbot\Includes\Services;

use Limb_Chatbot\Includes\Data_Objects\Chat;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Data_Objects\Message;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Factories\Live_Agent_Service_Factory;
use Limb_Chatbot\Includes\Interfaces\Live_Agent_Interface;
use Limb_Chatbot\Includes\Utilities\Chatbot_Utility;
use Limb_Chatbot\Includes\Utilities\Copilot_Utility;

/**
 * Live Agent Service
 *
 * Handles live agent connection logic based on chatbot configuration.
 * Routes to appropriate integration (Slack, Telegram, etc.).
 *
 * @package Limb_Chatbot\Includes\Services
 * @since 1.0.0
 */
class Live_Agent_Service {

	/**
	 * Chat meta key for live agent status.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	const META_LIVE_AGENT_ACTIVE = 'live_agent_active';

	/**
	 * Chat meta key for live agent config ID.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	const META_LIVE_AGENT_CONFIG_ID = 'live_agent_config_id';

	/**
	 * Chat meta key for live agent channel ID (Slack/Telegram specific).
	 *
	 * @var string
	 * @since 1.0.0
	 */
	const META_LIVE_AGENT_CHANNEL_ID = 'live_agent_channel_id';

	/**
	 * Chat meta key for live agent reason.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	const META_LIVE_AGENT_REASON = 'live_agent_reason';

	/**
	 * Connect a chat to a live agent.
	 *
	 * @param  Chat  $chat  Chat instance.
	 * @param  Chatbot_Utility  $utility  Chatbot utility.
	 * @param  array  $args  Connecting configuration
	 *
	 * @return Message
	 * @since 1.0.0
	 */
	public function connect_live_agent( Chat $chat, Chatbot_Utility $utility, array $args = [] ): Message {
		$is_success = false;
		$error_message = null;
		$reason = $args['reason'] ?? '';
		try {
			// Validate live agent feature is enabled
			if ( ! $utility->live_agent ) {
				throw new Exception(
					Error_Codes::VALIDATION_INVALID_VALUE,
					__( 'Live agent feature is not enabled for this chatbot.', 'limb-chatbot' )
				);
			}

			// Get live agent config
			$config_id = $utility->live_agent_config_id;
			$config    = ! empty( $config_id ) ? Config::find( $config_id ) : null;

			if ( ! $config ) {
				throw new Exception(
					Error_Codes::NOT_FOUND,
					__( 'Live agent configuration not found.', 'limb-chatbot' )
				);
			}

			// Route to appropriate integration
			$service = ( new Live_Agent_Service_Factory() )->make( $config );
			if ( $service instanceof Live_Agent_Interface ) {
				$service->connect( $chat, $utility, $config, $args );
			}

			// Update chat meta
			$chat->update_meta( self::META_LIVE_AGENT_ACTIVE, true );
			$chat->update_meta( self::META_LIVE_AGENT_CONFIG_ID, $config_id );
			$chat->update_meta( self::META_LIVE_AGENT_REASON, $reason );

			$is_success = true;

		} catch ( Exception $e ) {
			$error_message = $e->getMessage();
			Helper::log( $e, __METHOD__ . ' - Failed to connect live agent' );
		}

		// Generate AI-powered response message
		return $this->generate_live_agent_message( $chat, $utility, $is_success, $reason, $error_message, $config ?? null );
	}

	/**
	 * Check if live agent is currently active for a chat.
	 *
	 * @param  Chat  $chat  Chat instance.
	 *
	 * @return bool True if live agent is active.
	 * @since 1.0.0
	 */
	public function is_live_agent_active( Chat $chat ): bool {
		return (bool) $chat->get_meta( self::META_LIVE_AGENT_ACTIVE );
	}

	/**
	 * Disconnect live agent from a chat.
	 *
	 * Ends the live agent session, logs disconnection to the integration,
	 * and generates a friendly message for the user.
	 *
	 * @param  Chat  $chat  Chat instance.
	 *
	 * @return Message Disconnection message for the user.
	 * @since 1.0.0
	 */
	public function disconnect_live_agent( Chat $chat ): Message {
		try {
			// Get chatbot and utility
			$chatbot = $chat->get_chatbot();
			if ( ! $chatbot ) {
				throw new Exception( Error_Codes::NOT_FOUND, __( 'Chatbot not found.', 'limb-chatbot' ) );
			}

			$utility = new Chatbot_Utility( $chatbot );

			// Get live agent config
			$config_id = $chat->get_meta( self::META_LIVE_AGENT_CONFIG_ID );
			$config    = ! empty( $config_id ) ? Config::find( $config_id ) : null;

			if ( ! $config ) {
				throw new Exception( Error_Codes::NOT_FOUND, __( 'Live agent configuration not found.', 'limb-chatbot' ) );
			}

			// Route to appropriate integration for disconnect logging
			$service = ( new Live_Agent_Service_Factory() )->make( $config );
			if ( $service instanceof Live_Agent_Interface ) {
				$service->disconnect( $chat, $utility, $config );
			}

			// Update chat meta
			$chat->update_meta( self::META_LIVE_AGENT_ACTIVE, false );

			// Generate AI-powered disconnection message
			return $this->generate_disconnection_message( $chat, $utility );

		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ . ' - Failed to disconnect live agent' );

			// Still mark as disconnected
			$chat->update_meta( self::META_LIVE_AGENT_ACTIVE, false );

			// Return fallback message
			return $this->get_fallback_disconnection_message( $chat );
		}
	}

	/**
	 * Generate a context-aware message for live agent connection.
	 *
	 * Uses AI (Copilot utility) to generate a user-friendly message informing
	 * the user about the live agent connection status.
	 *
	 * @param  Chat  $chat  Chat instance.
	 * @param  Chatbot_Utility  $utility  Chatbot utility.
	 * @param  bool  $is_success  Whether connection was successful.
	 * @param  string  $reason  Reason for connection request.
	 * @param  string|null  $error_message  Error message if connection failed.
	 * @param  Config|null  $config  Live agent configuration.
	 *
	 * @return Message Generated message for the user.
	 * @since 1.0.0
	 */
	private function generate_live_agent_message( Chat $chat, Chatbot_Utility $utility, bool $is_success, string $reason = '', ?string $error_message = null, ?Config $config = null ): Message {
		try {
			// Try to use Copilot utility for AI-powered message generation
			$copilot = new Copilot_Utility( $utility->get_ai_model(), $utility->get_config() );
			// Generate AI response using the new Copilot method
			$ai_message = $copilot->generate_live_agent_connection_message( $is_success, $reason, $error_message, $utility->get_stream() );
			// Extract text from AI response
			$content = '';
			if ( $ai_message instanceof Message ) {
				$content = $ai_message->extract_text();
			}
			// If AI generation fails, use fallback
			if ( empty( $content ) ) {
				$content = $this->get_fallback_message( $is_success );
			}
			$message = Message::make( [
				'chat_uuid' => $chat->get_uuid(),
				'role'      => Message::ROLE_ASSISTANT,
				'content'   => [
					[
						'type' => 'text',
						'text' => [ 'value' => $content ]
					],
				]
			] );
			if ( $is_success ) {
				$message->content[] = [
					'type'             => Message::CONTENT_TYPE_SLACK_CONNECTION,
					'slack_connection' => [ 'value' => 'success' ]
				];
			}
			$message->is_live_agent_connection = true;

			return $message->attach_agents( $utility->agent_ids );
		} catch ( \Exception $e ) {
			// If AI generation fails, use fallback message
			Helper::log( $e, __METHOD__ . ' - Failed to generate AI message' );
			$message = Message::make( [
				'chat_uuid' => $chat->get_uuid(),
				'role'      => Message::ROLE_ASSISTANT,
				'content'   => [
					[
						'type' => 'text',
						'text' => [ 'value' => $this->get_fallback_message( $is_success ) ]
					],
					[
						'type' => Message::CONTENT_TYPE_SLACK_CONNECTION,
						'slack_connection' => [ 'value' => 'success' ]
					]
				]
			] );
			$message->is_live_agent_connection = true;
			return $message;
		}
	}

	/**
	 * Get fallback message when AI generation fails.
	 *
	 * @param  bool  $is_success  Whether connection was successful.
	 *
	 * @return string Fallback message.
	 * @since 1.0.0
	 */
	private function get_fallback_message( bool $is_success ): string {
		if ( $is_success ) {
			$message = __( 'Great! A live agent has been notified and will be with you shortly. 👋', 'limb-chatbot' );
		} else {
			$message = __( 'I apologize, but I\'m having trouble connecting you to a live agent right now. Please try again in a moment. 😔', 'limb-chatbot' );
		}

		return $message;
	}

	public function send_message( Chat $chat, Message $message, Config $config ) {
		$service = ( new Live_Agent_Service_Factory() )->make( $config );
		if ( $service instanceof Live_Agent_Interface ) {
			$service->send( $chat, $message, $config );
		}
	}

	/**
	 * Generate a disconnection message using AI.
	 *
	 * @param  Chat  $chat  Chat instance.
	 * @param  Chatbot_Utility  $utility  Chatbot utility.
	 *
	 * @return Message Generated disconnection message.
	 * @since 1.0.0
	 */
	private function generate_disconnection_message( Chat $chat, Chatbot_Utility $utility ): Message {
		try {
			// Use Copilot utility for AI-powered message generation
			$copilot = new Copilot_Utility(
				$utility->get_ai_model(),
				$utility->get_config()
			);

			$ai_message = $copilot->generate_live_agent_disconnection_message( false );

			// Extract text from AI response
			$content = '';
			if ( $ai_message instanceof Message ) {
				$content = $ai_message->extract_text();
			}

			// If AI generation fails, use fallback
			if ( empty( $content ) ) {
				$content = $this->get_fallback_disconnection_text();
			}
			$message =  Message::make( [
				'chat_uuid' => $chat->get_uuid(),
				'role'      => Message::ROLE_ASSISTANT,
				'content'   => [
					[
						'type' => 'text',
						'text' => [ 'value' => $content ]
					]
				]
			] );

			return $message->save();
		} catch ( \Exception $e ) {
			Helper::log( $e, __METHOD__ . ' - Failed to generate AI disconnect message' );
			return $this->get_fallback_disconnection_message( $chat );
		}
	}

	/**
	 * Get fallback disconnection message when AI generation fails.
	 *
	 * @param  Chat  $chat  Chat instance.
	 *
	 * @return Message Fallback disconnection message.
	 * @since 1.0.0
	 */
	private function get_fallback_disconnection_message( Chat $chat ): Message {
		return Message::make( [
			'chat_uuid' => $chat->get_uuid(),
			'role'      => Message::ROLE_ASSISTANT,
			'content'   => [
				[
					'type' => 'text',
					'text' => [ 'value' => $this->get_fallback_disconnection_text() ]
				]
			]
		] );
	}

	/**
	 * Get fallback disconnection text.
	 *
	 * @return string Fallback text.
	 * @since 1.0.0
	 */
	private function get_fallback_disconnection_text(): string {
		return __( 'Thank you for chatting with our live agent! 👋 Your session has ended, but I\'m still here if you need any further assistance. How can I help you today?', 'limb-chatbot' );
	}

}

