<?php
/**
 * License — activate a SureCart license key against the PressConduit relay.
 *
 * Posts {customer_id, site_url, plugin_token, license_key} to the relay's
 * /license/activate endpoint. The relay validates the key with SureCart, maps
 * the product to a plan, and binds it to this site's customer record so the
 * relay can gate premium features. The plugin just stores the result for
 * display; enforcement happens on the relay.
 */

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

class PCD_PC_License {

	const OPT_KEY    = 'pcd_pc_license_key';
	const OPT_PLAN   = 'pcd_pc_license_plan';
	const OPT_STATUS = 'pcd_pc_license_status';
	const OPT_ERROR  = 'pcd_pc_license_error';

	// Cache of the relay's account-status verdict (licensed|grandfathered|unlicensed).
	const STATUS_TRANSIENT = 'pcd_pc_account_status';

	/**
	 * Where the "View plans / purchase" links point. Filterable so it can be
	 * repointed without a code change.
	 */
	public static function purchase_url(): string {
		return (string) apply_filters( 'pcd_pc_purchase_url', 'https://pcdesignstx.com/pressconduit/' );
	}

	public static function key(): string {
		return (string) get_option( self::OPT_KEY, '' );
	}

	public static function plan(): string {
		return (string) get_option( self::OPT_PLAN, '' );
	}

	public static function status(): string {
		return (string) get_option( self::OPT_STATUS, '' );
	}

	public static function last_error(): string {
		return (string) get_option( self::OPT_ERROR, '' );
	}

	public static function is_active(): bool {
		return 'active' === self::status() && '' !== self::plan();
	}

	/**
	 * Send the key to the relay for validation + binding.
	 */
	public static function activate( string $key ): bool {
		$key     = trim( $key );
		$backend = PCD_PC_Pair::backend_url();

		if ( ! $backend ) {
			update_option( self::OPT_ERROR, __( 'Backend URL is not set.', 'pressconduit' ) );
			return false;
		}
		if ( ! PCD_PC_Pair::is_paired() ) {
			update_option( self::OPT_ERROR, __( 'Connect this site on the Connection tab first, then activate your license.', 'pressconduit' ) );
			return false;
		}
		if ( '' === $key ) {
			update_option( self::OPT_ERROR, __( 'Enter your license key.', 'pressconduit' ) );
			return false;
		}

		$response = wp_remote_post( $backend . '/license/activate', [
			'headers' => [ 'Content-Type' => 'application/json' ],
			'body'    => wp_json_encode( [
				'customer_id'  => PCD_PC_Pair::customer_id(),
				'site_url'     => site_url(),
				'plugin_token' => PCD_PC_Auth::get_token(),
				'license_key'  => $key,
			] ),
			'timeout' => 15,
		] );

		if ( is_wp_error( $response ) ) {
			update_option( self::OPT_ERROR, $response->get_error_message() );
			return false;
		}

		$body = json_decode( wp_remote_retrieve_body( $response ), true );
		if ( ! is_array( $body ) || empty( $body['activated'] ) ) {
			$reason = '';
			if ( is_array( $body ) ) {
				$reason = (string) ( $body['reason'] ?? $body['error'] ?? '' );
			}
			update_option( self::OPT_ERROR, self::reason_message( $reason ) );
			return false;
		}

		update_option( self::OPT_KEY, $key );
		update_option( self::OPT_PLAN, sanitize_text_field( (string) ( $body['plan'] ?? '' ) ) );
		update_option( self::OPT_STATUS, 'active' );
		delete_option( self::OPT_ERROR );
		delete_transient( self::STATUS_TRANSIENT );
		return true;
	}

	/**
	 * Clear local license state. (Does not revoke the SureCart license.)
	 */
	public static function deactivate(): void {
		delete_option( self::OPT_KEY );
		delete_option( self::OPT_PLAN );
		delete_option( self::OPT_STATUS );
		delete_option( self::OPT_ERROR );
		delete_transient( self::STATUS_TRANSIENT );
	}

	/**
	 * Ask the relay for this site's account status: licensed | grandfathered |
	 * unlicensed (+ plan, enforced). Cached 6h. Returns an array or null on any
	 * failure (caller treats null as "don't nag").
	 */
	public static function remote_status( bool $force = false ) {
		if ( ! $force ) {
			$cached = get_transient( self::STATUS_TRANSIENT );
			if ( is_array( $cached ) ) {
				return $cached;
			}
		}
		if ( ! class_exists( 'PCD_PC_Pair' ) || ! PCD_PC_Pair::is_paired() ) {
			return null;
		}
		$backend = PCD_PC_Pair::backend_url();
		if ( ! $backend ) {
			return null;
		}
		$response = wp_remote_post( $backend . '/license/status', [
			'headers' => [ 'Content-Type' => 'application/json' ],
			'body'    => wp_json_encode( [
				'customer_id'  => PCD_PC_Pair::customer_id(),
				'site_url'     => site_url(),
				'plugin_token' => PCD_PC_Auth::get_token(),
			] ),
			'timeout' => 12,
		] );
		if ( is_wp_error( $response ) ) {
			return null;
		}
		$code = (int) wp_remote_retrieve_response_code( $response );
		$body = json_decode( wp_remote_retrieve_body( $response ), true );
		if ( $code < 200 || $code >= 300 || ! is_array( $body ) || empty( $body['state'] ) ) {
			return null;
		}
		$status = [
			'state'    => sanitize_text_field( (string) $body['state'] ),
			'plan'     => sanitize_text_field( (string) ( $body['plan'] ?? '' ) ),
			'enforced' => ! empty( $body['enforced'] ),
		];
		set_transient( self::STATUS_TRANSIENT, $status, 6 * HOUR_IN_SECONDS );
		return $status;
	}

	/**
	 * Should we nudge this site to license? True ONLY when the relay says the
	 * site is genuinely unlicensed — never for grandfathered or licensed sites,
	 * and never on a relay hiccup (fail quiet).
	 */
	public static function needs_license(): bool {
		if ( self::is_active() ) {
			return false;
		}
		$status = self::remote_status();
		return is_array( $status ) && 'unlicensed' === $status['state'];
	}

	/**
	 * Turn a relay/SureCart failure reason into a friendly message.
	 */
	private static function reason_message( string $reason ): string {
		$map = [
			'invalid_key'        => __( 'That license key was not found. Check it against your SureCart receipt.', 'pressconduit' ),
			'license_revoked'    => __( 'This license is no longer active — the subscription may have been canceled or expired.', 'pressconduit' ),
			'no_api_token'       => __( 'License validation is not configured on the relay yet. Contact support.', 'pressconduit' ),
			'unauthorized'       => __( 'This site is not paired correctly. Re-pair on the Connection tab and try again.', 'pressconduit' ),
			'customer_not_found' => __( 'No pairing found for this site. Re-pair on the Connection tab and try again.', 'pressconduit' ),
			'missing_params'     => __( 'Missing pairing details. Re-pair on the Connection tab and try again.', 'pressconduit' ),
		];
		if ( isset( $map[ $reason ] ) ) {
			return $map[ $reason ];
		}
		/* translators: %s: failure reason returned by the relay. */
		return '' !== $reason
			? sprintf( __( 'Activation failed (%s).', 'pressconduit' ), $reason )
			: __( 'Activation failed. Please try again.', 'pressconduit' );
	}
}
