<?php
/**
 * AJAX handlers for row actions.
 *
 * @package RedirectZen
 */

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

class RDZ_Ajax {

	/**
	 * Hooks.
	 */
	public static function init() {
		add_action( 'wp_ajax_rdz_update_redirect', array( __CLASS__, 'update_redirect' ) );
		add_action( 'wp_ajax_rdz_delete_redirect', array( __CLASS__, 'delete_redirect' ) );
		add_action( 'wp_ajax_rdz_toggle_redirect', array( __CLASS__, 'toggle_redirect' ) );
		add_action( 'wp_ajax_rdz_verify_redirect', array( __CLASS__, 'verify_redirect' ) );
		add_action( 'wp_ajax_rdz_create_from_404', array( __CLASS__, 'create_from_404' ) );
		add_action( 'wp_ajax_rdz_404_status', array( __CLASS__, 'log_status' ) );
		add_action( 'wp_ajax_rdz_delete_404', array( __CLASS__, 'delete_404' ) );
		add_action( 'wp_ajax_rdz_hide_task', array( __CLASS__, 'hide_task' ) );
		add_action( 'wp_ajax_rdz_subscribe', array( __CLASS__, 'subscribe' ) );
	}

	/**
	 * Shared guard: capability + nonce; returns the row ID.
	 *
	 * @param string $id_key POST key holding the ID.
	 * @return int
	 */
	private static function guard( $id_key = 'redirect_id' ) {
		if ( ! current_user_can( RDZ_Admin::CAPABILITY ) ) {
			wp_send_json_error( array( 'message' => __( 'You are not allowed to do that.', 'redirectzen-301-redirect-manager' ) ), 403 );
		}
		check_ajax_referer( 'rdz_admin_nonce', 'nonce' );

		$id = isset( $_POST[ $id_key ] ) ? absint( $_POST[ $id_key ] ) : 0;
		if ( ! $id ) {
			wp_send_json_error( array( 'message' => __( 'Missing ID.', 'redirectzen-301-redirect-manager' ) ), 400 );
		}

		return $id;
	}

	/**
	 * Sends a uniform response.
	 *
	 * @param mixed $result Result (WP_Error → error response).
	 */
	private static function respond( $result ) {
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( array( 'message' => $result->get_error_message() ), 400 );
		}

		wp_send_json_success( is_array( $result ) ? $result : array() );
	}

	// Every public handler below verifies capability + nonce first, via
	// guard() or a direct check_ajax_referer( 'rdz_admin_nonce', 'nonce' ),
	// before reading any request data. The nonce sniff can't trace that
	// across the guard() call, so it is disabled for this handler block.
	// phpcs:disable WordPress.Security.NonceVerification.Missing

	/**
	 * Inline edit: source/target/type.
	 */
	public static function update_redirect() {
		$id = self::guard();

		$fields = array();
		if ( isset( $_POST['source'] ) ) {
			$fields['source'] = sanitize_text_field( wp_unslash( $_POST['source'] ) );
		}
		if ( isset( $_POST['target'] ) ) {
			$fields['target'] = sanitize_text_field( wp_unslash( $_POST['target'] ) );
		}
		if ( isset( $_POST['redirect_type'] ) ) {
			$fields['redirect_type'] = absint( $_POST['redirect_type'] );
		}

		self::respond( RDZ_Redirects::update_rule( $id, $fields ) );
	}

	/**
	 * Deletes one rule (destructive → the UI keeps its confirm()).
	 */
	public static function delete_redirect() {
		$id      = self::guard();
		$deleted = RDZ_Redirects::delete_rules( array( $id ) );

		self::respond( $deleted ? array( 'deleted' => $deleted ) : new WP_Error( 'rdz_not_found', __( 'Redirect not found.', 'redirectzen-301-redirect-manager' ) ) );
	}

	/**
	 * Enables/disables a rule (reversible → instant, no confirm).
	 */
	public static function toggle_redirect() {
		$id     = self::guard();
		$active = isset( $_POST['active'] ) ? (int) $_POST['active'] : 0;

		$result = RDZ_Redirects::update_rule( $id, array( 'is_active' => $active ) );
		if ( is_wp_error( $result ) ) {
			self::respond( $result );
		}

		wp_send_json_success( array( 'is_active' => (int) $result['is_active'] ) );
	}

	/**
	 * Verifies one rule synchronously and returns the fresh status.
	 */
	public static function verify_redirect() {
		$id   = self::guard();
		$rule = RDZ_Redirects::get( $id );
		if ( ! $rule ) {
			self::respond( new WP_Error( 'rdz_not_found', __( 'Redirect not found.', 'redirectzen-301-redirect-manager' ) ) );
		}

		$rule = RDZ_Verifier::verify_rule( $rule );

		wp_send_json_success(
			array(
				'verify_status' => $rule['verify_status'],
				'verify_http'   => (int) $rule['verify_http'],
				'verify_hops'   => (int) $rule['verify_hops'],
			)
		);
	}

	/**
	 * One-click redirect from a 404 log row.
	 */
	public static function create_from_404() {
		$id = self::guard( 'log_id' );

		$row = RDZ_404_Log::get( $id );
		if ( ! $row ) {
			self::respond( new WP_Error( 'rdz_not_found', __( '404 entry not found.', 'redirectzen-301-redirect-manager' ) ) );
		}

		$target = isset( $_POST['target'] ) ? sanitize_text_field( wp_unslash( $_POST['target'] ) ) : '';
		$type   = isset( $_POST['redirect_type'] ) ? absint( $_POST['redirect_type'] ) : (int) RDZ_Settings::get( 'default_redirect_type' );

		$result = RDZ_Redirects::add_rule( $row['path'], $target, $type );
		if ( is_wp_error( $result ) ) {
			self::respond( $result );
		}

		RDZ_Redirects::record_user_fix();
		RDZ_404_Log::set_status( $id, 2 );
		RDZ_404_Log::resolve_matching( $result['source'] );
		spawn_cron();

		wp_send_json_success( array( 'redirect_id' => (int) $result['id'], 'chain' => $result['chain'] ) );
	}

	/**
	 * Ignore / unignore a 404 row (reversible → instant with Undo).
	 */
	public static function log_status() {
		$id     = self::guard( 'log_id' );
		$status = isset( $_POST['status'] ) ? (int) $_POST['status'] : 1;
		if ( ! in_array( $status, array( 0, 1 ), true ) ) {
			$status = 1;
		}

		self::respond( RDZ_404_Log::set_status( $id, $status ) ? array( 'status' => $status ) : new WP_Error( 'rdz_db_error', __( 'Could not update the entry.', 'redirectzen-301-redirect-manager' ) ) );
	}

	/**
	 * Deletes a 404 row (destructive → the UI keeps its confirm()).
	 */
	public static function delete_404() {
		$id = self::guard( 'log_id' );

		self::respond( RDZ_404_Log::delete_rows( array( $id ) ) ? array() : new WP_Error( 'rdz_not_found', __( '404 entry not found.', 'redirectzen-301-redirect-manager' ) ) );
	}

	/**
	 * Hides a setup task row (per user).
	 */
	public static function hide_task() {
		if ( ! current_user_can( RDZ_Admin::CAPABILITY ) ) {
			wp_send_json_error( array( 'message' => __( 'You are not allowed to do that.', 'redirectzen-301-redirect-manager' ) ), 403 );
		}
		check_ajax_referer( 'rdz_admin_nonce', 'nonce' );

		$task = isset( $_POST['task'] ) ? sanitize_key( wp_unslash( $_POST['task'] ) ) : '';
		if ( ! in_array( $task, RDZ_Admin::$dismissible_tasks, true ) ) {
			wp_send_json_error( array( 'message' => __( 'Unknown task.', 'redirectzen-301-redirect-manager' ) ), 400 );
		}

		$hidden = RDZ_Admin::hidden_tasks();
		if ( ! in_array( $task, $hidden, true ) ) {
			$hidden[] = $task;
			update_user_meta( get_current_user_id(), 'rdz_hidden_tasks', $hidden );
		}

		wp_send_json_success();
	}

	/**
	 * Explicit newsletter opt-in from the dashboard card.
	 */
	public static function subscribe() {
		if ( ! current_user_can( RDZ_Admin::CAPABILITY ) ) {
			wp_send_json_error( array( 'message' => __( 'You are not allowed to do that.', 'redirectzen-301-redirect-manager' ) ), 403 );
		}
		check_ajax_referer( 'rdz_admin_nonce', 'nonce' );

		$email  = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
		$result = RDZ_Optin::record( $email, 'dashboard_card' );
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( array( 'message' => $result->get_error_message() ), 400 );
		}

		wp_send_json_success();
	}

	// phpcs:enable WordPress.Security.NonceVerification.Missing
}
