<?php
/**
 * Login Branding Module — "Aurora".
 *
 * Restyles the native WordPress login into a premium, on-brand dark
 * glassmorphism sign-in page (accent derived from the site palette, brand
 * removes public registration (the community is invite-only).
 *
 * It restyles WordPress's own login form rather than replacing it, so all
 * authentication, nonces, and error handling stay intact and secure.
 *
 * Lean by construction: the CSS and fonts load ONLY on wp-login.php, never
 * on the front end, so member browsing is completely unaffected.
 *
 * @package Platform\Helm\Modules\Login_Branding
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\Login_Branding;

use Platform\Helm\Contracts\ModuleInterface;
use Platform\Helm\Core\Authorization;

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

final class LoginBrandingModule implements ModuleInterface {

	public const OPTION      = 'platform_helm_login_branding';
	public const PAGE_SLUG   = 'platform-helm-login-branding';
	public const PARENT_SLUG = 'platform-helm';

	/**
	 * Example logo URL shown as the placeholder in the Logo URL field. Purely a
	 * hint — when the setting is left blank the login screen falls back to the
	 * site's Customizer logo (see resolve_logo()).
	 */
	public const DEFAULT_LOGO = 'https://example.com/logo.png';


	public function id(): string {
		return 'login_branding';
	}

	public function name(): string {
		return __( 'Login Branding', 'platform-helm' );
	}

	public function description(): string {
		return __( 'Premium "Aurora" login page (dark glassmorphism, brand logo, no public registration). Loads only on the login screen.', 'platform-helm' );
	}

	public function default_enabled(): bool {
		return false;
	}

	public function boot(): void {
		add_action( 'login_enqueue_scripts', [ $this, 'print_login_css' ] );
		add_filter( 'login_headerurl', [ $this, 'login_logo_url' ] );
		add_filter( 'login_headertext', [ $this, 'login_logo_text' ] );
		add_filter( 'login_display_language_dropdown', [ $this, 'language_dropdown' ] );
		add_filter( 'login_message', [ $this, 'login_message' ] );
		add_action( 'login_footer', [ $this, 'render_orbs' ] );
		add_action( 'login_init', [ $this, 'on_login_init' ] );

		add_action( 'admin_menu', [ $this, 'register_menu' ], 46 );
		add_action( 'admin_init', [ $this, 'maybe_save' ] );
	}

	/* ---------- settings ---------- */

	/**
	 * @return array{logo_url:string,accent:string,headline:string,subtext:string,hide_lang:bool,disable_register:bool}
	 */
	public static function settings(): array {
		$s = get_option( self::OPTION, [] );
		$s = is_array( $s ) ? $s : [];
		return [
			'logo_url'         => isset( $s['logo_url'] ) ? (string) $s['logo_url'] : '',
			'accent'           => isset( $s['accent'] ) && self::is_hex( (string) $s['accent'] ) ? (string) $s['accent'] : self::default_accent(),
			'headline'         => isset( $s['headline'] ) ? (string) $s['headline'] : __( 'Welcome back.', 'platform-helm' ),
			'subtext'          => isset( $s['subtext'] ) ? (string) $s['subtext'] : __( 'Sign in to access your dashboard and tools.', 'platform-helm' ),
			'hide_lang'        => isset( $s['hide_lang'] ) ? (bool) $s['hide_lang'] : true,
			'disable_register' => isset( $s['disable_register'] ) ? (bool) $s['disable_register'] : false,
		];
	}

	/**
	 * Default accent colour: derive from the current WordPress admin colour
	 * scheme (the closest thing WP exposes to a "site primary" colour), so the
	 * login page adopts the site's own palette out of the box. Falls back to
	 * the Helm brand blue.
	 */
	private static function default_accent(): string {
		global $_wp_admin_css_colors;
		$scheme = get_user_option( 'admin_color' );
		if ( $scheme && isset( $_wp_admin_css_colors[ $scheme ]->colors ) && is_array( $_wp_admin_css_colors[ $scheme ]->colors ) ) {
			// Use the most saturated/!default accent in the scheme (usually index 2 or 3).
			$colors = $_wp_admin_css_colors[ $scheme ]->colors;
			$pick   = $colors[2] ?? ( $colors[1] ?? ( $colors[0] ?? '' ) );
			if ( is_string( $pick ) && self::is_hex( $pick ) ) {
				return $pick;
			}
		}
		return '#0047AB'; // Helm brand blue.
	}

	private static function is_hex( string $v ): bool {
		return (bool) preg_match( '/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/', $v );
	}

	private function resolve_logo(): string {
		$s = self::settings();
		if ( '' !== $s['logo_url'] ) {
			return $s['logo_url'];
		}
		// Use the site's own custom logo (set in the Customizer). The login
		// background is dark, so a light/transparent logo works best; site
		// owners can upload a login-specific logo in the module settings.
		$custom = get_theme_mod( 'custom_logo' );
		if ( $custom ) {
			$url = wp_get_attachment_image_url( (int) $custom, 'full' );
			if ( $url ) {
				return $url;
			}
		}
		return '';
	}

	/* ---------- login screen ---------- */

	public function print_login_css(): void {
		$s      = self::settings();
		$accent = $s['accent'];
		$logo   = esc_url( $this->resolve_logo() );

		wp_enqueue_style(
			'platform-helm-login-fonts',
			'https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,600;12..96,700&family=DM+Sans:opsz,wght@9..40,400;9..40,500&display=swap',
			[],
			null
		);

		$mail_ico = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2390a4b0' stroke-width='1.7'%3E%3Cpath d='M4 6h16v12H4z'/%3E%3Cpath d='m4 7 8 6 8-6'/%3E%3C/svg%3E";
		$lock_ico = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2390a4b0' stroke-width='1.7'%3E%3Crect x='5' y='10' width='14' height='10' rx='2.2'/%3E%3Cpath d='M8 10V7a4 4 0 0 1 8 0v3'/%3E%3C/svg%3E";

		$css = "
		body.login{
			--accent:{$accent}; --accent-lite:#e2595f; --accent-glow:rgba(156,28,31,.5);
			font-family:'DM Sans',sans-serif;
			min-height:100vh; display:flex; align-items:center; justify-content:center;
			-webkit-font-smoothing:antialiased;
		}
		/* Force the dark backdrop even if the theme/BuddyBoss sets a light one. */
		html, html body.login{
			background:#061b26 !important;
			background-image:radial-gradient(120% 120% at 78% 8%,#123d52 0%,#0a2c3d 46%,#061b26 100%) !important;
			background-attachment:fixed !important;
		}
		.login .orb{position:fixed;border-radius:50%;filter:blur(70px);opacity:.5;z-index:0;pointer-events:none}
		.login .orb.a{width:520px;height:520px;background:radial-gradient(circle,#c0282e,transparent 68%);top:-160px;right:-120px;animation:tlo1 18s ease-in-out infinite}
		.login .orb.b{width:460px;height:460px;background:radial-gradient(circle,#1f6388,transparent 70%);bottom:-180px;left:-140px;animation:tlo2 22s ease-in-out infinite}
		.login .orb.c{width:300px;height:300px;background:radial-gradient(circle,#7a1518,transparent 72%);top:42%;left:60%;opacity:.3;animation:tlo1 26s ease-in-out infinite reverse}
		@keyframes tlo1{0%,100%{transform:translate(0,0)}50%{transform:translate(-46px,40px)}}
		@keyframes tlo2{0%,100%{transform:translate(0,0)}50%{transform:translate(50px,-36px)}}

		#login{
			position:relative;z-index:2;width:418px;max-width:calc(100vw - 40px);padding:40px 38px 26px;
			background:rgba(255,255,255,.055);border:1px solid rgba(255,255,255,.14);border-radius:24px;
			backdrop-filter:blur(26px) saturate(140%);-webkit-backdrop-filter:blur(26px) saturate(140%);
			box-shadow:0 30px 80px -28px rgba(0,0,0,.7),inset 0 1px 0 rgba(255,255,255,.08);
			animation:tlrise .8s cubic-bezier(.2,.8,.2,1) both;
		}
		@keyframes tlrise{from{opacity:0;transform:translateY(20px) scale(.98)}to{opacity:1;transform:none}}

		#login h1{margin:0 0 18px;text-align:center}
		#login h1 a{
			display:inline-block;
			background-image:url('{$logo}');background-size:contain;background-repeat:no-repeat;background-position:center center;
			width:240px;max-width:100%;height:52px;margin:0 auto;
			filter:drop-shadow(0 6px 18px rgba(0,0,0,.35));
		}
		.tl-head{margin:0 0 24px;text-align:center}
		.tl-head h2{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:26px;letter-spacing:-.025em;color:#f4f6ff;margin:0 0 6px;line-height:1.14}
		.tl-head p{color:rgba(232,236,255,.62);font-size:14.5px;margin:0;line-height:1.5}

		#loginform{background:transparent;border:none;box-shadow:none;padding:0;margin:0;overflow:visible}
		body.login #loginform input[type=text],
		body.login #loginform input[type=email],
		body.login #loginform input[type=password],
		body.login #loginform .input{
			width:100% !important;height:50px !important;box-sizing:border-box !important;
			border-radius:13px;border:1px solid rgba(255,255,255,.12);
			background-color:rgba(255,255,255,.045);background-repeat:no-repeat;background-position:14px center;background-size:18px;
			color:#f4f6ff !important;font-family:'DM Sans',sans-serif !important;
			font-size:15px !important;font-weight:400 !important;line-height:normal !important;text-indent:0 !important;
			margin:2px 0 6px;padding:0 16px 0 44px !important;box-shadow:none;
			transition:border-color .2s,box-shadow .2s,background-color .2s;
		}
		body.login #loginform input#user_login{background-image:url(\"{$mail_ico}\")}
		body.login #loginform input#user_pass{background-image:url(\"{$lock_ico}\");padding-right:46px !important}
		body.login #loginform input::placeholder{color:rgba(232,236,255,.42) !important;font-size:15px !important;font-weight:400 !important;line-height:normal !important;opacity:1 !important}
		body.login #loginform input::-webkit-input-placeholder{font-size:15px !important;line-height:normal !important}
		body.login #loginform input::-moz-placeholder{font-size:15px !important;line-height:normal !important;opacity:1}
		body.login #loginform input:focus{border-color:var(--accent) !important;background-color:rgba(255,255,255,.07);box-shadow:0 0 0 4px var(--accent-glow);outline:none}
		.login label{color:rgba(232,236,255,.62);font-size:12.5px;font-weight:500;letter-spacing:.02em}
		/* Field titles duplicate the placeholders — hide visually, keep for screen readers. */
		body.login #loginform label[for='user_login'],
		body.login #loginform label[for='user_pass']{
			position:absolute !important;width:1px;height:1px;padding:0;margin:-1px;
			overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
		}

		.login .wp-pwd{position:relative}
		.login .wp-pwd .button.wp-hide-pw{
			position:absolute;right:6px;top:9px;height:34px;width:34px;background:transparent;border:none;
			color:rgba(232,236,255,.5);box-shadow:none;border-radius:9px;
		}
		.login .wp-pwd .button.wp-hide-pw:hover{color:#fff;background:rgba(255,255,255,.06)}

		.login .forgetmenot{margin:6px 0 20px}
		.login .forgetmenot label{color:rgba(232,236,255,.62);font-size:13.5px}
		.login input[type=checkbox]{accent-color:var(--accent);width:18px;height:18px}

		.login .submit{margin:0}
		.login #wp-submit,.wp-core-ui .login .button-primary{
			width:100%;height:52px;border:none;border-radius:13px;cursor:pointer;float:none;
			font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:15.5px;color:#fff;
			background:linear-gradient(135deg,#b8242a,var(--accent));
			box-shadow:0 14px 34px -12px var(--accent-glow);text-shadow:none;
			transition:transform .15s,box-shadow .2s,filter .2s;
		}
		.login #wp-submit:hover{filter:brightness(1.08);transform:translateY(-1px);box-shadow:0 18px 42px -12px var(--accent-glow)}

		#nav,#backtoblog{text-align:center;padding:0;margin:18px 0 0;text-shadow:none}
		#nav{border-top:1px solid rgba(255,255,255,.14);padding-top:18px}
		#nav a,#backtoblog a{color:#ffffff;transition:color .2s}
		#nav a:hover,#backtoblog a:hover{color:var(--accent-lite)}
		/* Privacy policy + any other footer links: white for contrast on dark. */
		.login .privacy-policy-page-link a,.login .privacy-policy-link,body.login .privacy-policy-page-link a{color:#ffffff !important}
		.login .privacy-policy-page-link a:hover,.login .privacy-policy-link:hover{color:var(--accent-lite) !important}
		#nav{visibility:visible}

		@media(max-width:480px){#login{padding:30px 22px 22px;border-radius:18px}.tl-head h2{font-size:23px}}

		#login_error,.login .message,.login .notice{
			border-radius:11px;border-left:none;padding:11px 14px;font-size:13px;
			background:rgba(255,141,141,.1);border:1px solid rgba(255,141,141,.25);color:#ff8d8d;box-shadow:none;
		}
		.login .message,.login .notice{background:rgba(123,224,168,.1);border-color:rgba(123,224,168,.25);color:#7be0a8}
		.login #login_error a,.login .message a{color:inherit}
		";

		echo '<style id="platform-helm-login-aurora">' . $css . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}

	/** Decorative background orbs (position:fixed, so footer placement is fine). */
	public function render_orbs(): void {
		echo '<div class="orb a"></div><div class="orb b"></div><div class="orb c"></div>';
	}

	public function login_logo_url( $url ) {
		return home_url( '/' );
	}

	public function login_logo_text( $text ) {
		return get_bloginfo( 'name' );
	}

	public function language_dropdown( $display ) {
		return self::settings()['hide_lang'] ? false : (bool) $display;
	}

	/** Inject the headline/subtext above the form on the main login screen. */
	public function login_message( $message ) {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$action = isset( $_GET['action'] ) ? sanitize_key( wp_unslash( $_GET['action'] ) ) : 'login';
		if ( 'login' !== $action ) {
			return $message;
		}
		$s = self::settings();
		$head = '<div class="tl-head">'
			. '<h2>' . esc_html( $s['headline'] ) . '</h2>'
			. ( '' !== trim( (string) $s['subtext'] ) ? '<p>' . esc_html( $s['subtext'] ) . '</p>' : '' )
			. '</div>';
		return $head . $message;
	}

	/** Login-screen init: block public registration + suppress ad leaks. */
	public function on_login_init(): void {
		$s = self::settings();

		if ( $s['disable_register'] ) {
			// Turn registration off for the login-page render: WordPress only
			// prints the "Register" nav link when this option is on, so this
			// removes it at the source (CSS is a backup). Scoped to the login
			// request only — your invite/MemberPress flow is untouched.
			add_filter( 'pre_option_users_can_register', '__return_zero' );

			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$action = isset( $_GET['action'] ) ? sanitize_key( wp_unslash( $_GET['action'] ) ) : '';
			if ( 'register' === $action ) {
				wp_safe_redirect( wp_login_url() );
				exit;
			}
		}

		// Best-effort: keep Advanced Ads banners off the sign-in screen.
		if ( class_exists( '\Advanced_Ads' ) || function_exists( 'advads_ad' ) ) {
			add_filter( 'advanced-ads-can-display', '__return_false', 999 );
		}
	}

	/* ---------- settings page ---------- */

	public function register_menu(): void {
		if ( ! Authorization::is_master_admin() ) {
			return;
		}
		add_submenu_page(
			self::PARENT_SLUG,
			__( 'Login Branding', 'platform-helm' ),
			__( 'Login Branding', 'platform-helm' ),
			'manage_options',
			self::PAGE_SLUG,
			[ $this, 'render' ]
		);
	}

	public function maybe_save(): void {
		if ( ! isset( $_POST['platform_helm_lb_save'] ) ) {
			return;
		}
		if ( ! Authorization::is_master_admin() ) {
			return;
		}
		check_admin_referer( 'platform_helm_lb_settings', '_lb_nonce' );

		$accent = isset( $_POST['accent'] ) ? sanitize_text_field( wp_unslash( $_POST['accent'] ) ) : '#9C1C1F';

		update_option( self::OPTION, [
			'logo_url'         => isset( $_POST['logo_url'] ) ? esc_url_raw( wp_unslash( $_POST['logo_url'] ) ) : '',
			'accent'           => self::is_hex( $accent ) ? $accent : '#9C1C1F',
			'headline'         => isset( $_POST['headline'] ) ? sanitize_text_field( wp_unslash( $_POST['headline'] ) ) : '',
			'subtext'          => isset( $_POST['subtext'] ) ? sanitize_text_field( wp_unslash( $_POST['subtext'] ) ) : '',
			'hide_lang'        => ! empty( $_POST['hide_lang'] ),
			'disable_register' => ! empty( $_POST['disable_register'] ),
		] );

		add_action( 'admin_notices', static function (): void {
			echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Login branding saved.', 'platform-helm' ) . '</p></div>';
		} );
	}

	public function render(): void {
		Authorization::require_master_admin();
		$s = self::settings();

		$actions = sprintf(
			'<a href="%s" target="_blank" rel="noopener" class="btn btn-secondary"><i class="ti ti-external-link" aria-hidden="true"></i> %s</a>',
			esc_url( wp_login_url() ),
			esc_html__( 'Preview login page', 'platform-helm' )
		);
		\Platform\Helm\Core\Ui::open_page(
			__( 'Login Branding — Aurora', 'platform-helm' ),
			__( 'A premium sign-in page. Loads only on the login screen, so it adds nothing to front-end performance.', 'platform-helm' ),
			$actions
		);
		\Platform\Helm\Core\Ui::card_open();
		?>
			<form method="post">
				<?php wp_nonce_field( 'platform_helm_lb_settings', '_lb_nonce' ); ?>
				<table class="form-table" role="presentation">
					<tr>
						<th scope="row"><label for="lb-logo"><?php esc_html_e( 'Logo URL', 'platform-helm' ); ?></label></th>
						<td>
							<input type="url" id="lb-logo" name="logo_url" class="regular-text" value="<?php echo esc_attr( $s['logo_url'] ); ?>" placeholder="<?php echo esc_attr( self::DEFAULT_LOGO ); ?>" />
							<p class="description"><?php esc_html_e( 'Use a light/white logo (the background is dark). Blank = your site’s Customizer logo.', 'platform-helm' ); ?></p>
						</td>
					</tr>
					<tr>
						<th scope="row"><label for="lb-headline"><?php esc_html_e( 'Headline', 'platform-helm' ); ?></label></th>
						<td><input type="text" id="lb-headline" name="headline" class="regular-text" value="<?php echo esc_attr( $s['headline'] ); ?>" /></td>
					</tr>
					<tr>
						<th scope="row"><label for="lb-subtext"><?php esc_html_e( 'Sub-text', 'platform-helm' ); ?></label></th>
						<td><input type="text" id="lb-subtext" name="subtext" class="regular-text" value="<?php echo esc_attr( $s['subtext'] ); ?>" /></td>
					</tr>
					<tr>
						<th scope="row"><label for="lb-accent"><?php esc_html_e( 'Accent / button colour', 'platform-helm' ); ?></label></th>
						<td><input type="text" id="lb-accent" name="accent" value="<?php echo esc_attr( $s['accent'] ); ?>" placeholder="#9C1C1F" /> <code><?php echo esc_html( $s['accent'] ); ?></code></td>
					</tr>
					<tr>
						<th scope="row"><?php esc_html_e( 'Registration', 'platform-helm' ); ?></th>
						<td><label><input type="checkbox" name="disable_register" value="1" <?php checked( $s['disable_register'] ); ?> /> <?php esc_html_e( 'Remove the public “Register” link (for invite-only sites)', 'platform-helm' ); ?></label></td>
					</tr>
					<tr>
						<th scope="row"><?php esc_html_e( 'Language switcher', 'platform-helm' ); ?></th>
						<td><label><input type="checkbox" name="hide_lang" value="1" <?php checked( $s['hide_lang'] ); ?> /> <?php esc_html_e( 'Hide the Google language switcher', 'platform-helm' ); ?></label></td>
					</tr>
				</table>
				<p class="submit"><button type="submit" name="platform_helm_lb_save" class="button button-primary"><?php esc_html_e( 'Save changes', 'platform-helm' ); ?></button></p>
			</form>
		<?php
		\Platform\Helm\Core\Ui::card_close();
		\Platform\Helm\Core\Ui::close_page();
	}
}
