<?php

namespace Ugcify\License;

defined( 'ABSPATH' ) || exit;

/**
 * Handles license activation, deactivation, and remote validation via EDD Software Licensing.
 *
 * Uses the Easy Digital Downloads (EDD) Software Licensing API. The plugin
 * first tries the primary EDD store URL, falling back to the secondary URL
 * when the primary is unavailable.
 *
 * WP Options managed here:
 *   ugcify_pro_license_key    — raw key string
 *   ugcify_pro_license_status — 'active' | 'deactivate'
 *   ugcify_pro_is_premium     — 'yes' | 'no'
 *   ugcify_pro_license_data   — array (key, last_check, start_date, end_date, plan, status)
 *   ugcify_pro_license_plan   — plan slug returned by the license server
 *
 * @since 1.0.0
 * @package Ugcify\License
 */
class Licensing {

	/**
	 * Singleton instance.
	 *
	 * @var Licensing
	 */
	private static $instance;

	/**
	 * Get the singleton instance.
	 *
	 * @return Licensing
	 */
	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Whether a local development license override is enabled.
	 *
	 * Opt-in via wp-config.php using:
	 * - UGCIFY_DEV_LICENSE_OVERRIDE => true
	 * - UGCIFY_DEV_LICENSE_PLAN     => 'growth' | 'pro' | 'business'
	 *
	 * @return bool
	 */
	public static function is_dev_override_enabled() {
		if ( ! \defined( 'UGCIFY_DEV_LICENSE_OVERRIDE' ) ) {
			return false;
		}

		$value = \constant( 'UGCIFY_DEV_LICENSE_OVERRIDE' );

		if ( \is_bool( $value ) ) {
			return $value;
		}

		if ( ! \is_scalar( $value ) ) {
			return false;
		}

		return \in_array( \strtolower( (string) $value ), array( '1', 'true', 'yes', 'on' ), true );
	}

	/**
	 * Get the local override plan.
	 *
	 * @return string
	 */
	private static function get_dev_override_plan() {
		$plan = \defined( 'UGCIFY_DEV_LICENSE_PLAN' )
			? \sanitize_key( (string) \constant( 'UGCIFY_DEV_LICENSE_PLAN' ) )
			: 'business';

		return \in_array( $plan, array( 'growth', 'pro', 'business' ), true ) ? $plan : 'business';
	}

	/**
	 * Resolve a local development license key to its simulated plan.
	 *
	 * @param string $license_key Raw license key.
	 * @return string Empty string when the key is not recognised.
	 */
	private static function get_local_plan_for_key( $license_key ) {
		$key_plan_map = array(
			'8zM2vLpQ9n5Xk1RwT7b6Yj4GfD3sHv' => 'growth',
			'YR27aZqIBXfsmmMNd8uBuKcnRc5I6H' => 'pro',
			'6y3MFl2DihJU5avqQmYrbpnjDwZgzs' => 'business',
		);

		return isset( $key_plan_map[ $license_key ] ) ? $key_plan_map[ $license_key ] : '';
	}

	/**
	 * Whether the current WordPress site is running in a local/development environment.
	 *
	 * @return bool
	 */
	private static function is_local_environment() {
		return false;
		if( self::is_beta_environment() ) {
			return true;
		}

		$environment = \defined( 'WP_ENVIRONMENT_TYPE' )
			? \constant( 'WP_ENVIRONMENT_TYPE' )
			: ( \function_exists( 'wp_get_environment_type' ) ? \wp_get_environment_type() : 'production' );

		if ( 'local' === $environment ) {
			return true;
		}

		$site_url = \function_exists( 'home_url' ) ? \home_url() : '';
		$host     = $site_url ? (string) \wp_parse_url( $site_url, PHP_URL_HOST ) : '';

		if ( empty( $host ) && \defined( 'UGCIFY_INSTANCE' ) ) {
			$host = (string) \wp_parse_url( 'http://' . \constant( 'UGCIFY_INSTANCE' ), PHP_URL_HOST );
		}

		if ( empty( $host ) ) {
			return false;
		}

		$host = \strtolower( $host );

		if ( \in_array( $host, array( 'localhost', '127.0.0.1', '::1' ), true ) ) {
			return true;
		}

		foreach ( array( '.local', '.test', '.localhost', '.invalid' ) as $suffix ) {
			if ( \strlen( $host ) >= \strlen( $suffix ) && 0 === \substr_compare( $host, $suffix, -\strlen( $suffix ) ) ) {
				return true;
			}
		}

		if ( 1 === \preg_match( '/^(10\.|127\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.)/', $host ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Whether the current environment is the beta testing environment.
	 *
	 * @return bool
	 */
	private static function is_beta_environment() {
		return false;
	}

	/**
	 * Make an EDD Software Licensing API request.
	 *
	 * Tries the primary EDD store first; falls back to the backup URL.
	 *
	 * @param string $action     EDD action (activate_license, deactivate_license, check_license).
	 * @param string $license_key Raw license key.
	 * @return object|null Decoded JSON response object, or null on failure.
	 */
	private function edd_license_api( $action, $license_key ) {
		$api_params = array(
			'edd_action' => $action,
			'license'    => $license_key,
			'item_id'    => UGCIFY_EDD_ITEM_ID,
			'url'        => home_url(),
			'source'     => 'rextheme',
		);

		$request_args = array(
			'timeout'   => 15,
			'sslverify' => false,
		);

		$primary_response = wp_remote_get(
			UGCIFY_EDD_STORE_URL . '?' . http_build_query( $api_params ),
			$request_args
		);

		if ( ! is_wp_error( $primary_response ) && 200 === (int) wp_remote_retrieve_response_code( $primary_response ) ) {
			$data = json_decode( wp_remote_retrieve_body( $primary_response ) );
			if ( null !== $data ) {
				return $data;
			}
		}

		$backup_response = wp_remote_get(
			UGCIFY_EDD_LICENSE_URL . '?' . http_build_query( $api_params ),
			$request_args
		);

		if ( ! is_wp_error( $backup_response ) && 200 === (int) wp_remote_retrieve_response_code( $backup_response ) ) {
			$data = json_decode( wp_remote_retrieve_body( $backup_response ) );
			if ( null !== $data ) {
				return $data;
			}
		}

		return null;
	}

	/**
	 * Determine the ugcify plan tier from an EDD license API response.
	 *
	 * Checks price_id first (filterable map), then falls back to item_name parsing.
	 * Default plan is 'growth' when no signal is found.
	 *
	 * @param object $license_data EDD API response object.
	 * @return string Plan slug: 'growth' | 'pro' | 'business'.
	 */
	private function determine_plan_from_edd_response( $license_data ) {
		$price_id_map = apply_filters(
			'ugcify_edd_price_id_plan_map',
			array(
				'1' => 'growth-lifetime',
				'2' => 'pro-lifetime',
				'3' => 'business-lifetime',
				'4' => 'growth-annual',
				'5' => 'pro-annual',
				'6' => 'business-annual',
			)
		);

		if ( isset( $license_data->price_id ) && isset( $price_id_map[ (string) $license_data->price_id ] ) ) {
			return $price_id_map[ (string) $license_data->price_id ];
		}

		if ( ! empty( $license_data->item_name ) ) {
			$name = strtolower( (string) $license_data->item_name );
			if ( false !== strpos( $name, 'business' ) ) {
				return 'business';
			}
			if ( false !== strpos( $name, 'pro' ) ) {
				return 'pro';
			}
			if ( false !== strpos( $name, 'growth' ) ) {
				return 'growth';
			}
		}

		return 'growth';
	}

	/**
	 * Return a user-facing error message for an EDD error code.
	 *
	 * @param string $error_code EDD error code from the license response.
	 * @return string
	 */
	private function get_edd_error_message( $error_code ) {
		switch ( $error_code ) {
			case 'expired':
				return __( 'Your license key has expired. Please renew your license.', 'ugcify' );
			case 'revoked':
				return __( 'Your license key has been disabled. Please contact support.', 'ugcify' );
			case 'missing':
				return __( 'Invalid license key. Please check your license and try again.', 'ugcify' );
			case 'invalid':
			case 'site_inactive':
				return __( 'Your license is not active for this URL.', 'ugcify' );
			case 'item_name_mismatch':
				return __( 'This license key does not belong to UGCify. Please use the correct license key.', 'ugcify' );
			case 'no_activations_left':
				return __( 'Your license key has reached its activation limit.', 'ugcify' );
			case 'license_not_activable':
				return __( 'This is a bundle license key. Please use your individual product license key.', 'ugcify' );
			default:
				return __( 'License activation failed. Please try again or contact support.', 'ugcify' );
		}
	}

	/**
	 * Persist a simulated license state for local development.
	 *
	 * @param string $operation_name 'activate' | 'deactivate'
	 * @param string $license_key    Raw license key.
	 * @return array
	 */
	private function process_local_license_operation( $operation_name, $license_key ) {
		if ( 'deactivate' === $operation_name ) {
			$license_data = $this->clear_license_data();
			do_action( 'ugcify_pro_license_deactivated', $license_data );

			return array(
				'success' => true,
				'message' => __( 'Local development license deactivated.', 'ugcify' ),
				'status'  => 'deactivate',
				'data'    => $license_data,
			);
		}
		
		if ( self::is_local_environment() )  {
			$plan = self::get_local_plan_for_key( $license_key );
			if ( empty( $plan ) ) {
				return array(
					'success' => false,
					'message' => __( 'Invalid local development license key.', 'ugcify' ),
					'status'  => 'deactivate',
					'data'    => array(),
				);
			}
		}
		

		$license_data = array(
			'key'             => $license_key,
			'last_check'      => time(),
			'start_date'      => gmdate( 'Y-m-d' ),
			'end_date'        => '',
			'plan'            => $plan,
			'status'          => 'active',
			'is_dev_override' => true,
		);

		update_option( 'ugcify_pro_license_key', $license_key );
		update_option( 'ugcify_pro_license_data', $license_data );
		update_option( 'ugcify_pro_is_premium', 'yes' );
		update_option( 'ugcify_pro_license_status', 'active' );
		update_option( 'ugcify_pro_license_plan', $license_data['plan'] );

		do_action( 'ugcify_pro_license_activated', $license_data );

		return array(
			'success' => true,
			'message' => sprintf(
				/* translators: %s: simulated plan slug. */
				__( 'Local development license activated for the %s tier without contacting the license server.', 'ugcify' ),
				$plan
			),
			'status'  => 'active',
			'data'    => $license_data,
		);
	}

	/**
	 * Get the effective license state from stored options.
	 *
	 * @return array
	 */
	private static function get_effective_license_state() {
		if ( self::is_dev_override_enabled() ) {
			$license_key = \defined( 'UGCIFY_DEV_LICENSE_KEY' )
				? \sanitize_text_field( (string) \constant( 'UGCIFY_DEV_LICENSE_KEY' ) )
				: '';

			return array(
				'key'        => $license_key,
				'status'     => 'active',
				'is_premium' => true,
				'data'       => array(
					'key'             => $license_key,
					'last_check'      => \time(),
					'start_date'      => '',
					'end_date'        => '',
					'plan'            => self::get_dev_override_plan(),
					'status'          => 'active',
					'is_dev_override' => true,
				),
			);
		}

		return array(
			'key'        => \get_option( 'ugcify_pro_license_key', '' ),
			'status'     => \get_option( 'ugcify_pro_license_status', 'deactivate' ),
			'is_premium' => 'yes' === \get_option( 'ugcify_pro_is_premium', 'no' ),
			'data'       => \get_option( 'ugcify_pro_license_data', array() ),
		);
	}

	/**
	 * Get the effective stored license status.
	 *
	 * @return string
	 */
	public static function get_license_status() {
		$state = self::get_effective_license_state();
		return $state['status'];
	}

	/**
	 * Whether the effective license state is premium.
	 *
	 * @return bool
	 */
	public static function is_premium() {
		$state = self::get_effective_license_state();
		return $state['is_premium'];
	}

	// -------------------------------------------------------------------------
	// Static read helpers
	// -------------------------------------------------------------------------

	/**
	 * Whether a valid, active license is present.
	 *
	 * Checks stored option values set during activation or the weekly cron revalidation.
	 *
	 * @return bool
	 */
	public static function is_license_valid() {
		if ( self::is_dev_override_enabled() ) {
			return true;
		}

		if ( self::is_local_environment() ) {
			$stored_key  = \get_option( 'ugcify_pro_license_key', '' );
			$stored_plan = self::get_local_plan_for_key( $stored_key );
			if ( ! empty( $stored_plan ) && 'active' === \get_option( 'ugcify_pro_license_status', '' ) ) {
				return true;
			}
		}

		return 'active' === \get_option( 'ugcify_pro_license_status', '' )
			&& 'yes' === \get_option( 'ugcify_pro_is_premium', 'no' );
	}

	/**
	 * Get stored license data array.
	 *
	 * @return array
	 */
	public static function get_license_data() {
		$state = self::get_effective_license_state();
		return $state['data'];
	}

	/**
	 * Get stored raw license key.
	 *
	 * @return string
	 */
	public static function get_license_key() {
		$state = self::get_effective_license_state();
		return $state['key'];
	}

	// -------------------------------------------------------------------------
	// Remote operations
	// -------------------------------------------------------------------------

	/**
	 * Perform a remote status-check against the EDD license server.
	 *
	 * @return bool True when the server reports the license as valid.
	 */
	public function remote_license_check() {
		if ( self::is_dev_override_enabled() ) {
			return true;
		}

		if ( self::is_local_environment() ) {
			return self::is_license_valid();
		}

		$license_key = self::get_license_key();
		if ( empty( $license_key ) ) {
			return false;
		}

		$license_data = $this->edd_license_api( 'check_license', $license_key );

		if ( null === $license_data ) {
			return false;
		}

		return isset( $license_data->license ) && 'valid' === $license_data->license;
	}

	/**
	 * Perform an activate or deactivate operation against the EDD license server
	 * and persist the resulting state in wp_options.
	 *
	 * @param string $operation_name 'activate' | 'deactivate'
	 * @param string $license_key    Raw license key (required for activation).
	 * @return array {
	 *     @type bool   $success
	 *     @type string $message
	 *     @type string $status  'active' | 'deactivate'
	 *     @type array  $data    License data array (may be empty on failure).
	 * }
	 */
	public function process_license_operation( $operation_name = 'activate', $license_key = '' ) {
		if ( empty( $license_key ) && 'activate' === $operation_name ) {
			return array(
				'success' => false,
				'message' => __( 'License key is required.', 'ugcify' ),
			);
		}

		if ( self::is_local_environment() ) {
			return $this->process_local_license_operation( $operation_name, $license_key );
		}

		if ( self::is_dev_override_enabled() ) {
			$message = 'deactivate' === $operation_name
				? __( 'Development license override is enabled. Disable UGCIFY_DEV_LICENSE_OVERRIDE to deactivate locally.', 'ugcify' )
				: __( 'Development license override is enabled for this local environment.', 'ugcify' );

			return array(
				'success' => true,
				'message' => $message,
				'status'  => self::get_license_status(),
				'data'    => self::get_license_data(),
			);
		}

		// If the key contains asterisks it is the masked display form — resolve it.
		if ( strpos( $license_key, '*' ) !== false ) {
			$stored_license  = get_option( 'ugcify_pro_license_key', '' );
			$decrypt_license = ProFunctions::decrypt_key( $license_key );
			if ( $stored_license === $decrypt_license ) {
				$license_key = $stored_license;
			}
		}

		$edd_action = 'activate' === $operation_name ? 'activate_license' : 'deactivate_license';
		$license_data = $this->edd_license_api( $edd_action, $license_key );

		if ( null === $license_data ) {
			return array(
				'success' => false,
				'message' => __( 'An error occurred communicating with the license server. Please try again.', 'ugcify' ),
			);
		}

		// ── Deactivation ───────────────────────────────────────────────────────
		if ( 'deactivate' === $operation_name ) {
			$stored_data = $this->clear_license_data();
			do_action( 'ugcify_pro_license_deactivated', $stored_data );

			$message = ( is_object( $license_data ) && isset( $license_data->success ) && $license_data->success )
				? __( 'License deactivated successfully.', 'ugcify' )
				: __( 'License has been deactivated.', 'ugcify' );

			return array(
				'success' => true,
				'message' => $message,
				'status'  => 'deactivate',
				'data'    => $stored_data,
			);
		}

		// ── Activation ─────────────────────────────────────────────────────────
		if ( false === $license_data->success ) {
			$error_code  = isset( $license_data->error ) ? (string) $license_data->error : '';
			$stored_data = $this->clear_license_data();
			do_action( 'ugcify_pro_license_deactivated', $stored_data );

			return array(
				'success' => false,
				'message' => $this->get_edd_error_message( $error_code ),
				'status'  => 'deactivate',
				'data'    => array(),
			);
		}

		if ( isset( $license_data->license ) && 'valid' === $license_data->license ) {
			$plan     = $this->determine_plan_from_edd_response( $license_data );
			$end_date = ( isset( $license_data->expires ) && 'lifetime' !== $license_data->expires )
				? $license_data->expires
				: '';

			$stored_data = array(
				'key'        => $license_key,
				'last_check' => time(),
				'start_date' => '',
				'end_date'   => $end_date,
				'plan'       => $plan,
				'status'     => 'active',
			);

			// Capture download_link / package from the EDD activation response if the
			// store's custom enhancer plugin injected them. This lets the Updater skip
			// the separate get_version API call and offer "Install Pro Build" immediately.
			$activation_download_url = '';
			if ( ! empty( $license_data->download_link ) ) {
				$activation_download_url      = esc_url_raw( $license_data->download_link );
				$stored_data['download_link'] = $activation_download_url;
			} elseif ( ! empty( $license_data->package ) ) {
				$activation_download_url      = esc_url_raw( $license_data->package );
				$stored_data['download_link'] = $activation_download_url;
			}

			update_option( 'ugcify_pro_license_key', $license_key );
			update_option( 'ugcify_pro_license_data', $stored_data );
			update_option( 'ugcify_pro_is_premium', 'yes' );
			update_option( 'ugcify_pro_license_status', 'active' );
			update_option( 'ugcify_pro_license_plan', $plan );

			// Persist the "needs pro install" flag so the undismissable notice shows on
			// every admin page until the pro ZIP is actually downloaded and installed.
			// Updater::on_upgrade_complete() clears this option after a successful install.
			\update_option( 'ugcify_needs_pro_install', true );

			// Store the download URL in its own option so Updater::check_update() can
			// always build the update-transient entry even when EDD's get_version API
			// is unreachable or returns no new_version field.
			if ( ! empty( $activation_download_url ) ) {
				\update_option( 'ugcify_pro_download_url', $activation_download_url );
			}

			do_action( 'ugcify_pro_license_activated', $stored_data );

			return array(
				'success' => true,
				'message' => __( 'License activated successfully.', 'ugcify' ),
				'status'  => 'active',
				'data'    => $stored_data,
			);
		}

		// License status is not 'valid' and success is not false — unexpected state.
		$stored_data = $this->clear_license_data();
		do_action( 'ugcify_pro_license_deactivated', $stored_data );

		return array(
			'success' => false,
			'message' => __( 'License activation failed. Please try again or contact support.', 'ugcify' ),
			'status'  => 'deactivate',
			'data'    => array(),
		);
	}

	// -------------------------------------------------------------------------
	// Cron revalidation
	// -------------------------------------------------------------------------

	/**
	 * Perform a remote license check and update stored state.
	 *
	 * Called weekly by LicenseCron. On success the last_check timestamp is updated.
	 * On failure the license status is reset to deactivate.
	 *
	 * @return void
	 */
	public static function run_remote_revalidation(): void {
		if ( self::is_dev_override_enabled() ) {
			return;
		}

		if ( self::is_local_environment() ) {
			return;
		}

		$license_key = self::get_license_key();

		if ( empty( $license_key ) ) {
			update_option( 'ugcify_pro_is_premium', 'no' );
			update_option( 'ugcify_pro_license_status', 'deactivate' );
			return;
		}

		$is_valid = ( new self() )->remote_license_check();

		if ( $is_valid ) {
			$license_data               = self::get_license_data();
			$license_data['last_check'] = time();
			update_option( 'ugcify_pro_license_data', $license_data );
		} else {
			update_option( 'ugcify_pro_is_premium', 'no' );
			update_option( 'ugcify_pro_license_status', 'deactivate' );
			do_action( 'ugcify_pro_license_deactivated', self::get_license_data() );
		}
	}

	// -------------------------------------------------------------------------
	// Internal helpers
	// -------------------------------------------------------------------------

	/**
	 * Reset all license-related WP options to their empty/inactive defaults.
	 *
	 * @return array Empty license data array.
	 */
	private function clear_license_data() {
		$license_data = array(
			'key'        => '',
			'last_check' => time(),
			'start_date' => '',
			'end_date'   => '',
			'plan'       => '',
			'status'     => 'deactivate',
		);

		update_option( 'ugcify_pro_license_key', '' );
		update_option( 'ugcify_pro_license_data', $license_data );
		update_option( 'ugcify_pro_is_premium', 'no' );
		update_option( 'ugcify_pro_license_status', 'deactivate' );
		update_option( 'ugcify_pro_license_plan', '' );

		return $license_data;
	}
}
