<?php
/**
 * Trash AJAX handlers — list, restore, delete, batch ops, empty.
 *
 * @package CoffeeWP_Media_Cleanup
 */

namespace CWPM\Ajax;

use CWPM\Core\Db;
use CWPM\Core\Logger;
use CWPM\Core\Trash;

defined( 'ABSPATH' ) || exit;

// phpcs:disable WordPress.Security.NonceVerification.Missing -- nonce verified centrally in BaseHandler::verify_request().

class TrashHandler extends BaseHandler {

	/**
	 * Constructor — register AJAX actions.
	 */
	public function __construct() {
		add_action( 'wp_ajax_cwpm_trash_list', array( $this, 'trash_list' ) );
		add_action( 'wp_ajax_cwpm_trash_list_ids', array( $this, 'trash_list_ids' ) );
		add_action( 'wp_ajax_cwpm_trash_restore', array( $this, 'trash_restore' ) );
		add_action( 'wp_ajax_cwpm_trash_delete', array( $this, 'trash_delete' ) );
		add_action( 'wp_ajax_cwpm_trash_empty', array( $this, 'trash_empty' ) );
		add_action( 'wp_ajax_cwpm_trash_batch_restore', array( $this, 'trash_batch_restore' ) );
		add_action( 'wp_ajax_cwpm_trash_batch_delete', array( $this, 'trash_batch_delete' ) );
	}

	/**
	 * Return a paginated, searchable list of trash records.
	 *
	 * On first call for existing installs (DB table empty but trash folder has
	 * files), triggers sync_trash_table() to populate the DB.
	 */
	public function trash_list() {
		check_ajax_referer( 'cwpm_nonce', 'nonce' );
		$this->verify_request();

		$args = array(
			'page'     => isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1,
			'per_page' => isset( $_POST['per_page'] ) ? absint( $_POST['per_page'] ) : 50,
			'search'   => isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '',
		);

		$data = Db::query_trash( $args );

		if ( empty( $data['results'] ) && empty( $args['search'] ) ) {
			Trash::sync_trash_table();
			$data = Db::query_trash( $args );
		}

		wp_send_json_success( $data );
	}

	/**
	 * Return lightweight IDs for all matching trash records (no pagination).
	 *
	 * Used by "Select All" so the frontend can build batch action targets
	 * across all matching rows without loading full result data.
	 */
	public function trash_list_ids() {
		check_ajax_referer( 'cwpm_nonce', 'nonce' );
		$this->verify_request();

		$args = array(
			'search' => isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '',
		);

		$results = Db::query_trash_ids( $args );
		wp_send_json_success( array( 'results' => $results ) );
	}

	/**
	 * Restore a single file from the trash back to the uploads directory.
	 */
	public function trash_restore() {
		check_ajax_referer( 'cwpm_nonce', 'nonce' );
		$this->verify_request();

		$rel = sanitize_text_field( wp_unslash( $_POST['rel_path'] ?? '' ) );

		if ( empty( $rel ) ) {
			wp_send_json_error( 'Missing rel_path', 400 );
		}

		if ( Trash::restore_file( $rel ) ) {
			Db::update_result_action( $rel, 'restored', 'restored' );
			Logger::info( 'File restored from trash: ' . $rel );
			wp_send_json_success( array( 'rel_path' => $rel ) );
		} else {
			Logger::error( 'Failed to restore file from trash: ' . $rel );
			wp_send_json_error( 'Restore failed', 500 );
		}
	}

	/**
	 * Permanently delete a single file from the trash.
	 */
	public function trash_delete() {
		check_ajax_referer( 'cwpm_nonce', 'nonce' );
		$this->verify_request();

		$rel = sanitize_text_field( wp_unslash( $_POST['rel_path'] ?? '' ) );

		if ( empty( $rel ) ) {
			wp_send_json_error( 'Missing rel_path', 400 );
		}

		if ( Trash::permanent_delete( $rel ) ) {
			Db::update_result_action( $rel, 'deleted', 'deleted' );
			Logger::info( 'File permanently deleted from trash: ' . $rel );
			wp_send_json_success( array( 'rel_path' => $rel ) );
		} else {
			Logger::error( 'Failed to permanently delete file from trash: ' . $rel );
			wp_send_json_error( 'Delete failed', 500 );
		}
	}

	/**
	 * Permanently delete every file in the trash.
	 */
	public function trash_empty() {
		check_ajax_referer( 'cwpm_nonce', 'nonce' );
		$this->verify_request();

		$count = Trash::empty_trash();

		Logger::info( 'Trash emptied. ' . $count . ' files permanently deleted.' );

		wp_send_json_success( array( 'deleted' => $count ) );
	}

	/**
	 * Restore multiple files from the trash in a single request.
	 *
	 * Expects POST:
	 *   rel_paths — JSON-encoded array of rel_path strings.
	 *   force     — if '1', delete DB records even when file is missing.
	 */
	public function trash_batch_restore() {
		check_ajax_referer( 'cwpm_nonce', 'nonce' );
		$this->verify_request();

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- decode_string_array() validates + sanitises each item.
		$raw       = isset( $_POST['rel_paths'] ) ? wp_unslash( $_POST['rel_paths'] ) : '';
		$rel_paths = $this->decode_string_array( is_string( $raw ) ? $raw : '' );

		if ( null === $rel_paths ) {
			wp_send_json_error( 'Invalid rel_paths format', 400 );
		}

		$force = isset( $_POST['force'] ) && '1' === $_POST['force'];

		$results   = array();
		$succeeded = 0;
		$failed    = 0;

		foreach ( $rel_paths as $rel ) {
			if ( $force ) {

				$attachment_id = Trash::find_attachment_by_rel_path( $rel );
				Db::delete_trash_record( $rel );
				if ( $attachment_id > 0 ) {
					Trash::hard_delete_soft_attachment( $attachment_id );
				}
				Db::update_result_action( $rel, 'restored', 'restored' );
				Logger::info( 'File restored from trash (forced): ' . $rel );
				$results[] = array(
					'rel_path' => $rel,
					'success'  => true,
					'forced'   => true,
				);
				++$succeeded;
			} else {
				$result    = Trash::restore_file( $rel );
				$results[] = array(
					'rel_path' => $rel,
					'success'  => $result,
				);
				if ( $result ) {
					Db::update_result_action( $rel, 'restored', 'restored' );
					Logger::info( 'File restored from trash: ' . $rel );
					++$succeeded;
				} else {
					++$failed;
				}
			}
		}

		Logger::info( 'Batch restore completed. ' . $succeeded . ' files restored.' . ( $force ? ' (forced - DB records only)' : '' ) );

		wp_send_json_success(
			array(
				'succeeded' => $succeeded,
				'failed'    => $failed,
				'results'   => $results,
			)
		);
	}

	/**
	 * Permanently delete multiple files from the trash in a single request.
	 *
	 * Expects POST:
	 *   rel_paths — JSON-encoded array of rel_path strings.
	 *   force     — if '1', delete DB records even when file is missing.
	 */
	public function trash_batch_delete() {
		check_ajax_referer( 'cwpm_nonce', 'nonce' );
		$this->verify_request();

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- decode_string_array() validates + sanitises each item.
		$raw       = isset( $_POST['rel_paths'] ) ? wp_unslash( $_POST['rel_paths'] ) : '';
		$rel_paths = $this->decode_string_array( is_string( $raw ) ? $raw : '' );

		if ( null === $rel_paths ) {
			wp_send_json_error( 'Invalid rel_paths format', 400 );
		}

		$force = isset( $_POST['force'] ) && '1' === $_POST['force'];

		$results   = array();
		$succeeded = 0;
		$failed    = 0;

		foreach ( $rel_paths as $rel ) {
			if ( $force ) {

				$attachment_id = Trash::find_attachment_by_rel_path( $rel );
				Db::delete_trash_record( $rel );
				if ( $attachment_id > 0 ) {
					Trash::hard_delete_soft_attachment( $attachment_id );
				}
				Db::update_result_action( $rel, 'deleted', 'deleted' );
				Logger::info( 'File permanently deleted from trash (forced): ' . $rel );
				$results[] = array(
					'rel_path' => $rel,
					'success'  => true,
					'forced'   => true,
				);
				++$succeeded;
			} else {
				$result    = Trash::permanent_delete( $rel );
				$results[] = array(
					'rel_path' => $rel,
					'success'  => $result,
				);
				if ( $result ) {
					Db::update_result_action( $rel, 'deleted', 'deleted' );
					Logger::info( 'File permanently deleted from trash: ' . $rel );
					++$succeeded;
				} else {
					++$failed;
				}
			}
		}

		Logger::info( 'Batch delete completed. ' . $succeeded . ' files permanently deleted.' . ( $force ? ' (forced - DB records only)' : '' ) );

		wp_send_json_success(
			array(
				'succeeded' => $succeeded,
				'failed'    => $failed,
				'results'   => $results,
			)
		);
	}
}
