<?php

namespace Limb_Chatbot\Includes\Repositories;

use Exception;
use Limb_Chatbot\Includes\Data_Objects\Chat;
use Limb_Chatbot\Includes\Data_Objects\Chat_Meta;
use Limb_Chatbot\Includes\Data_Objects\Meta_Data_Object;

/**
 * Repository for managing chat meta data.
 *
 * @since 1.0.0
 */
class Chat_Meta_Repository {

	/**
	 * Create a new meta entry for a chat.
	 *
	 * @param  Chat  $chat  The chat object.
	 * @param  string  $meta_key  The meta key.
	 * @param  mixed  $meta_value  The meta value.
	 *
	 * @return Meta_Data_Object The created meta data object.
	 * @throws Exception
	 * @since 1.0.0
	 *
	 */
	public function create( Chat $chat, string $meta_key, $meta_value ): Meta_Data_Object {
		return Chat_Meta::create( [
			'chat_id'    => $chat->get_id(),
			'meta_key'   => $meta_key,
			'meta_value' => $meta_value
		] );
	}

	/**
	 * Get meta items for a given chat filtered optionally by key and/or value.
	 *
	 * @since 1.0.0
	 *
	 * @param Chat $chat The chat object.
	 * @param string|null $meta_key Optional meta key to filter by.
	 * @param mixed|null $meta_value Optional meta value to filter by.
	 * @return array List of meta data objects matching the criteria.
	 */
	public function get_items( Chat $chat, ?string $meta_key = null, $meta_value = null ): array {
		$params            = [];
		$params['chat_id'] = $chat->get_id();
		if ( ! empty( $meta_key ) ) {
			$params['meta_key'] = $meta_key;
		}
		if ( ! empty( $meta_value ) ) {
			$params['meta_value'] = $meta_value;
		}

		return Chat_Meta::where( $params )->get();
	}

	/**
	 * Get meta items by key and value.
	 *
	 * @since 1.0.0
	 *
	 * @param string $meta_key Meta key.
	 * @param string $meta_value Meta value.
	 * @return array|null List of meta data objects or null if none found.
	 */
	public function get_items_by_key_value( string $meta_key, string $meta_value ): ?array {
		return Chat_Meta::where( [ 'meta_key' => $meta_key, 'meta_value' => $meta_value ] )->get();
	}

	/**
	 * Checks if any meta entry exists for a given chat with optional filtering.
	 *
	 * @since 1.0.0
	 *
	 * @param Chat $chat The chat object.
	 * @param string|null $meta_key Optional meta key filter.
	 * @param mixed|null $meta_value Optional meta value filter.
	 * @return bool True if exists, false otherwise.
	 */
	public function exists( Chat $chat, ?string $meta_key = null, $meta_value = null ): bool {
		$params            = [];
		$params['chat_id'] = $chat->get_id();
		if ( ! empty( $meta_key ) ) {
			$params['meta_key'] = $meta_key;
		}
		if ( ! empty( $meta_value ) ) {
			$params['meta_value'] = $meta_value;
		}

		return (bool) Chat_Meta::count( $params );
	}

	/**
	 * Delete meta entries based on given conditions.
	 *
	 * @since 1.0.0
	 *
	 * @param array $where Conditions to match for deletion.
	 * @return bool True on success, false otherwise.
	 */
	public function delete( $where ) {
		return Chat_Meta::delete( $where );
	}

	/**
	 * Updates multiple metadata entries for a given chat.
	 *
	 * @param  array  $data  List of meta data entries with 'meta_key' and 'meta_value'.
	 * @param  string  $chat_uuid  The ID of the chat to which the meta belongs.
	 *
	 * @return array Updated Chat_Meta objects.
	 * @throws \Exception
	 * @since 1.0.0
	 */
	public function batch_update( array $data, string $chat_uuid ): array {
		$chat = Chat::find_by_uuid( $chat_uuid );
		if ( $chat instanceof Chat ) {
			$chat_id = $chat->get_id();
			foreach ( $data as $item ) {
				$where = [ 'chat_id' => $chat_id, 'meta_key' => $item['meta_key'] ];
				Chat_Meta::update( $where, [ 'meta_value' => $item['meta_value'] ] );
				$metas[] = Chat_Meta::where( $where )->first();
			}
		}

		return $metas ?? [];
	}
}