<?php

namespace The7\Admin\Notices;

use The7\Admin\Pages\Dashboard;

defined( 'ABSPATH' ) || exit;

/**
 * Version Update Notice.
 *
 * A dismissible admin notice shown on every admin screen except the dashboard, warning that this
 * line has not been tested against an upcoming WordPress release and pointing the user to the
 * dashboard to review their update options. Theme-authored fixed copy — not an Announcement,
 * carries no server message and runs no shortcode pipeline. See CONTEXT.md, "Version Update Notice".
 *
 * Note the mismatch between the class name and the copy, which is deliberate. The notice's job is
 * unchanged — nudge a v14 user toward the next line's update options — but on this line it argues
 * from WordPress compatibility rather than from availability, and `self::VERSION` remains the
 * project's next-major-line constant (read by the License Swap surfaces), so it is not renamed.
 * See docs/adr/0014-v14-compatibility-warning-notice.md.
 */
class Version_Update_Notice extends Abstract_Notice {

	/**
	 * Advertised major line. Hardcoded for now — a one-constant bump.
	 *
	 * Also read by the License Swap surfaces as the project's next-major-line constant, so it is
	 * never repurposed for anything else.
	 */
	const VERSION = '15';

	/**
	 * WordPress version this line has not been tested against.
	 *
	 * Deliberately a constant rather than a comparison against the site's running WordPress or the
	 * `Tested up to` header: the warning is issued *before* this version is released, so any
	 * conditional check would show it to nobody. A one-constant bump per WordPress major.
	 */
	const UNTESTED_WP_VERSION = '7.1';

	/**
	 * Dismissal code persisted in the7_dismissed_admin_notices.
	 */
	const CODE = 'the7_version_update_notice';

	public function render() {
		printf(
			'<p><strong>%1$s</strong> %2$s<br>%3$s</p>',
			esc_html__( 'Compatibility warning:', 'the7mk2' ),
			esc_html(
				sprintf(
					/* translators: %s: WordPress version, e.g. "7.1". */
					__( 'Your installed version of The7 has not been tested for compatibility with WordPress %s.', 'the7mk2' ),
					self::UNTESTED_WP_VERSION
				)
			),
			self::get_review_options_link() // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built from esc_url() and esc_html__().
		);
	}

	/**
	 * Headline advertising the available line, e.g. "The7 15 is available".
	 *
	 * The major is always supplied by the caller, so headline and offer cannot drift: a
	 * surface that knows which line is on offer passes that line's major.
	 *
	 * Not used by this notice, which carries its own compatibility copy. The remaining caller is
	 * the theme details "Update Available" box, which fires only on a genuinely pending cross-line
	 * offer and where advertising the offered line is the right sentence.
	 *
	 * @param int|string $major Major version being advertised.
	 *
	 * @return string
	 */
	public static function get_headline( $major ) {
		/* translators: %s: The7 major version. */
		return sprintf( __( 'The7 %s is available', 'the7mk2' ), $major );
	}

	/**
	 * The "Review your update options …" sentence with a dashboard link, pre-sanitized for output.
	 *
	 * Used by the theme details "Update Available" box. This notice links to the same destination
	 * but without the trailing clause — see get_review_options_link().
	 *
	 * The wp_kses_post() here covers the translated wrapper, which may carry markup from a
	 * translation file; the interpolated link is already escaped by construction.
	 *
	 * @return string
	 */
	public static function get_review_options_sentence() {
		return wp_kses_post(
			sprintf(
				/* translators: %s: "Review your update options" link. */
				__( '%s to keep receiving future security, compatibility, and feature updates.', 'the7mk2' ),
				self::get_review_options_link()
			)
		);
	}

	/**
	 * The bare "Review your update options" dashboard link.
	 *
	 * Fully escaped by construction — the href through esc_url() and the label through
	 * esc_html__() — so callers may echo it directly.
	 *
	 * @return string
	 */
	private static function get_review_options_link() {
		return sprintf(
			'<a href="%1$s">%2$s</a>',
			esc_url( admin_url( 'admin.php?page=the7-dashboard' ) ),
			esc_html__( 'Review your update options', 'the7mk2' )
		);
	}

	/**
	 * Visible to anyone who can act on the link, wherever the link is worth following.
	 *
	 * The dashboard is excluded because that is where the link leads — there is nothing to offer a
	 * reader who has already arrived. Registration is required: the call to action is to move onto
	 * the next line, which an unregistered install cannot act on. The capability is `update_themes`
	 * rather than `update_core` because the call to action is about the theme, not about WordPress.
	 *
	 * @return bool
	 */
	public function is_visible() {
		if ( Dashboard::is_current_screen() ) {
			return false;
		}

		return current_user_can( 'update_themes' ) && presscore_theme_is_activated();
	}

	public function get_code() {
		return self::CODE;
	}

	/**
	 * Dismissible warning chrome.
	 *
	 * Deliberately without DASHBOARD_NOTICE, so the notice is hidden by
	 * `#the7-dashboard > .notice:not(.the7-dashboard-notice)` on The7's own admin screens — the
	 * same treatment every other notice gets there.
	 *
	 * @return string
	 */
	public function get_wrapper_class() {
		return parent::get_wrapper_class() . ' ' . self::NOTICE_WARNING . ' ' . self::NOTICE_DISMISSIBLE;
	}

	/**
	 * Keep the notice re-notifying after a theme version change.
	 *
	 * Subscribed to `the7_installed_build_changed` outside the admin gate, because that
	 * announcement fires once and is very often first seen on a front-end request.
	 *
	 * Guarded because reset() writes unconditionally, and calling it blind would create an empty
	 * autoloaded option row on every install that has never dismissed anything.
	 *
	 * @return void
	 */
	public static function reset_on_build_change() {
		$notices = the7_admin_notices();
		if ( $notices->notice_is_dismissed( self::CODE ) ) {
			$notices->reset( self::CODE );
		}
	}
}
