<?php

namespace Limb_Chatbot\Includes\Data_Objects;

use Limb_Chatbot\Includes\Services\Collection;
use Limb_Chatbot\Includes\Services\Data_Object_Collection;

class Action extends WPDB_Data_Object {
	const TABLE_NAME = 'lbaic_actions';
	const FILLABLE = [
		'id',
		'title',
		'name',
		'ai_instructions',
		'status',
		'created_at',
		'updated_at'
	];

	const STATUS_INACTIVE = 0;
	const STATUS_ACTIVE = 1;

	public ?int $status;

	public string $title;

	/**
	 * @var string Action name
	 */
	public string $name;

	/**
	 * @var string AI instructions
	 */
	public string $ai_instructions;

	/**
	 * @var string Created timestamp
	 */
	public $created_at;

	/**
	 * @var string Updated timestamp
	 */
	public $updated_at;

	/**
	 * @json_excluded
	 * @var array Meta properties to load
	 */
	public array $meta_properties = array( 'parameters', 'action_callbacks' );

	/**
	 * @json_excluded
	 * @var mixed Included relations
	 */
	public array $included = [];

	/**
	 * Find action by name
	 *
	 * @param  string  $action_name  Action name
	 *
	 * @return static|null
	 */
	public static function find_by_name( $action_name ) {
		return self::where( [ 'name' => $action_name ] )->first() ?? null;
	}

	public static function find_by_title( string $value ) {
		return Action::where( [ 'title' => $value ] )->first() ?? null;
	}

	/**
	 * Attach a callback to this action
	 *
	 * @param  int  $callback_id  Callback ID
	 * @param  int  $order  Execution order (default 1)
	 * @param  int  $is_required  Whether callback is required (default 1)
	 *
	 * @return Action_Callback
	 * @throws \Exception
	 */
	public function attach_callback( int $callback_id, int $order = 1, int $is_required = 1 ): Action_Callback {
		// Check if callback already exists for this action
		$existing = Action_Callback::where( [
			'action_id' => $this->get_id(),
			'id'        => $callback_id
		] )->first();

		if ( $existing ) {
			// Update existing callback
			$existing->set_order( $order );
			$existing->set_is_required( $is_required );
			$existing->touch();
			$existing->save();

			return $existing;
		}

		// Create new callback linked to this action
		$callback = new Action_Callback();
		$callback->set_action_id( $this->get_id() );
		$callback->set_id( $callback_id );
		$callback->set_order( $order );
		$callback->set_is_required( $is_required );
		$callback->save();

		return $callback;
	}

	/**
	 * Check if action has any callbacks
	 *
	 * @return null|Collection
	 */
	public function has_callbacks(): ?Collection {
		$callbacks = $this->get_callbacks();

		return $callbacks->is_empty() ? null : $callbacks;
	}

	/**
	 * Get action callbacks ordered by execution order
	 *
	 * @return Data_Object_Collection Collection of Action_Callback objects
	 */
	public function get_callbacks(): Data_Object_Collection {
		return Action_Callback::where( [ 'action_id' => $this->get_id() ], - 1, - 1, '`order`', 'asc' );
	}

	/**
	 * Get created timestamp
	 *
	 * @return string
	 */
	public function get_created_at() {
		return $this->created_at;
	}

	/**
	 * Set created timestamp
	 *
	 * @param  string  $created_at
	 *
	 * @return void
	 */
	public function set_created_at( $created_at ): void {
		$this->created_at = $created_at;
	}

	/**
	 * Get updated timestamp
	 *
	 * @return string
	 */
	public function get_updated_at() {
		return $this->updated_at;
	}

	/**
	 * Set updated timestamp
	 *
	 * @param  string  $updated_at
	 *
	 * @return void
	 */
	public function set_updated_at( $updated_at ): void {
		$this->updated_at = $updated_at;
	}

	/**
	 * Get action name
	 *
	 * @return string
	 */
	public function get_name(): string {
		return $this->name;
	}

	/**
	 * Set action name
	 *
	 * @param  string  $name
	 *
	 * @return void
	 */
	public function set_name( string $name ): void {
		$this->name = $name;
	}

	/**
	 * Get AI instructions
	 *
	 * @return string|null
	 */
	public function get_ai_instructions(): ?string {
		return $this->ai_instructions;
	}

	/**
	 * Set AI instructions
	 *
	 * @param  string|null  $ai_instructions
	 *
	 * @return void
	 */
	public function set_ai_instructions( ?string $ai_instructions ): void {
		$this->ai_instructions = $ai_instructions;
	}

	/**
	 * Get parameters (alias for parameters() method)
	 *
	 * @return Data_Object_Collection
	 */
	public function get_parameters(): Data_Object_Collection {
		return $this->parameters();
	}

	/**
	 * Get action parameters
	 *
	 * @return Data_Object_Collection
	 */
	public function parameters(): Data_Object_Collection {
		return Parameter::where( [ 'action_id' => $this->get_id() ],  - 1, - 1, '`order`', 'asc' );
	}

	public function action_callbacks(): Data_Object_Collection {
		return Action_Callback::where( [ 'action_id' => $this->get_id() ] );
	}

	/**
	 * Delete actions matching the where condition
	 *
	 * Also deletes associated parameters and action callbacks
	 *
	 * @param  array  $where  Where condition for deletion
	 *
	 * @return bool True on success, false on failure
	 */
	public static function delete( $where ): bool {
		$items = self::where( $where );
		if ( ! $items->is_empty() ) {
			$items->each( function ( Action $action ) {
				Parameter::delete( [ 'action_id' => $action->get_id() ] );
				Action_Callback::delete( [ 'action_id' => $action->get_id() ] );
			} );
		}

		return parent::delete( $where );
	}

	public function get_status(): ?int {
		return $this->status;
	}

	public function set_status( ?int $status ): void {
		$this->status = $status;
	}

	public function has_callback( $name ) {
		return ! Action_Callback::where(['action_id' => $this->id, 'name' => $name])->is_empty();
	}

	public function get_title(): string {
		return $this->title;
	}

	public function set_title( string $title ): void {
		$this->title = $title;
	}

	public function get_chatbot_uuid(): ?string {
		return $this->chatbot_uuid;
	}

	public function set_chatbot_uuid( ?string $chatbot_uuid ): void {
		$this->chatbot_uuid = $chatbot_uuid;
	}

	public function get_chatbot(): ?Chatbot {
		$chatbot = property_exists( $this, 'chatbot_uuid' ) && ! empty( $this->chatbot_uuid ) ? Chatbot::find_by_uuid( $this->chatbot_uuid ) : null;
		if ( ! $chatbot instanceof Chatbot ) {
			$chatbot = Chatbot::make();
		}

		return $chatbot;
	}
}