<?php

namespace Limb_Chatbot\Includes\Repositories;

use Limb_Chatbot\Includes\Data_Objects\Action;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Services\Collection;
use Limb_Chatbot\Includes\Services\Helper;
use Limb_Chatbot\Includes\Data_Objects\Chatbot;

/**
 * Repository class for managing Action records.
 *
 * Provides methods for retrieving, creating, updating, and deleting actions.
 *
 * @package Limb_Chatbot\Includes\Repositories
 * @since 1.0.0
 */
class Action_Repository {

	/**
	 * Retrieves a collection of actions based on given parameters.
	 *
	 * Supports search filtering and pagination.
	 *
	 * @param  array  $params  {
	 *     Optional. Parameters for filtering and pagination.
	 *
	 * @type string $search Search keyword to match against action name.
	 * @type string[] $search_fields Fields to apply the search against.
	 * @type int $per_page Number of results per page. Default 10.
	 * @type int $page Current page number. Default 1.
	 * @type string $orderby Field to order by. Default 'created_at'.
	 * @type string $order Sort order direction. Accepts 'asc' or 'desc'. Default 'desc'.
	 * }
	 *
	 * @return Collection Collection of Action objects.
	 * @since 1.0.0
	 */
	public function get_items( array $params = [] ): Collection {
		// Handle search
		if ( ! empty( $params['search'] ) && ! empty( $params['search_fields'] ) ) {
			foreach ( $params['search_fields'] as $field ) {
				$params["{$field}LIKE"] = "%{$params['search']}%";
			}
		}

		// Handle ordering
		$order_by = $params['orderby'] ?? 'created_at';
		$order    = strtoupper( $params['order'] ?? 'DESC' );

		// Handle pagination

		$offset  = $params['page'] ?? 1;
		$limit = $params['per_page'] ?? 10;
		if ( array_key_exists( 'chatbot_uuid', $params ) && empty( $params['chatbot_uuid'] ) ) {
			$params['chatbot_uuid'] = null;
		}

		return Action::where( $params, $limit, $offset, $order_by, $order);
	}

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

	/**
	 * Deletes an action.
	 *
	 * @param  int  $id  Action ID.
	 *
	 * @return bool True if deletion was successful, false otherwise.
	 * @since 1.0.0
	 */
	public function delete( int $id ): bool {
		$action  = Action::find( $id );
		$chatbot = $action->get_chatbot();
		if ( $chatbot instanceof Chatbot ) {
			$action_ids = $chatbot->get_parameter( 'action_ids' );
			if ( ! empty( $action_ids ) && in_array( $id, $action_ids ) ) {
				foreach ( $action_ids as $key => $value ) {
					if ( $value == $id ) {
						unset( $action_ids[ $key ] );
					}
				}
				$chatbot->update_parameter( 'action_ids', $action_ids );
			}
		}

		return Action::delete( [ 'id' => $id ] );
	}

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

		foreach ( $items as $item ) {
			try {
				if ( ! empty( $item['id'] ) ) {
					// Update existing action
					$action = $this->update( $item['id'], $item );
				} else {
					// Create new action
					$action = $this->create( $item );
				}

				if ( $action ) {
					$collection->push_item( $action );
				}
			} catch ( Exception $e ) {
				Helper::log( $e, __METHOD__ );
				$errors = $collection->get_property( 'errors' );
				$collection->push_property( 'errors',
					array_merge( $errors, [ 'item' => $item, 'error' => Helper::get_wp_error( $e ) ] ) );
				continue;
			}
		}

		return $collection;
	}

	/**
	 * Updates an existing action.
	 *
	 * @param  int  $id  Action ID.
	 * @param  array  $data  Data to update.
	 *
	 * @return Action|null The updated Action object or null on failure.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function update( int $id, array $data ): ?Action {
		$action = $this->get_item( $id );
		if ( ! $action ) {
			throw new Exception( Error_Codes::NOT_FOUND, __( 'Action not found.', 'limb-chatbot' ) );
		}
		if ( ! empty( $data['title'] ) ) {
			$data['name'] = Helper::text_to_underscore( $data['title'] );
		}
		if ( ( $existing = Action::find_by_name( $data['name'] ) ) instanceof Action ) {
			if ($existing->get_id() !== $id) {
				throw new Exception( Error_Codes::VALIDATION_INVALID_VALUE, __( 'Action with this title already exists.', 'limb-chatbot' ) );
			}
		}

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

	/**
	 * Retrieves a single action by ID.
	 *
	 * @param  int  $id  Action ID.
	 *
	 * @return Action|null The Action object or null if not found.
	 * @since 1.0.0
	 */
	public function get_item( int $id ): ?Action {
		return Action::find( $id );
	}

	/**
	 * Creates a new action.
	 *
	 * @param  array  $data  Action data including name and ai_instructions.
	 *
	 * @return Action|null The created Action object or null on failure.
	 * @throws \Exception
	 * @since 1.0.0
	 */
	public function create( array $data ): ?Action {
		if ( empty( $data['name'] ) ) {
			$data['name'] = Helper::text_to_underscore( $data['title'] );
		}
		if ( empty( $data['status'] ) ) {
			$data['status'] = Action::STATUS_ACTIVE;
		}

		return Action::create( $data );
	}
}

