<?php
/**
 * Cleanup task registry.
 *
 * @package DatabaseCleanup
 */

namespace DatabaseCleanup\Includes;

use DatabaseCleanup\Includes\Tasks\Task_As_Canceled_Actions;
use DatabaseCleanup\Includes\Tasks\Task_As_Complete_Actions;
use DatabaseCleanup\Includes\Tasks\Task_As_Complete_Logs;
use DatabaseCleanup\Includes\Tasks\Task_As_Failed_Actions;
use DatabaseCleanup\Includes\Tasks\Task_As_Failed_Logs;
use DatabaseCleanup\Includes\Tasks\Task_As_Pending_Actions;
use DatabaseCleanup\Includes\Tasks\Task_As_Pending_Logs;
use DatabaseCleanup\Includes\Tasks\Task_Auto_Drafts;
use DatabaseCleanup\Includes\Tasks\Task_Duplicated_Commentmeta;
use DatabaseCleanup\Includes\Tasks\Task_Duplicated_Postmeta;
use DatabaseCleanup\Includes\Tasks\Task_Duplicated_Termmeta;
use DatabaseCleanup\Includes\Tasks\Task_Duplicated_Usermeta;
use DatabaseCleanup\Includes\Tasks\Task_Expired_Transients;
use DatabaseCleanup\Includes\Tasks\Task_Oembed_Caches;
use DatabaseCleanup\Includes\Tasks\Task_Old_Drafts;
use DatabaseCleanup\Includes\Tasks\Task_Optimize_Tables;
use DatabaseCleanup\Includes\Tasks\Task_Orphaned_Comment_Meta;
use DatabaseCleanup\Includes\Tasks\Task_Orphaned_Post_Meta;
use DatabaseCleanup\Includes\Tasks\Task_Orphaned_Term_Relationships;
use DatabaseCleanup\Includes\Tasks\Task_Pingbacks;
use DatabaseCleanup\Includes\Tasks\Task_Post_Revisions;
use DatabaseCleanup\Includes\Tasks\Task_Repair_Tables;
use DatabaseCleanup\Includes\Tasks\Task_Spam_Comments;
use DatabaseCleanup\Includes\Tasks\Task_Trashed_Comments;
use DatabaseCleanup\Includes\Tasks\Task_Trashed_Posts;
use DatabaseCleanup\Includes\Tasks\Task_Unapproved_Comments;
use DatabaseCleanup\Includes\Tasks\Task_Unused_Termmeta;
use DatabaseCleanup\Includes\Tasks\Task_Unused_Usermeta;
use DatabaseCleanup\Includes\Tasks\Task_Orphaned_Transient_Timeouts;
use DatabaseCleanup\Includes\Tasks\Task_Woocommerce_Sessions;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Cleanup_Task_Registry {

	/** @var array<string, Cleanup_Task_Interface>|null */
	private static ?array $tasks = null;

	/** @var array<string, string> */
	private const CATEGORIES = [
		'revisions'                   => 'content',
		'auto_drafts'                 => 'content',
		'old_drafts'                  => 'content',
		'trashed_posts'               => 'content',
		'oembed_caches'               => 'content',
		'spam_comments'               => 'comments',
		'trashed_comments'            => 'comments',
		'unapproved_comments'         => 'comments',
		'pingbacks'                   => 'comments',
		'expired_transients'          => 'options',
		'orphaned_transient_timeouts' => 'options',
		'woocommerce_sessions'        => 'woocommerce',
		'orphaned_post_meta'          => 'orphans',
		'orphaned_comment_meta'       => 'orphans',
		'unused_usermeta'             => 'orphans',
		'unused_termmeta'             => 'orphans',
		'orphaned_term_relationships' => 'orphans',
		'duplicated_postmeta'         => 'orphans',
		'duplicated_commentmeta'      => 'orphans',
		'duplicated_usermeta'         => 'orphans',
		'duplicated_termmeta'         => 'orphans',
		'optimize_tables'             => 'maintenance',
		'repair_tables'               => 'maintenance',
		'as_complete_actions'         => 'action_scheduler',
		'as_pending_actions'          => 'action_scheduler',
		'as_failed_actions'           => 'action_scheduler',
		'as_canceled_actions'         => 'action_scheduler',
		'as_complete_logs'            => 'action_scheduler',
		'as_pending_logs'             => 'action_scheduler',
		'as_failed_logs'              => 'action_scheduler',
	];

	public static function boot(): void {
		require_once __DIR__ . '/tasks/abstract-cleanup-task.php';
		require_once __DIR__ . '/tasks/class-task-post-revisions.php';
		require_once __DIR__ . '/tasks/class-task-auto-drafts.php';
		require_once __DIR__ . '/tasks/class-task-old-drafts.php';
		require_once __DIR__ . '/tasks/class-task-trashed-posts.php';
		require_once __DIR__ . '/tasks/class-task-spam-comments.php';
		require_once __DIR__ . '/tasks/class-task-trashed-comments.php';
		require_once __DIR__ . '/tasks/class-task-unapproved-comments.php';
		require_once __DIR__ . '/tasks/class-task-pingbacks.php';
		require_once __DIR__ . '/tasks/class-task-expired-transients.php';
		require_once __DIR__ . '/tasks/class-task-orphaned-transient-timeouts.php';
		require_once __DIR__ . '/tasks/class-task-woocommerce-sessions.php';
		require_once __DIR__ . '/tasks/class-task-orphaned-post-meta.php';
		require_once __DIR__ . '/tasks/class-task-orphaned-comment-meta.php';
		require_once __DIR__ . '/tasks/class-task-unused-usermeta.php';
		require_once __DIR__ . '/tasks/class-task-unused-termmeta.php';
		require_once __DIR__ . '/tasks/class-task-orphaned-term-relationships.php';
		require_once __DIR__ . '/tasks/class-task-duplicated-postmeta.php';
		require_once __DIR__ . '/tasks/class-task-duplicated-commentmeta.php';
		require_once __DIR__ . '/tasks/class-task-duplicated-usermeta.php';
		require_once __DIR__ . '/tasks/class-task-duplicated-termmeta.php';
		require_once __DIR__ . '/tasks/class-task-oembed-caches.php';
		require_once __DIR__ . '/tasks/class-task-optimize-tables.php';
		require_once __DIR__ . '/tasks/class-task-repair-tables.php';
		require_once __DIR__ . '/tasks/abstract-action-scheduler-task.php';
		require_once __DIR__ . '/tasks/class-task-as-complete-actions.php';
		require_once __DIR__ . '/tasks/class-task-as-pending-actions.php';
		require_once __DIR__ . '/tasks/class-task-as-failed-actions.php';
		require_once __DIR__ . '/tasks/class-task-as-canceled-actions.php';
		require_once __DIR__ . '/tasks/class-task-as-complete-logs.php';
		require_once __DIR__ . '/tasks/class-task-as-pending-logs.php';
		require_once __DIR__ . '/tasks/class-task-as-failed-logs.php';
	}

	/**
	 * @return array<string, Cleanup_Task_Interface>
	 */
	public static function all(): array {
		if ( self::$tasks !== null ) {
			return self::$tasks;
		}

		self::boot();

		$instances = [
			new Task_Post_Revisions(),
			new Task_Auto_Drafts(),
			new Task_Old_Drafts(),
			new Task_Trashed_Posts(),
			new Task_Oembed_Caches(),
			new Task_Spam_Comments(),
			new Task_Trashed_Comments(),
			new Task_Unapproved_Comments(),
			new Task_Pingbacks(),
			new Task_Expired_Transients(),
			new Task_Orphaned_Transient_Timeouts(),
			new Task_Orphaned_Post_Meta(),
			new Task_Orphaned_Comment_Meta(),
			new Task_Unused_Usermeta(),
			new Task_Unused_Termmeta(),
			new Task_Orphaned_Term_Relationships(),
			new Task_Duplicated_Postmeta(),
			new Task_Duplicated_Commentmeta(),
			new Task_Duplicated_Usermeta(),
			new Task_Duplicated_Termmeta(),
			new Task_Optimize_Tables(),
			new Task_Repair_Tables(),
			new Task_As_Complete_Actions(),
			new Task_As_Pending_Actions(),
			new Task_As_Failed_Actions(),
			new Task_As_Canceled_Actions(),
			new Task_As_Complete_Logs(),
			new Task_As_Pending_Logs(),
			new Task_As_Failed_Logs(),
		];

		if ( Task_Woocommerce_Sessions::is_available() ) {
			$instances[] = new Task_Woocommerce_Sessions();
		}

		self::$tasks = [];

		foreach ( $instances as $task ) {
			self::$tasks[ $task->get_id() ] = $task;
		}

		/**
		 * Filter registered database cleanup tasks.
		 *
		 * @param array<string, Cleanup_Task_Interface> $tasks
		 */
		self::$tasks = apply_filters( 'wpps_database_cleanup_tasks', self::$tasks );

		return self::$tasks;
	}

	public static function get( string $id ): ?Cleanup_Task_Interface {
		$all = self::all();

		return $all[ $id ] ?? null;
	}

	public static function get_category( string $task_id ): string {
		return self::CATEGORIES[ $task_id ] ?? 'general';
	}

	/**
	 * @return array<string, string>
	 */
	public static function category_labels(): array {
		return [
			'content'     => __( 'Content', 'wp-powersuite' ),
			'comments'    => __( 'Comments', 'wp-powersuite' ),
			'options'     => __( 'Options', 'wp-powersuite' ),
			'orphans'     => __( 'Orphans & duplicates', 'wp-powersuite' ),
			'maintenance' => __( 'Maintenance', 'wp-powersuite' ),
			'action_scheduler' => __( 'Action Scheduler', 'wp-powersuite' ),
			'woocommerce'      => __( 'WooCommerce', 'wp-powersuite' ),
			'general'     => __( 'Other', 'wp-powersuite' ),
		];
	}

	/**
	 * @return list<array{id:string,label:string,description:string,safe:bool,category:string}>
	 */
	public static function catalog(): array {
		$items = [];

		foreach ( self::all() as $task_id => $task ) {
			$items[] = [
				'id'            => $task_id,
				'label'         => $task->get_label(),
				'description'   => $task->get_description(),
				'safe'          => $task->is_safe(),
				'safety_level'  => self::safety_level( $task_id ),
				'category'      => self::get_category( $task_id ),
			];
		}

		return $items;
	}

	/**
	 * Three-tier safety classification used by the UI: safe | review | advanced.
	 *
	 * - safe:     reversible/expendable data, enabled by default.
	 * - review:   content that may still be wanted (drafts, pending comments).
	 * - advanced: structural/queue operations that need extra care.
	 */
	public static function safety_level( string $task_id ): string {
		$task = self::get( $task_id );

		if ( $task && $task->is_safe() ) {
			return 'safe';
		}

		$review = [ 'old_drafts', 'unapproved_comments', 'trashed_posts', 'pingbacks' ];

		if ( in_array( $task_id, $review, true ) ) {
			return 'review';
		}

		return 'advanced';
	}

	/**
	 * @return list<string>
	 */
	public static function safe_task_ids(): array {
		$ids = [];

		foreach ( self::all() as $id => $task ) {
			if ( $task->is_safe() ) {
				$ids[] = $id;
			}
		}

		return $ids;
	}

	public static function is_allowed_task( string $task_id, array $settings, bool $allow_caution = false ): bool {
		$task = self::get( $task_id );

		if ( ! $task ) {
			return false;
		}

		if ( ! $task->is_safe() && ! $allow_caution ) {
			return false;
		}

		return self::is_scannable_task( $task_id, $settings );
	}

	/**
	 * Whether a task may be included in scans (read-only; caution tasks are allowed).
	 */
	public static function is_scannable_task( string $task_id, array $settings ): bool {
		$task = self::get( $task_id );

		if ( ! $task ) {
			return false;
		}

		if ( $task_id === 'woocommerce_sessions' && ! Task_Woocommerce_Sessions::is_available() ) {
			return false;
		}

		if ( in_array( $task_id, [ 'optimize_tables', 'repair_tables' ], true ) && empty( $settings['optimize_tables'] ) ) {
			return false;
		}

		return true;
	}

	/**
	 * @param list<string> $task_ids
	 */
	public static function includes_caution_tasks( array $task_ids ): bool {
		foreach ( $task_ids as $task_id ) {
			$task = self::get( sanitize_key( (string) $task_id ) );

			if ( $task && ! $task->is_safe() ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * @param list<string> $task_ids
	 * @return list<string>
	 */
	public static function filter_allowed_task_ids( array $task_ids, array $settings, bool $allow_caution = false ): array {
		$valid = [];

		foreach ( $task_ids as $task_id ) {
			$task_id = sanitize_key( (string) $task_id );

			if ( $task_id !== '' && self::is_allowed_task( $task_id, $settings, $allow_caution ) ) {
				$valid[] = $task_id;
			}
		}

		return array_values( array_unique( $valid ) );
	}
}
