<?php

namespace Limb_Chatbot\Includes\Repositories;

use Limb_Chatbot\Includes\Data_Objects\Action_Callback;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Services\Collection;

/**
 * Repository class for managing Action_Callback records.
 *
 * Provides methods for retrieving, creating, updating, and deleting action callbacks.
 *
 * @package Limb_Chatbot\Includes\Repositories
 * @since 1.0.0
 */
class Action_Callback_Repository {

	/**
	 * Retrieves a collection of callbacks based on given parameters.
	 *
	 * Supports filtering and pagination.
	 *
	 * @param int   $action_id The action ID to filter by
	 * @param array $params    Parameters for filtering and pagination
	 *
	 * @return Collection Collection of Action_Callback objects.
	 * @since 1.0.0
	 */
	public function get_items( int $action_id, array $params ): Collection {
		return Action_Callback::where( array_merge(
			[ 'action_id' => $action_id ],
			$params
		) );
	}

	/**
	 * Deletes a callback.
	 *
	 * @param int $id Callback ID.
	 *
	 * @return bool True if deletion was successful, false otherwise.
	 * @since 1.0.0
	 */
	public function delete( int $id ): bool {
		return Action_Callback::delete( [ 'id' => $id ] );
	}

	/**
	 * Batch delete multiple callbacks.
	 *
	 * @param array $ids Array of callback IDs to delete.
	 *
	 * @return bool True if all deletions were successful.
	 * @since 1.0.0
	 */
	public function batch_delete( array $ids ): bool {
		return Action_Callback::delete( [ 'id' => $ids ] );
	}

	/**
	 * Retrieves a single callback by ID.
	 *
	 * @param int $id Callback ID.
	 *
	 * @return Action_Callback|null The Action_Callback object if found, null otherwise.
	 * @since 1.0.0
	 */
	public function get_item( int $id ): ?Action_Callback {
		return Action_Callback::find( $id );
	}

	/**
	 * Updates an existing callback.
	 *
	 * @param int   $id    Callback ID.
	 * @param array $data  Data to update.
	 *
	 * @return Action_Callback|null The updated Action_Callback object or null on failure.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function update( int $id, array $data ): ?Action_Callback {
		$callback = $this->get_item( $id );
		if ( ! $callback ) {
			throw new Exception( Error_Codes::NOT_FOUND, __( 'Callback not found.', 'limb-chatbot' ) );
		}

		return Action_Callback::update( [ 'id' => $id ], $data );
	}

	/**
	 * Creates a new callback.
	 *
	 * @param array $data Callback data.
	 *
	 * @return Action_Callback|null The created Action_Callback object or null on failure.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function create( array $data ): ?Action_Callback {
		return Action_Callback::create( $data );
	}

	/**
	 * Batch create or update callbacks.
	 *
	 * @param array $items Array of callback data arrays.
	 *
	 * @return Collection Collection of created or updated Action_Callback objects.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function batch( array $items ): Collection {
		$collection = new Collection();

		foreach ( $items as $item ) {
			try {
				if ( ! empty( $item['id'] ) ) {
					$callback = $this->update( $item['id'], $item );
				} else {
					$callback = $this->create( $item );
				}

				if ( $callback ) {
					$collection->push_item( $callback );
				}
			} catch ( Exception $e ) {
				$errors = $collection->get_property( 'errors' ) ?? [];
				$collection->push_property( 'errors', array_merge( $errors, [ 'item' => $item, 'error' => $e->getMessage() ] ) );
				continue;
			}
		}

		return $collection;
	}
}

