<?php

namespace WPDRMS\ASP\Misc;

use Exception;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WPDRMS\PluginCore\Rest\AbstractRest;
use WPDRMS\Utils\Functions;
use WPDRMS\Utils\Server;

class UpdatesHelpRoute extends AbstractRest {
	public function registerRoutes( string $route_namespace ): void {
		register_rest_route(
			$route_namespace,
			'updates-help/status',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'getStatus' ),
				// Read-only: demo visitors are granted access via DemoMode's read filter.
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'updates-help/activate',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'activate' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'updates-help/deactivate',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'deactivate' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'updates-help/check',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'check' ),
				// Read-only: demo visitors are granted access via DemoMode's read filter.
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);
	}

	/**
	 * @return WP_Error|WP_REST_Response
	 */
	public function getStatus() {
		try {
			// isActivated() returns the raw license key (or false). Never put it on the wire:
			// expose only the activation state as booleans, and a masked key for real admins.
			$local  = PluginLicense::isActivated( false );
			$remote = PluginLicense::isActivated( true );
			$key    = $remote !== false ? $remote : $local;

			return new WP_REST_Response(
				array(
					'installed'          => ASP_CURR_VER_STRING,
					'latest'             => wd_asp()->updates->getVersionString(),
					'last_updated'       => wd_asp()->updates->getLastUpdated(),
					'locally_activated'  => $local !== false,
					'remotely_activated' => $remote !== false,
					// Admins only — withheld from demo/non-admin viewers entirely.
					'masked_key'         => ( $key !== false && current_user_can( 'manage_options' ) )
						? self::maskKey( (string) $key )
						: null,
					'environment'        => Server::getEnvironmentType(),
				),
				200
			);
		} catch ( Exception $e ) {
			return new WP_Error( 'asp_license_error', $e->getMessage(), array( 'status' => 500 ) );
		}
	}

	/**
	 * Masks a license key for display, revealing only the last 4 characters.
	 *
	 * @param string $key The raw license key.
	 * @return string
	 */
	private static function maskKey( string $key ): string {
		$visible = 4;
		if ( strlen( $key ) <= $visible ) {
			return str_repeat( '*', strlen( $key ) );
		}
		return str_repeat( '*', strlen( $key ) - $visible ) . substr( $key, -$visible );
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function activate( WP_REST_Request $request ) {
		if ( get_transient( '_asp_license_activate_throttle' ) ) {
			return new WP_Error( 'asp_license_error', 'Too many requests. Please wait before retrying.', array( 'status' => 429 ) );
		}

		try {
			$params = $request->get_json_params();
			$key    = isset( $params['key'] ) ? trim( (string) $params['key'] ) : '';

			if ( empty( $key ) || strlen( $key ) !== 36 || !Functions::uv($key) ) {
				return new WP_Error( 'asp_license_error', 'Invalid key format.', array( 'status' => 400 ) );
			}

			set_transient( '_asp_license_activate_throttle', 1, 3 );

			$result = PluginLicense::activate( $key );

			if ( $result === false ) {
				return new WP_Error( 'asp_license_error', 'Connection error, please try again.', array( 'status' => 503 ) );
			}

			if ( isset( $result['status'] ) && (int) $result['status'] !== 1 ) {
				$message = isset( $result['message'] ) ? (string) $result['message'] : 'Activation failed.';
				return new WP_Error( 'asp_license_error', $message, array( 'status' => 400 ) );
			}

			update_site_option( '_asp_la', $key );

			return new WP_REST_Response( $result, 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'asp_license_error', $e->getMessage(), array( 'status' => 500 ) );
		}
	}

	/**
	 * @return WP_Error|WP_REST_Response
	 */
	public function deactivate() {
		try {
			$result = PluginLicense::deactivate();

			if ( $result === false ) {
				return new WP_Error( 'asp_license_error', 'Connection error, please try again.', array( 'status' => 503 ) );
			}

			delete_site_option( '_asp_la' );

			if ( isset( $result['status'] ) && (int) $result['status'] !== 1 ) {
				$message = isset( $result['message'] ) ? (string) $result['message'] : 'Deactivation failed.';
				return new WP_Error( 'asp_license_error', $message, array( 'status' => 400 ) );
			}

			return new WP_REST_Response( $result, 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'asp_license_error', $e->getMessage(), array( 'status' => 500 ) );
		}
	}

	/**
	 * GET updates-help/check
	 *
	 * Always returns HTTP 200. message:"ok" means the modal should be shown;
	 * message:"1" means the license is valid.
	 *
	 * @return WP_REST_Response
	 */
	public function check(): WP_REST_Response {
		// Development/staging sites now activate too (into a development slot), so they are no
		// longer implicitly bypassed — only demo mode is. The `asp_license_check_bypass` filter
		// remains as an explicit escape hatch (e.g. for offline/air-gapped environments).
		if ( apply_filters( 'asp_license_check_bypass', (bool) ASP_DEMO ) ) {
			return new WP_REST_Response( array( 'message' => '1' ), 200 );
		}

		PluginLicense::syncSignature();

		if ( ! PluginLicense::isActivated() ) {
			return new WP_REST_Response( array( 'message' => 'ok' ), 200 );
		}

		if ( ! get_transient( '_asp_license_daily_check' ) ) {
			set_transient( '_asp_license_daily_check', 1, DAY_IN_SECONDS );
			if ( ! PluginLicense::isActivated( true ) ) {
				return new WP_REST_Response( array( 'message' => 'ok' ), 200 );
			}
		}

		$backup       = get_site_option( '_asp_la' );
		$backup_valid = $backup !== false && is_string( $backup ) && Functions::uv( $backup );

		if ( ! PluginLicense::getData() ) {
			if ( $backup_valid ) {
				return new WP_REST_Response( array( 'message' => '1' ), 200 );
			}
			return new WP_REST_Response( array( 'message' => 'ok' ), 200 );
		}

		if ( $backup !== false && ! $backup_valid ) {
			return new WP_REST_Response( array( 'message' => 'ok' ), 200 );
		}

		return new WP_REST_Response( array( 'message' => '1' ), 200 );
	}
}
