<?php
/**
 * Administrative REST API.
 *
 * @package VoidPulse
 */

namespace VoidPulse\Admin;

use VoidPulse\Notifications\Analytics;
use VoidPulse\Notifications\RecentSaleCollector;
use VoidPulse\Infrastructure\NotificationSettings;
use VoidPulse\Infrastructure\EventRepository;
use VoidPulse\Infrastructure\Jobs;
use VoidPulse\Shared\CampaignSchema;

defined( 'ABSPATH' ) || exit;

final class RestController {
	/**
	 * Register routes.
	 *
	 * @return void
	 */
	public function register() {
		register_rest_route(
			'voidpulse/v1',
			'/campaign',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_campaign' ),
					'permission_callback' => array( $this, 'can_edit' ),
				),
				array(
					'methods'             => \WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'save_campaign' ),
					'permission_callback' => array( $this, 'can_edit' ),
					'args'                => array(
						'campaign' => array(
							'required' => true,
							'type'     => 'object',
						),
					),
				),
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/campaign/export',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'export_campaign' ),
				'permission_callback' => array( $this, 'can_edit' ),
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/campaign/defaults',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => static function () { return rest_ensure_response( CampaignSchema::defaults() ); },
				'permission_callback' => array( $this, 'can_edit' ),
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/campaign/import',
			array(
				'methods'             => \WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'import_campaign' ),
				'permission_callback' => array( $this, 'can_edit' ),
				'args'                => array(
					'document' => array( 'required' => true, 'type' => 'object' ),
				),
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/products',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'products' ),
				'permission_callback' => array( $this, 'can_edit' ),
				'args'                => array(
					'search'  => array( 'type' => 'string', 'maxLength' => 100, 'default' => '' ),
					'include' => array( 'type' => 'string', 'maxLength' => 1200, 'default' => '' ),
				),
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/analytics',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => static function ( $request ) { return rest_ensure_response( Analytics::summary( $request->get_param( 'range' ) ) ); },
				'permission_callback' => static function () { return current_user_can( 'view_voidpulse_analytics' ); },
				'args'                => array(
					'range' => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => Analytics::MAXIMUM_RANGE, 'default' => 30 ),
				),
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/diagnostics',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'diagnostics' ),
				'permission_callback' => static function () { return current_user_can( 'manage_voidpulse_settings' ); },
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/cache',
			array(
				'methods'             => \WP_REST_Server::DELETABLE,
				'callback'            => array( $this, 'clear_cache' ),
				'permission_callback' => static function () { return current_user_can( 'manage_voidpulse_settings' ); },
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/schedule/repair',
			array(
				'methods'             => \WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'repair_schedule' ),
				'permission_callback' => static function () { return current_user_can( 'manage_voidpulse_settings' ); },
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/data-lifecycle',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'data_lifecycle' ),
					'permission_callback' => static function () { return current_user_can( 'manage_voidpulse_settings' ); },
				),
				array(
					'methods'             => \WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'save_data_lifecycle' ),
					'permission_callback' => static function () { return current_user_can( 'manage_voidpulse_settings' ); },
					'args'                => array( 'settings' => array( 'required' => true, 'type' => 'object' ) ),
				),
			)
		);
		register_rest_route(
			'voidpulse/v1',
			'/analytics/data',
			array(
				'methods'             => \WP_REST_Server::DELETABLE,
				'callback'            => array( $this, 'clear_analytics' ),
				'permission_callback' => static function () { return current_user_can( 'manage_voidpulse_settings' ); },
				'args'                => array( 'confirm' => array( 'required' => true, 'type' => 'boolean' ) ),
			)
		);
	}

	/**
	 * Campaign permission.
	 *
	 * @return bool
	 */
	public function can_edit() {
		return current_user_can( 'edit_voidpulse_campaigns' );
	}

	/**
	 * Return campaign/defaults.
	 *
	 * @return \WP_REST_Response
	 */
	public function get_campaign() {
		$campaign = ( new NotificationSettings() )->get();
		return rest_ensure_response( $campaign ?: CampaignSchema::defaults() );
	}

	/**
	 * Search published products and resolve selected product labels.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response
	 */
	public function products( $request ) {
		$search   = sanitize_text_field( $request->get_param( 'search' ) );
		$include  = array_slice( wp_parse_id_list( $request->get_param( 'include' ) ), 0, 100 );
		$products = array();
		foreach ( $include as $product_id ) {
			$product = wc_get_product( $product_id );
			if ( $product && $product->exists() && 'publish' === $product->get_status() ) {
				$products[ $product->get_id() ] = $product;
			}
		}
		if ( strlen( $search ) >= 2 ) {
			$data_store = \WC_Data_Store::load( 'product' );
			foreach ( $data_store->search_products( $search, '', true, false, 20 ) as $product_id ) {
				$product = wc_get_product( $product_id );
				if ( $product && $product->is_type( 'variation' ) ) {
					$product = wc_get_product( $product->get_parent_id() );
				}
				if ( $product && $product->exists() && 'publish' === $product->get_status() ) {
					$products[ $product->get_id() ] = $product;
				}
			}
		}
		$response = array();
		foreach ( $products as $product ) {
			$response[] = array(
				'id'   => absint( $product->get_id() ),
				'name' => sanitize_text_field( $product->get_name() ),
				'sku'  => sanitize_text_field( $product->get_sku() ),
			);
		}
		return rest_ensure_response( $response );
	}

	/**
	 * Save campaign and refresh on publication.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function save_campaign( $request ) {
		$campaign = CampaignSchema::strip_metadata( $request->get_param( 'campaign' ) );
		if ( isset( $campaign['status'] ) && 'active' === $campaign['status'] && ! current_user_can( 'publish_voidpulse_campaigns' ) ) {
			return new \WP_Error( 'voidpulse_forbidden_publish', __( 'You cannot publish campaigns.', 'voidpulse-social-proof-for-woocommerce' ), array( 'status' => 403 ) );
		}
		$validated = CampaignSchema::validate( $campaign );
		if ( is_wp_error( $validated ) ) {
			return $validated;
		}
		$settings = new NotificationSettings();
		$existing = $settings->get();
		$saved    = $settings->save( $validated, get_current_user_id() );
		if ( is_wp_error( $saved ) ) {
			return $saved;
		}
		if ( ! $existing ) {
			do_action( 'voidpulse_campaign_created' );
		}
		if ( 'active' === $validated['status'] ) {
			( new RecentSaleCollector() )->collect( $validated );
			do_action( 'voidpulse_campaign_published' );
		} elseif ( 'paused' === $validated['status'] ) {
			do_action( 'voidpulse_campaign_paused' );
		}
		return rest_ensure_response( array( 'campaign' => $settings->get() ) );
	}

	/**
	 * Return a versioned export envelope.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function export_campaign() {
		$campaign = ( new NotificationSettings() )->get();
		if ( ! $campaign ) {
			return new \WP_Error( 'voidpulse_no_campaign', __( 'No campaign is available to export.', 'voidpulse-social-proof-for-woocommerce' ), array( 'status' => 404 ) );
		}
		return rest_ensure_response(
			array(
				'schema'         => 'voidpulse-campaign',
				'schema_version' => 1,
				'plugin_version' => VOIDPULSE_VERSION,
				'campaign'       => CampaignSchema::strip_metadata( $campaign ),
			)
		);
	}

	/**
	 * Validate an import envelope and place it into the single draft slot.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function import_campaign( $request ) {
		$document = $request->get_param( 'document' );
		if ( strlen( wp_json_encode( $document ) ) > 1024 * 1024 ) {
			return new \WP_Error( 'voidpulse_import_too_large', __( 'Campaign imports are limited to 1 MB.', 'voidpulse-social-proof-for-woocommerce' ), array( 'status' => 413 ) );
		}
		$document_keys = is_array( $document ) ? array_keys( $document ) : array();
		sort( $document_keys );
		$expected_keys = array( 'campaign', 'plugin_version', 'schema', 'schema_version' );
		if ( ! is_array( $document ) || $document_keys !== $expected_keys ) {
			return new \WP_Error( 'voidpulse_import_schema', __( 'The import document has an invalid structure.', 'voidpulse-social-proof-for-woocommerce' ), array( 'status' => 400 ) );
		}
		if ( 'voidpulse-campaign' !== $document['schema'] || 1 !== absint( $document['schema_version'] ) || ! is_array( $document['campaign'] ) ) {
			return new \WP_Error( 'voidpulse_import_version', __( 'The campaign schema or version is unsupported.', 'voidpulse-social-proof-for-woocommerce' ), array( 'status' => 400 ) );
		}
		$document['campaign']           = CampaignSchema::strip_metadata( $document['campaign'] );
		$document['campaign']['status'] = 'draft';
		$validated = CampaignSchema::validate( $document['campaign'] );
		if ( is_wp_error( $validated ) ) {
			return $validated;
		}
		$saved = ( new NotificationSettings() )->save( $validated, get_current_user_id() );
		return is_wp_error( $saved ) ? $saved : rest_ensure_response( array( 'campaign' => ( new NotificationSettings() )->get() ) );
	}

	/**
	 * Return non-secret diagnostics.
	 *
	 * @return \WP_REST_Response
	 */
	public function diagnostics() {
		global $wpdb;
		$cached = wp_cache_get( 'voidpulse_diagnostics', 'voidpulse' );
		if ( is_array( $cached ) ) {
			return rest_ensure_response( $cached );
		}
		$table = $wpdb->prefix . 'voidpulse_events';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Plugin-owned event table; diagnostics are cached below.
		$count = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $table ) );
		$diagnostics = array(
			'event_cache_count' => $count,
			'last_refresh'      => absint( get_option( 'voidpulse_last_cache_refresh', 0 ) ),
			'next_refresh'      => ( new Jobs() )->next_refresh(),
			'schema_version'    => get_option( 'voidpulse_schema_version', '' ),
			'asset_version'     => VOIDPULSE_VERSION,
			'hpos_enabled'      => class_exists( '\Automattic\WooCommerce\Utilities\OrderUtil' ) ? \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() : false,
		);
		wp_cache_set( 'voidpulse_diagnostics', $diagnostics, 'voidpulse', 30 );
		return rest_ensure_response( $diagnostics );
	}

	/**
	 * Clear only cached safe events.
	 *
	 * @return \WP_REST_Response
	 */
	public function clear_cache() {
		global $wpdb;
		$table = $wpdb->prefix . 'voidpulse_events';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Explicit bounded admin maintenance write to a plugin-owned cache table.
		$wpdb->query( $wpdb->prepare( 'DELETE FROM %i', $table ) );
		wp_cache_delete( 'events_newest', 'voidpulse' );
		wp_cache_delete( 'events_random', 'voidpulse' );
		wp_cache_delete( 'voidpulse_diagnostics', 'voidpulse' );
		return rest_ensure_response( array( 'cleared' => true ) );
	}

	/**
	 * Restore missing background refresh and cleanup actions.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function repair_schedule() {
		$next = ( new Jobs() )->repair_schedule();
		wp_cache_delete( 'voidpulse_diagnostics', 'voidpulse' );
		if ( ! $next ) {
			return new \WP_Error( 'voidpulse_schedule_repair_failed', __( 'The background refresh could not be scheduled. Check whether cron is disabled for this site.', 'voidpulse-social-proof-for-woocommerce' ), array( 'status' => 500 ) );
		}
		return rest_ensure_response( array( 'repaired' => true, 'next_refresh' => $next ) );
	}

	/**
	 * Return lifecycle preferences and storage usage.
	 *
	 * @return \WP_REST_Response
	 */
	public function data_lifecycle() {
		return rest_ensure_response( ( new DataLifecycle() )->settings() );
	}

	/**
	 * Save lifecycle preferences.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response
	 */
	public function save_data_lifecycle( $request ) {
		return rest_ensure_response( ( new DataLifecycle() )->save( (array) $request['settings'] ) );
	}

	/**
	 * Clear analytics after an explicit confirmation.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function clear_analytics( $request ) {
		if ( true !== rest_sanitize_boolean( $request['confirm'] ) ) {
			return new \WP_Error( 'voidpulse_confirmation_required', __( 'Confirm analytics deletion before continuing.', 'voidpulse-social-proof-for-woocommerce' ), array( 'status' => 400 ) );
		}
		( new DataLifecycle() )->clear_analytics();
		wp_cache_delete( 'voidpulse_diagnostics', 'voidpulse' );
		return rest_ensure_response( array( 'cleared' => true ) );
	}
}
