<?php

namespace Limb_Chatbot\Includes\Data_Objects;

use Limb_Chatbot\Includes\Services\Helper;

/**
 * Represents a Job data object in the queue system.
 *
 * @since 1.0.9
 */
class Job extends WPDB_Data_Object {

	/**
	 * The name of the database table associated with this model.
	 *
	 * @since 1.0.9
	 */
	const TABLE_NAME = 'lbaic_jobs';

	/**
	 * The list of fillable fields for mass assignment.
	 *
	 * @since 1.0.9
	 */
	const FILLABLE = [
		'type',
		'sub_type',
		'status',
		'progress_percent',
		'config',
		'chatbot_uuid',
		'stats',
		'errors',
		'created_at',
		'started_at',
		'completed_at',
	];

	/**
	 * Job status constants
	 */
	const STATUS_PENDING = 'pending';
	const STATUS_GENERATING_TASKS = 'generating_tasks';
	const STATUS_PROCESSING = 'processing';
	const STATUS_PAUSED = 'paused';
	const STATUS_COMPLETED = 'completed';
	const STATUS_FAILED = 'failed';
	const STATUS_CANCELLED = 'cancelled';

	/**
	 * Job type constants
	 */
	const TYPE_DATASET_GENERATING = 'dataset_generating';
	const TYPE_DATASET_DELETE = 'dataset_delete';
	const TYPE_DATASET_SYNC = 'dataset_sync';
	const TYPE_DATASET_REGENERATE = 'dataset_regenerate';
	const TYPE_FILE_UPLOAD = 'file_upload';
	const TYPE_SITEMAP_SCRAPE = 'sitemap_scrape';
	const CHATBOT_DEFAULT = 'default';
	const SUB_TYPE_ACTIONABLE_DATASET_GENERATION = 'actionable';
	const SUB_TYPE_INFORMATIONAL_DATASET_GENERATION = 'informational';

	/**
	 * Job config key: resolved DB id for informational vector storage (set during job create / automation).
	 */
	const CONFIG_RESOLVED_VECTOR_INDEX_ID = 'resolved_vector_index_id';

	/**
	 * Job type.
	 *
	 * @var string
	 * @since 1.0.9
	 */
	public string $type;
	/**
	 * Job status.
	 *
	 * @var string
	 * @since 1.0.9
	 */
	public string $status = self::STATUS_PENDING;
	/**
	 * Progress percentage (0-100).
	 *
	 * @var float
	 * @since 1.0.9
	 */
	public float $progress_percent = 0.0;

	/**
	 * Job sub-type.
	 *
	 * @var string|null
	 * @since 1.0.9
	 */
	public ?string $sub_type = null;
	/**
	 * Job configuration (JSON).
	 *
	 * @var array|null
	 * @since 1.0.9
	 */
	public ?array $config = null;

	/**
	 * Job statistics (JSON).
	 *
	 * @var array|null
	 * @since 1.0.9
	 */
	public ?array $stats = null;

	/**
	 * Job errors (JSON).
	 *
	 * @var array|null
	 * @since 1.0.9
	 */
	public ?array $errors = null;

	/**
	 * Created timestamp.
	 *
	 * @var string
	 * @since 1.0.9
	 */
	public string $created_at;

	/**
	 * Started timestamp.
	 *
	 * @var string|null
	 * @since 1.0.9
	 */
	public ?string $started_at = null;

	/**
	 * Completed timestamp.
	 *
	 * @var string|null
	 * @since 1.0.9
	 */
	public ?string $completed_at = null;
	public ?string $chatbot_uuid = 'default';

	public function __construct( $instance = null ) {
		if ( is_array( $instance ) && ! empty( $instance['stats'] ) && $this->isJson( $instance['stats'] ) ) {
			$instance['stats'] = Helper::maybe_json_decode( $instance['stats'] );
		}
		if ( is_array( $instance ) && ! empty( $instance['errors'] ) && $this->isJson( $instance['errors'] ) ) {
			$instance['errors'] = Helper::maybe_json_decode( $instance['errors'] );
		}
		if ( is_array( $instance ) && ! empty( $instance['config'] ) && $this->isJson( $instance['config'] ) ) {
			$instance['config'] = Helper::maybe_json_decode( $instance['config'] );
		}
		parent::__construct( $instance );
	}

	/**
	 * Get job type.
	 *
	 * @return string
	 * @since 1.0.9
	 */
	public function get_type(): string {
		return $this->type;
	}

	/**
	 * Get job status.
	 *
	 * @return string
	 * @since 1.0.9
	 */
	public function get_status(): string {
		return $this->status;
	}

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

	/**
	 * Set job status.
	 *
	 * @param  string|null  $status
	 *
	 * @return void
	 * @since 1.0.9
	 */
	public function set_status( ?string $status ): void {
		$this->status = $status;
	}

	/**
	 * Get job configuration as array.
	 *
	 * @return null|array
	 * @since 1.0.9
	 */
	public function get_config(): ?array {
		return $this->config;
	}

	/**
	 * Set job configuration.
	 *
	 * @param  null|array  $config
	 *
	 * @return void
	 * @since 1.0.9
	 */
	public function set_config( ?array $config ): void {
		$this->config = $config;
	}

	/**
	 * Add an error to the job.
	 *
	 * @param  array  $error
	 *
	 * @return void
	 * @since 1.0.9
	 */
	public function add_error( array $error ): void {
		$errors   = $this->get_errors();
		$errors[] = $error;
		$this->set_errors( $errors );
	}

	/**
	 * Get job errors as array.
	 *
	 * @return array|null
	 * @since 1.0.9
	 */
	public function get_errors(): ?array {
		return $this->errors;
	}

	/**
	 * Set job errors.
	 *
	 * @param  array|null  $errors
	 *
	 * @return void
	 * @since 1.0.9
	 */
	public function set_errors( ?array $errors ): void {
		$this->errors = $errors;
	}

	/**
	 * Check if job is generating tasks.
	 *
	 * @return bool
	 * @since 1.0.9
	 */
	public function is_generating_tasks(): bool {
		return $this->status === self::STATUS_GENERATING_TASKS;
	}

	/**
	 * Check if job is currently processing.
	 *
	 * @return bool
	 * @since 1.0.9
	 */
	public function is_processing(): bool {
		return $this->status === self::STATUS_PROCESSING;
	}

	/**
	 * Check if job is paused.
	 *
	 * @return bool
	 * @since 1.0.9
	 */
	public function is_paused(): bool {
		return $this->status === self::STATUS_PAUSED;
	}

	/**
	 * Check if job is completed.
	 *
	 * @return bool
	 * @since 1.0.9
	 */
	public function is_completed(): bool {
		return $this->status === self::STATUS_COMPLETED;
	}

	/**
	 * Check if job is failed.
	 *
	 * @return bool
	 * @since 1.0.9
	 */
	public function is_failed(): bool {
		return $this->status === self::STATUS_FAILED;
	}

	/**
	 * Check if job is cancelled.
	 *
	 * @return bool
	 * @since 1.0.9
	 */
	public function is_cancelled(): bool {
		return $this->status === self::STATUS_CANCELLED;
	}

	/**
	 * Check if job can be processed.
	 *
	 * @return bool
	 * @since 1.0.9
	 */
	public function can_process(): bool {
		return in_array( $this->status,
			[ self::STATUS_PENDING, self::STATUS_GENERATING_TASKS, self::STATUS_PROCESSING ] );
	}

	/**
	 * Get started at timestamp.
	 *
	 * @return string|null
	 * @since 1.0.9
	 */
	public function get_started_at(): ?string {
		return $this->started_at;
	}

	/**
	 * Set started at timestamp.
	 *
	 * @param  string|null  $timestamp
	 *
	 * @return void
	 * @since 1.0.9
	 */
	public function set_started_at( ?string $timestamp ): void {
		$this->started_at = $timestamp;
	}

	/**
	 * Get completed at timestamp.
	 *
	 * @return string|null
	 * @since 1.0.9
	 */
	public function get_completed_at(): ?string {
		return $this->completed_at;
	}

	/**
	 * Set completed at timestamp.
	 *
	 * @param  string|null  $timestamp
	 *
	 * @return void
	 * @since 1.0.9
	 */
	public function set_completed_at( ?string $timestamp ): void {
		$this->completed_at = $timestamp;
	}

	/**
	 * Convert job to array for API response.
	 *
	 * @return array
	 * @since 1.0.9
	 */
	public function to_array(): array {
		return [
			'id'               => $this->id,
			'type'             => $this->type,
			'status'           => $this->status,
			'progress_percent' => $this->get_progress_percent(),
			'stats'            => $this->get_stats(),
			'errors'           => $this->get_errors(),
			'created_at'       => $this->created_at,
			'started_at'       => $this->started_at,
			'completed_at'     => $this->completed_at,
			'sub_type'         => $this->sub_type,
			'config'           => $this->config,
			'chatbot_uuid'     => $this->chatbot_uuid,
		];
	}

	/**
	 * Get progress percentage.
	 *
	 * @return float
	 * @since 1.0.9
	 */
	public function get_progress_percent(): float {
		return (float) $this->progress_percent;
	}

	/**
	 * Set progress percentage.
	 *
	 * @param  null|float  $percent
	 *
	 * @return void
	 * @since 1.0.9
	 */
	public function set_progress_percent( ?float $percent ): void {
		$percent                = $percent ?? 0.00;
		$this->progress_percent = min( 100, max( 0, $percent ) );
	}

	/**
	 * Get job statistics as array.
	 *
	 * @return array|null
	 * @since 1.0.9
	 */
	public function get_stats(): ?array {
		return $this->stats;
	}

	/**
	 * Set job statistics.
	 *
	 * @param  array|null  $stats
	 *
	 * @return void
	 * @since 1.0.9
	 */
	public function set_stats( ?array $stats ): void {
		$this->stats = $stats;
	}

	public function get_config_value( $key ) {
		return ! empty( $this->config[ $key ] ) ? $this->config[ $key ] : null;
	}

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

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

	public function is_pending() {
		return $this->status === self::STATUS_PENDING;
	}

	public function get_sub_type(): ?string {
		return $this->sub_type;
	}

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

	public function get_tasks() {
		return Task::where( [ 'job_id' => $this->get_id() ], -1, -1 )->get();
	}

	public function clear_errors() {
		$this->errors = [];
		$this->save();
	}
}

