<?php
/**
 * Newsroom Pro licensing via NewsOS.io (REST).
 *
 * Key format: NROS-XXXX-XXXX-XXXX (no I, O, 0, 1).
 * Subscription end date returned by API; Pro locks when expired.
 *
 * @package Newsroom_AI_Assistant
 */

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

if ( ! defined( 'NEWSAI_PRO_LICENSE_KEY_REGEX' ) ) {
	/** @var string Pattern aligned with NewsOS License API. */
	define( 'NEWSAI_PRO_LICENSE_KEY_REGEX', '/^NROS-[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4}$/' );
}

if ( ! function_exists( 'newsai_pro_license_api_url' ) ) {
	function newsai_pro_license_api_url() {
		$base = apply_filters( 'newsai_pro_license_api_base', 'https://newsos.io' );
		$base = untrailingslashit( (string) $base );

		return $base . '/wp-json/newsos/v1/license/validate';
	}
}

if ( ! function_exists( 'newsai_pro_product_slug' ) ) {
	function newsai_pro_product_slug() {
		return apply_filters( 'newsai_pro_product_slug', 'newsroom-os-pro' );
	}
}

if ( ! function_exists( 'newsai_pro_license_date_still_valid' ) ) {
	/**
	 * @param string $ymd Y-m-d UTC “paid through” date (inclusive).
	 */
	function newsai_pro_license_date_still_valid( $ymd ) {
		if ( ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', (string) $ymd ) ) {
			return false;
		}
		$today = gmdate( 'Y-m-d' );

		return (string) $ymd >= $today;
	}
}

if ( ! function_exists( 'newsai_is_pro' ) ) {
	/**
	 * Pro unlock (one plugin for all sites):
	 * 1) Default OFF — ON only after successful NewsOS license activation (valid + not past expires_at).
	 * 2) Optional: NEWSAI_PRO_BUILD true in wp-config (local/agency dev only; not for customer builds).
	 */
	function newsai_is_pro() {
		if ( defined( 'NEWSAI_PRO_BUILD' ) && NEWSAI_PRO_BUILD ) {
			return (bool) apply_filters( 'newsai_is_pro', true );
		}
		if ( get_option( 'newsai_pro_license_status', '' ) !== 'valid' ) {
			return (bool) apply_filters( 'newsai_is_pro', false );
		}
		$exp = (string) get_option( 'newsai_pro_license_expires_at', '' );
		if ( $exp !== '' && ! newsai_pro_license_date_still_valid( $exp ) ) {
			return (bool) apply_filters( 'newsai_is_pro', false );
		}

		return (bool) apply_filters( 'newsai_is_pro', true );
	}
}

if ( ! function_exists( 'newsai_pro_normalize_license_key' ) ) {
	function newsai_pro_normalize_license_key( $key ) {
		return strtoupper( preg_replace( '/\s+/', '', (string) $key ) );
	}
}

if ( ! function_exists( 'newsai_pro_license_key_valid_format' ) ) {
	function newsai_pro_license_key_valid_format( $key ) {
		$k = newsai_pro_normalize_license_key( $key );

		return (bool) preg_match( NEWSAI_PRO_LICENSE_KEY_REGEX, $k );
	}
}

if ( ! function_exists( 'newsai_pro_remote_request' ) ) {
	/**
	 * @param string $license_key Normalized key.
	 * @param string $action      activate|check|deactivate
	 * @param string $email       Optional customer email (activate / check).
	 * @return array{0:array|WP_Error,1:array}
	 */
	function newsai_pro_remote_request( $license_key, $action = 'check', $email = '' ) {
		$action = in_array( $action, [ 'activate', 'check', 'deactivate' ], true ) ? $action : 'check';
		$url    = newsai_pro_license_api_url();
		$body   = [
			'license_key'    => newsai_pro_normalize_license_key( $license_key ),
			'site_url'       => home_url( '/' ),
			'site_name'      => sanitize_text_field( (string) get_bloginfo( 'name' ) ),
			'product'        => newsai_pro_product_slug(),
			'action'         => $action,
			'version'        => defined( 'NEWSAI_VERSION' ) ? (string) NEWSAI_VERSION : '',
			'customer_email' => sanitize_email( (string) $email ),
		];

		$response = wp_remote_post(
			$url,
			[
				'timeout' => 15,
				'headers' => [
					'Content-Type' => 'application/json; charset=utf-8',
					'Accept'       => 'application/json',
				],
				'body'    => wp_json_encode( $body ),
			]
		);

		return [ $response, $body ];
	}
}

if ( ! function_exists( 'newsai_pro_parse_remote_response' ) ) {
	/**
	 * @return array{ok:bool, network:bool, message:string, expires_at:string, billing:string, api_code:string}
	 */
	function newsai_pro_parse_remote_response( $response ) {
		$empty = [
			'ok'         => false,
			'network'    => false,
			'message'    => '',
			'expires_at' => '',
			'billing'    => '',
			'api_code'   => '',
		];

		if ( is_wp_error( $response ) ) {
			$empty['network'] = true;
			$empty['message'] = $response->get_error_message();

			return $empty;
		}

		$code = (int) wp_remote_retrieve_response_code( $response );
		$raw  = (string) wp_remote_retrieve_body( $response );
		// Strip UTF-8 BOM + leading/trailing whitespace before decoding. Some servers
		// (especially WP plugins whose PHP source files were saved with BOM) prepend
		// a stray "\xEF\xBB\xBF" to every response, which makes `json_decode()` return
		// null and the activation silently fails with a generic "validation failed".
		$clean = preg_replace( '/^(?:\xEF\xBB\xBF|\s)+/', '', $raw );
		$data  = json_decode( (string) $clean, true );

		$expires  = '';
		$billing  = '';
		$api_code = '';
		if ( is_array( $data ) && ! empty( $data['code'] ) ) {
			$api_code = sanitize_key( (string) $data['code'] );
		}
		if ( is_array( $data ) && isset( $data['license'] ) && is_array( $data['license'] ) ) {
			if ( ! empty( $data['license']['expires_at'] ) ) {
				$expires = sanitize_text_field( (string) $data['license']['expires_at'] );
			}
			if ( ! empty( $data['license']['billing'] ) ) {
				$billing = sanitize_key( (string) $data['license']['billing'] );
			}
		}

		if ( $code >= 200 && $code < 300 && is_array( $data ) && ! empty( $data['success'] ) ) {
			return [
				'ok'         => true,
				'network'    => false,
				'message'    => '',
				'expires_at' => $expires,
				'billing'    => $billing,
				'api_code'   => '',
			];
		}

		$msg = is_array( $data ) && ! empty( $data['message'] ) ? (string) $data['message'] : '';
		if ( $msg === '' ) {
			// Server gave us a non-success response with no `message` field. Surface the
			// HTTP code + a body snippet so the admin can see whether the endpoint is
			// missing (404 / HTML), throwing a fatal (200 with empty body), or just
			// returning a poorly-shaped JSON. This is critical when the validation
			// host is misconfigured (e.g. wp-json route not registered).
			$snippet = trim( wp_strip_all_tags( $raw ) );
			if ( strlen( $snippet ) > 180 ) {
				$snippet = substr( $snippet, 0, 180 ) . '…';
			}
			$msg = sprintf(
				/* translators: 1: HTTP status code, 2: response body snippet. */
				__( 'License validation failed (HTTP %1$d). Server response: %2$s', 'newsroom-ai-assistant' ),
				$code,
				$snippet !== '' ? $snippet : __( '(empty body)', 'newsroom-ai-assistant' )
			);
		}
		if ( $api_code !== '' ) {
			$msg = $api_code . ': ' . $msg;
		}

		$empty['message']    = $msg;
		$empty['expires_at'] = $expires;
		$empty['billing']    = $billing;
		$empty['api_code']   = $api_code;

		return $empty;
	}
}

if ( ! function_exists( 'newsai_pro_persist_license_meta' ) ) {
	function newsai_pro_persist_license_meta( $expires_at, $billing = '' ) {
		if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', (string) $expires_at ) ) {
			update_option( 'newsai_pro_license_expires_at', (string) $expires_at, false );
		}
		if ( $billing !== '' ) {
			update_option( 'newsai_pro_license_billing', $billing, false );
		}
	}
}

if ( ! function_exists( 'newsai_pro_clear_license_meta' ) ) {
	function newsai_pro_clear_license_meta() {
		delete_option( 'newsai_pro_license_expires_at' );
		delete_option( 'newsai_pro_license_billing' );
	}
}

if ( ! function_exists( 'newsai_pro_activate_license' ) ) {
	/**
	 * @return array{success:bool, message:string}
	 */
	function newsai_pro_activate_license( $key, $email = '' ) {
		$key = newsai_pro_normalize_license_key( $key );
		if ( ! newsai_pro_license_key_valid_format( $key ) ) {
			return [
				'success' => false,
				'message' => __( 'Invalid key format. Use NROS-XXXX-XXXX-XXXX (no I, O, 0, or 1).', 'newsroom-ai-assistant' ),
			];
		}
		$email = sanitize_email( (string) $email );
		if ( ! is_email( $email ) ) {
			return [
				'success' => false,
				'message' => __( 'A valid billing email is required.', 'newsroom-ai-assistant' ),
			];
		}

		list( $response ) = newsai_pro_remote_request( $key, 'activate', $email );
		$parsed           = newsai_pro_parse_remote_response( $response );

		if ( ! empty( $parsed['network'] ) ) {
			return [ 'success' => false, 'message' => $parsed['message'] ];
		}

		if ( empty( $parsed['ok'] ) ) {
			update_option( 'newsai_pro_license_status', 'invalid', false );
			update_option( 'newsai_pro_license_last_error', sanitize_text_field( $parsed['message'] ), false );
			newsai_pro_clear_license_meta();

			return [ 'success' => false, 'message' => $parsed['message'] ];
		}

		if ( function_exists( 'newsai_secret_update_option' ) ) {
			newsai_secret_update_option( 'pro_license_key', $key );
		} else {
			update_option( 'newsai_pro_license_key', $key, false );
		}
		if ( $email !== '' ) {
			update_option( 'newsai_pro_license_email', sanitize_email( $email ), false );
		}
		update_option( 'newsai_pro_license_status', 'valid', false );
		update_option( 'newsai_pro_license_checked_at', time(), false );
		update_option( 'newsai_pro_license_registered_url', esc_url_raw( home_url( '/' ) ), false );
		delete_option( 'newsai_pro_license_last_error' );
		if ( $parsed['expires_at'] !== '' ) {
			newsai_pro_persist_license_meta( $parsed['expires_at'], $parsed['billing'] );
		}

		return [ 'success' => true, 'message' => '' ];
	}
}

if ( ! function_exists( 'newsai_pro_registered_site_url' ) ) {
	/**
	 * Site URL sent to NewsOS on last successful license bind (for admin display).
	 *
	 * @return string
	 */
	function newsai_pro_registered_site_url() {
		$stored = (string) get_option( 'newsai_pro_license_registered_url', '' );
		if ( $stored !== '' ) {
			return $stored;
		}

		return home_url( '/' );
	}
}

if ( ! function_exists( 'newsai_pro_deactivate_license' ) ) {
	function newsai_pro_deactivate_license() {
		$key = function_exists( 'newsai_secret_get' ) ? newsai_secret_get( 'pro_license_key' ) : (string) get_option( 'newsai_pro_license_key', '' );
		$em  = (string) get_option( 'newsai_pro_license_email', '' );
		if ( $key !== '' ) {
			newsai_pro_remote_request( $key, 'deactivate', $em );
		}
		if ( function_exists( 'newsai_secret_delete_option' ) ) {
			newsai_secret_delete_option( 'pro_license_key' );
		} else {
			delete_option( 'newsai_pro_license_key' );
		}
		delete_option( 'newsai_pro_license_email' );
		delete_option( 'newsai_pro_license_registered_url' );
		update_option( 'newsai_pro_license_status', 'invalid', false );
		delete_option( 'newsai_pro_license_last_error' );
		newsai_pro_clear_license_meta();
	}
}

if ( ! function_exists( 'newsai_pro_refresh_license' ) ) {
	/**
	 * @return array{success:bool, message:string}
	 */
	function newsai_pro_refresh_license() {
		$key = function_exists( 'newsai_secret_get' ) ? newsai_secret_get( 'pro_license_key' ) : (string) get_option( 'newsai_pro_license_key', '' );
		if ( $key === '' ) {
			return [ 'success' => false, 'message' => __( 'No license key saved.', 'newsroom-ai-assistant' ) ];
		}
		if ( ! newsai_pro_license_key_valid_format( $key ) ) {
			update_option( 'newsai_pro_license_status', 'invalid', false );
			newsai_pro_clear_license_meta();

			return [ 'success' => false, 'message' => __( 'Stored license key format is invalid.', 'newsroom-ai-assistant' ) ];
		}

		$em = (string) get_option( 'newsai_pro_license_email', '' );

		list( $response ) = newsai_pro_remote_request( $key, 'check', $em );
		$parsed           = newsai_pro_parse_remote_response( $response );

		if ( ! empty( $parsed['network'] ) ) {
			return [ 'success' => false, 'message' => $parsed['message'] ];
		}

		// Server has no URL registered for this key (cleared DB, URL drift, etc.) — re-run activate to bind this site.
		if ( empty( $parsed['ok'] ) && isset( $parsed['api_code'] ) && $parsed['api_code'] === 'not_activated' ) {
			list( $response ) = newsai_pro_remote_request( $key, 'activate', $em );
			$parsed          = newsai_pro_parse_remote_response( $response );
		}

		if ( empty( $parsed['ok'] ) ) {
			update_option( 'newsai_pro_license_status', 'invalid', false );
			update_option( 'newsai_pro_license_last_error', sanitize_text_field( $parsed['message'] ), false );
			newsai_pro_clear_license_meta();

			return [ 'success' => false, 'message' => $parsed['message'] ];
		}

		update_option( 'newsai_pro_license_status', 'valid', false );
		update_option( 'newsai_pro_license_checked_at', time(), false );
		update_option( 'newsai_pro_license_registered_url', esc_url_raw( home_url( '/' ) ), false );
		delete_option( 'newsai_pro_license_last_error' );
		if ( $parsed['expires_at'] !== '' ) {
			newsai_pro_persist_license_meta( $parsed['expires_at'], $parsed['billing'] );
		}

		return [ 'success' => true, 'message' => '' ];
	}
}

if ( ! function_exists( 'newsai_pro_cron_validate' ) ) {
	function newsai_pro_cron_validate() {
		if ( defined( 'NEWSAI_PRO_BUILD' ) && NEWSAI_PRO_BUILD ) {
			return;
		}
		if ( get_option( 'newsai_pro_license_status', '' ) !== 'valid' ) {
			return;
		}
		newsai_pro_refresh_license();
	}
}

add_action( 'newsai_pro_daily_license_check', 'newsai_pro_cron_validate' );

if ( ! function_exists( 'newsai_pro_schedule_license_cron' ) ) {
	function newsai_pro_schedule_license_cron() {
		if ( ! wp_next_scheduled( 'newsai_pro_daily_license_check' ) ) {
			wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'newsai_pro_daily_license_check' );
		}
	}
}
add_action( 'admin_init', 'newsai_pro_schedule_license_cron' );

if ( ! function_exists( 'newsai_pro_flash_license_message' ) ) {
	function newsai_pro_flash_license_message( $type, $message ) {
		set_transient(
			'nros_licf_' . get_current_user_id(),
			[
				'type'    => ( $type === 'error' ) ? 'error' : 'success',
				'message' => (string) $message,
			],
			300
		);
	}
}

if ( ! function_exists( 'newsai_pro_consume_license_flash_to_settings' ) ) {
	function newsai_pro_consume_license_flash_to_settings() {
		$k = 'nros_licf_' . get_current_user_id();
		$v = get_transient( $k );
		if ( ! is_array( $v ) || empty( $v['message'] ) ) {
			return;
		}
		delete_transient( $k );
		add_settings_error(
			'newsai_settings',
			'nros_license',
			esc_html( (string) $v['message'] ),
			( isset( $v['type'] ) && $v['type'] === 'error' ) ? 'error' : 'updated'
		);
	}
}

if ( ! function_exists( 'newsai_pro_promo_link' ) ) {
	/**
	 * Sales URL with UTM tracking. Filterable for reseller/white-label setups.
	 *
	 * @param string $source UTM source tag.
	 * @return string
	 */
	function newsai_pro_promo_link( $source = 'admin' ) {
		$base = (string) apply_filters( 'newsai_pro_buy_url_base', 'https://newsos.io/' );
		$url  = add_query_arg(
			[
				'utm_source'   => 'newsroom-os',
				'utm_medium'   => sanitize_key( $source ),
				'utm_campaign' => 'buy-pro',
			],
			$base
		);

		return (string) apply_filters( 'newsai_pro_buy_url', $url, $source );
	}
}

if ( ! function_exists( 'newsai_pro_promo_label' ) ) {
	/**
	 * Localized "Upgrade to Pro" label.
	 *
	 * @return string
	 */
	function newsai_pro_promo_label() {
		return __( 'Upgrade to Pro', 'newsroom-ai-assistant' );
	}
}

if ( ! function_exists( 'newsai_pro_promo_banner_dismissed' ) ) {
	function newsai_pro_promo_banner_dismissed() {
		$uid = (int) get_current_user_id();
		if ( $uid < 1 ) {
			return true;
		}
		$until = (int) get_user_meta( $uid, 'newsai_pro_promo_dismiss_until', true );
		return $until > time();
	}
}

if ( ! function_exists( 'newsai_pro_promo_banner_should_show' ) ) {
	/**
	 * Show the banner only on plugin pages or while editing posts, never on Pro sites
	 * and never if the user dismissed it in the last 30 days.
	 *
	 * @return bool
	 */
	function newsai_pro_promo_banner_should_show() {
		if ( ! is_admin() || ! is_user_logged_in() ) {
			return false;
		}
		if ( newsai_is_pro() ) {
			return false;
		}
		if ( newsai_pro_promo_banner_dismissed() ) {
			return false;
		}
		$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
		if ( ! $screen ) {
			return false;
		}
		if ( strpos( (string) $screen->id, 'newsai-settings' ) !== false ) {
			return true;
		}
		if ( in_array( $screen->base, [ 'post' ], true ) ) {
			return true;
		}
		return false;
	}
}

if ( ! function_exists( 'newsai_pro_render_promo_banner' ) ) {
	/**
	 * Compact, dismissible upgrade banner for plugin pages.
	 *
	 * @return void
	 */
	function newsai_pro_render_promo_banner() {
		if ( ! newsai_pro_promo_banner_should_show() ) {
			return;
		}
		$url   = newsai_pro_promo_link( 'admin-banner' );
		$nonce = wp_create_nonce( 'newsai_pro_promo_dismiss' );

		$title     = __( 'Unlock Newsroom OS Pro', 'newsroom-ai-assistant' );
		$desc      = __( 'Auto-Timeline, writer leaderboard, duplicate-tag guard and more — one NewsOS license per site unlocks every Pro feature.', 'newsroom-ai-assistant' );
		$cta_buy   = __( 'See Pro on NewsOS', 'newsroom-ai-assistant' );
		$cta_learn = __( 'I already have a license →', 'newsroom-ai-assistant' );
		$dismiss   = __( 'Not now', 'newsroom-ai-assistant' );
		$pro_url   = admin_url( 'admin.php?page=newsai-settings&tab=pro' );

		echo '<div class="notice newsai-pro-promo" data-nonce="' . esc_attr( $nonce ) . '" style="position:relative;padding:14px 44px 14px 16px;margin:12px 0;border-left:4px solid #6366f1;background:linear-gradient(135deg,#eef2ff 0%,#fdf2f8 100%);box-shadow:0 1px 0 rgba(0,0,0,.02);">';
		echo '<div style="display:flex;flex-wrap:wrap;align-items:center;gap:14px;">';
		echo '<div style="flex:0 0 auto;font-size:24px;line-height:1;">🚀</div>';
		echo '<div style="flex:1 1 240px;min-width:240px;">';
		echo '<strong style="font-size:14px;color:#3730a3;">' . esc_html( $title ) . '</strong>';
		echo '<div style="color:#3f3f46;margin-top:2px;font-size:13px;">' . esc_html( $desc ) . '</div>';
		echo '</div>';
		echo '<div style="flex:0 0 auto;display:flex;gap:8px;flex-wrap:wrap;">';
		echo '<a href="' . esc_url( $url ) . '" target="_blank" rel="noopener" class="button button-primary" style="background:#6366f1;border-color:#6366f1;">' . esc_html( $cta_buy ) . '</a>';
		echo '<a href="' . esc_url( $pro_url ) . '" class="button">' . esc_html( $cta_learn ) . '</a>';
		echo '</div>';
		echo '</div>';
		echo '<button type="button" class="notice-dismiss newsai-pro-promo-dismiss" aria-label="' . esc_attr( $dismiss ) . '"><span class="screen-reader-text">' . esc_html( $dismiss ) . '</span></button>';
		echo '<script>(function(){var n=document.currentScript.parentNode;var b=n.querySelector(".newsai-pro-promo-dismiss");if(!b||!window.jQuery)return;b.addEventListener("click",function(){jQuery.post(ajaxurl,{action:"newsai_dismiss_pro_promo",nonce:n.dataset.nonce});n.style.display="none";});})();</script>';
		echo '</div>';
	}
}
add_action( 'admin_notices', 'newsai_pro_render_promo_banner' );

if ( ! function_exists( 'newsai_pro_ajax_dismiss_promo' ) ) {
	function newsai_pro_ajax_dismiss_promo() {
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'unauthorized' ], 403 );
		}
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'newsai_pro_promo_dismiss' ) ) {
			wp_send_json_error( [ 'message' => 'bad_nonce' ], 403 );
		}
		update_user_meta( get_current_user_id(), 'newsai_pro_promo_dismiss_until', time() + ( 30 * DAY_IN_SECONDS ) );
		wp_send_json_success();
	}
}
add_action( 'wp_ajax_newsai_dismiss_pro_promo', 'newsai_pro_ajax_dismiss_promo' );

if ( ! function_exists( 'newsai_pro_render_lock_card' ) ) {
	/**
	 * Inline Pro lock for a settings pane, AI sidebar, etc.
	 *
	 * @param string $feature_title Friendly feature name.
	 * @param string $why            Short explanation.
	 * @param string $source         UTM source tag for the link.
	 * @return void
	 */
	function newsai_pro_render_lock_card( $feature_title, $why = '', $source = 'feature-lock' ) {
		$url       = newsai_pro_promo_link( $source );
		$pro_url   = admin_url( 'admin.php?page=newsai-settings&tab=pro' );
		$cta_buy   = __( 'Buy Pro on NewsOS', 'newsroom-ai-assistant' );
		$cta_have  = __( 'I have a license — Activate', 'newsroom-ai-assistant' );
		$badge     = __( 'Available in Pro', 'newsroom-ai-assistant' );

		echo '<div class="newsai-pro-lock" style="padding:18px 20px;border:1px solid #c7d2fe;background:linear-gradient(135deg,#f5f3ff 0%,#fdf2f8 100%);border-radius:8px;">';
		echo '<div style="display:inline-block;padding:2px 10px;border-radius:999px;background:#e0e7ff;color:#3730a3;font-weight:600;font-size:11px;letter-spacing:.04em;text-transform:uppercase;">🔒 ' . esc_html( $badge ) . '</div>';
		echo '<h3 style="margin:10px 0 4px 0;color:#1f2937;">' . esc_html( (string) $feature_title ) . '</h3>';
		if ( $why !== '' ) {
			echo '<p style="margin:0 0 14px 0;color:#4b5563;">' . esc_html( (string) $why ) . '</p>';
		}
		echo '<p style="margin:0;display:flex;flex-wrap:wrap;gap:8px;">';
		echo '<a href="' . esc_url( $url ) . '" target="_blank" rel="noopener" class="button button-primary" style="background:#6366f1;border-color:#6366f1;">' . esc_html( $cta_buy ) . '</a>';
		echo '<a href="' . esc_url( $pro_url ) . '" class="button">' . esc_html( $cta_have ) . '</a>';
		echo '</p>';
		echo '</div>';
	}
}
