<?php

namespace Limb_Chatbot\Includes\Services;

use Exception;
use Limb_Chatbot\Includes\Data_Objects\Chat;
use Limb_Chatbot\Includes\Data_Objects\Chatbot;
use Limb_Chatbot\Includes\Data_Objects\Message;
use Limb_Chatbot\Includes\Repositories\Chat_Meta_Repository;
use Limb_Chatbot\Includes\Repositories\Chat_Repository;
use Limb_Chatbot\Includes\Repositories\Message_Repository;
use Limb_Chatbot\Includes\Utilities\Chatbot_Utility;
use Limb_Chatbot\Includes\Services\Preview_State;


/**
 * Service class to manage Chat operations like creation, running, clearing, and deleting chats.
 *
 * @since 1.0.0
 */
class Chat_Service {

	/**
	 * The chatbot instance associated with this service.
	 *
	 * @var Chatbot
	 * @since 1.0.0
	 */
	public Chatbot $chatbot;

	/**
	 * Repository for managing chat data persistence.
	 *
	 * @var Chat_Repository|null
	 * @since 1.0.0
	 */
	public ?Chat_Repository $chat_repository;

	/**
	 * Repository for managing chat meta data.
	 *
	 * @var Chat_Meta_Repository|null
	 * @since 1.0.0
	 */
	public ?Chat_Meta_Repository $chat_meta_repository;

	/**
	 * Chat_Service constructor.
	 *
	 * @param  Chatbot  $chatbot  Chatbot instance to associate.
	 * @param  Chat_Repository|null  $chat_repository  Optional chat repository instance.
	 * @param  Chat_Meta_Repository|null  $chat_meta_repository  Optional chat meta repository instance.
	 *
	 * @since 1.0.0
	 */
	public function __construct( Chatbot $chatbot, ?Chat_Repository $chat_repository = null, ?Chat_Meta_Repository $chat_meta_repository = null ) {
		$this->chatbot              = $chatbot;
		$this->chat_repository      = $chat_repository;
		$this->chat_meta_repository = $chat_meta_repository;
	}

	/**
	 * Create a new chat.
	 *
	 * @param  array  $data  Chat data for creation.
	 *
	 * @return Chat|null The created chat object or null on failure.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function create( array $data ): ?Chat {
		$chatbot_user = User_Manager::instance()->get_current_user();
		$chat         = $this->chat_repository->create( $data, $this->chatbot );
		if ( $chat->add_participant( $chatbot_user ) ) {
			$chatbot_user->increment_new_chat_usage();
		}

		return $chat;
	}

	/**
	 * Run chat interaction to generate a reply.
	 *
	 * @param  Chat  $chat  Chat instance to run.
	 * @param  bool  $preview  Whether to run in preview mode (admin only).
	 *
	 * @return Message Generated reply data.
	 * @throws Exception
	 * @since 1.0.0
	 *
	 */
	public function run( Chat $chat, bool $preview = false, $reload = false ) {
		if ( $preview && User_Manager::instance()->current_user->wp_can( 'manage_options' ) ) {
			$this->chatbot->set_preview( true );
			$preview_state = Preview_State::load();
			$this->chatbot->set_preview_state_parameters( $preview_state->get_parameters() );
		}
		if ( $reload ) {
			$last_message = $chat->get_last_message();
			if ( $last_message->get_role() === Message::ROLE_ASSISTANT ) {
				Message::delete( [ 'id' => $last_message->get_id() ] );
			}
		}
		$utility = new Chatbot_Utility( $this->chatbot );

		return ( new Chatbot_Service( $utility ) )->generate_reply( $chat );
	}

	/**
	 * Clear all messages from a chat.
	 *
	 * @since 1.0.0
	 *
	 * @param Chat $chat Chat instance whose messages to clear.
	 * @return bool True on success, false otherwise.
	 */
	public function clear( Chat $chat ): bool {
		return ( new Message_Service( $chat, new Message_Repository() ) )->delete( [ 'chat_uuid' => $chat->get_uuid() ] );
	}

	/**
	 * Delete a chat and associated data including meta and messages.
	 *
	 * @since 1.0.0
	 *
	 * @param Chat $chat Chat instance to delete.
	 * @return bool True on successful deletion, false otherwise.
	 */
	public function delete( Chat $chat ): bool {
		$this->chat_meta_repository->delete( [ 'chat_id' => $chat->get_id() ] );
		( new Message_Service( $chat, new Message_Repository() ) )->delete( [ 'chat_uuid' => $chat->get_uuid() ] );

		return Chat::delete( [ 'id' => $chat->get_id() ] );
	}
}