<?php
/**
 * Dashboard Colors — FREE
 *
 * Applies Panelra colors while keeping contrast aligned with
 * WordPress admin-color behaviour. Menu/icon/button text colors are
 * always auto-calculated, so custom colors remain readable.
 *
 * @package Panelra
 */
if ( ! defined( 'ABSPATH' ) ) { exit; }

class Pnlrdb_Dashboard_Colors {

	public function __construct() {
		add_action( 'admin_enqueue_scripts', array( $this, 'inject_styles' ) );
	}

	/**
	 * Normalize a hex color.
	 *
	 * @param mixed  $hex      Raw hex color.
	 * @param string $fallback Fallback hex color.
	 * @return string
	 */
	public static function normalize_hex( $hex, $fallback ) {
		$hex = sanitize_hex_color( (string) $hex );
		return $hex ? strtolower( $hex ) : strtolower( $fallback );
	}

	/**
	 * Convert a hex color to RGB values.
	 *
	 * @param string $hex Hex color.
	 * @return array{r:int,g:int,b:int}
	 */
	public static function hex_to_rgb( $hex ) {
		$hex = ltrim( self::normalize_hex( $hex, '#000000' ), '#' );
		if ( 3 === strlen( $hex ) ) {
			$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
		}

		return array(
			'r' => hexdec( substr( $hex, 0, 2 ) ),
			'g' => hexdec( substr( $hex, 2, 2 ) ),
			'b' => hexdec( substr( $hex, 4, 2 ) ),
		);
	}

	/**
	 * Relative luminance helper.
	 *
	 * @param string $hex Hex color.
	 * @return float
	 */
	public static function relative_luminance( $hex ) {
		$rgb = self::hex_to_rgb( $hex );
		$map = array();

		foreach ( $rgb as $channel ) {
			$value  = $channel / 255;
			$map[] = ( $value <= 0.03928 ) ? ( $value / 12.92 ) : pow( ( $value + 0.055 ) / 1.055, 2.4 );
		}

		return ( 0.2126 * $map[0] ) + ( 0.7152 * $map[1] ) + ( 0.0722 * $map[2] );
	}

	/**
	 * WCAG contrast ratio.
	 *
	 * @param string $color_a Color A.
	 * @param string $color_b Color B.
	 * @return float
	 */
	public static function contrast_ratio( $color_a, $color_b ) {
		$l1 = self::relative_luminance( $color_a );
		$l2 = self::relative_luminance( $color_b );
		$light = max( $l1, $l2 );
		$dark  = min( $l1, $l2 );
		return ( $light + 0.05 ) / ( $dark + 0.05 );
	}

	/**
	 * Return the most readable text color for a given background.
	 *
	 * @param string $background Background color.
	 * @param string $light      Candidate light color.
	 * @param string $dark       Candidate dark color.
	 * @return string
	 */
	public static function best_text_color( $background, $light = '#ffffff', $dark = '#1d2327' ) {
		$light = self::normalize_hex( $light, '#ffffff' );
		$dark  = self::normalize_hex( $dark, '#1d2327' );
		return self::contrast_ratio( $background, $light ) >= self::contrast_ratio( $background, $dark ) ? $light : $dark;
	}

	/**
	 * Adjust a foreground color until it has enough contrast on a background.
	 *
	 * @param string $foreground Foreground color.
	 * @param string $background Background color.
	 * @param float  $minimum    Minimum contrast ratio.
	 * @return string
	 */
	public static function ensure_contrast( $foreground, $background = '#ffffff', $minimum = 4.5 ) {
		$foreground = self::normalize_hex( $foreground, '#2271b1' );
		$background = self::normalize_hex( $background, '#ffffff' );

		if ( self::contrast_ratio( $foreground, $background ) >= $minimum ) {
			return $foreground;
		}

		$dark_candidate  = $foreground;
		$light_candidate = $foreground;

		for ( $i = 1; $i <= 12; $i++ ) {
			$dark_candidate = self::mix_colors( $foreground, '#000000', $i * 0.06 );
			if ( self::contrast_ratio( $dark_candidate, $background ) >= $minimum ) {
				return $dark_candidate;
			}
		}

		for ( $i = 1; $i <= 12; $i++ ) {
			$light_candidate = self::mix_colors( $foreground, '#ffffff', $i * 0.06 );
			if ( self::contrast_ratio( $light_candidate, $background ) >= $minimum ) {
				return $light_candidate;
			}
		}

		return self::best_text_color( $background );
	}

	/**
	 * Mix two colors.
	 *
	 * @param string $color_a Base color.
	 * @param string $color_b Mixed-in color.
	 * @param float  $ratio   0..1 ratio of color_b.
	 * @return string
	 */
	public static function mix_colors( $color_a, $color_b, $ratio ) {
		$ratio = max( 0, min( 1, (float) $ratio ) );
		$a = self::hex_to_rgb( $color_a );
		$b = self::hex_to_rgb( $color_b );

		$r = (int) round( $a['r'] + ( ( $b['r'] - $a['r'] ) * $ratio ) );
		$g = (int) round( $a['g'] + ( ( $b['g'] - $a['g'] ) * $ratio ) );
		$bl = (int) round( $a['b'] + ( ( $b['b'] - $a['b'] ) * $ratio ) );

		return sprintf( '#%02x%02x%02x', $r, $g, $bl );
	}

	/**
	 * Convert hex to rgb string.
	 *
	 * @param string $hex Hex color.
	 * @return string
	 */
	public static function rgb_string( $hex ) {
		$rgb = self::hex_to_rgb( $hex );
		return $rgb['r'] . ', ' . $rgb['g'] . ', ' . $rgb['b'];
	}

	/**
	 * Get current WP admin scheme defaults.
	 *
	 * @return array<string,string>
	 */
	public static function get_wp_scheme_defaults() {
		global $_wp_admin_css_colors;

		$scheme_key = get_user_option( 'admin_color' );
		$scheme     = isset( $_wp_admin_css_colors[ $scheme_key ] ) ? $_wp_admin_css_colors[ $scheme_key ] : null;
		$fresh      = isset( $_wp_admin_css_colors['fresh'] ) ? $_wp_admin_css_colors['fresh'] : null;

		$colors = ( isset( $scheme->colors ) && is_array( $scheme->colors ) ) ? $scheme->colors : array();
		if ( empty( $colors ) && isset( $fresh->colors ) && is_array( $fresh->colors ) ) {
			$colors = $fresh->colors;
		}

		$icons = ( isset( $scheme->icon_colors ) && is_array( $scheme->icon_colors ) ) ? $scheme->icon_colors : array();
		if ( empty( $icons ) && isset( $fresh->icon_colors ) && is_array( $fresh->icon_colors ) ) {
			$icons = $fresh->icon_colors;
		}

		$sidebar = self::normalize_hex( $colors[0] ?? '#1d2327', '#1d2327' );
		$primary = self::normalize_hex( $colors[2] ?? '#2271b1', '#2271b1' );

		$menu_base    = self::normalize_hex( $icons['base'] ?? self::best_text_color( $sidebar, '#f6f7f7', '#1d2327' ), '#a7aaad' );
		$menu_focus   = self::normalize_hex( $icons['focus'] ?? self::best_text_color( $sidebar ), '#72aee6' );
		$menu_current = self::normalize_hex( $icons['current'] ?? self::best_text_color( $sidebar ), '#ffffff' );

		return array(
			'sidebar_bg'   => $sidebar,
			'primary'      => $primary,
			'content_text' => '#2c3338',
			'menu_base'    => $menu_base,
			'menu_focus'   => $menu_focus,
			'menu_current' => $menu_current,
		);
	}

	/**
	 * Whether Panelra should leave WordPress content colors fully native.
	 *
	 * Panelra never recolors #wpcontent links or buttons. This helper is kept for
	 * backward-compatible internal checks and only treats an empty color option as
	 * fully native.
	 *
	 * @return bool
	 */
	public static function use_native_wp_content_colors() {
		$colors = get_option( 'pnlrdb_dashboard_colors', array() );
		return empty( $colors );
	}

	/**
	 * Build all design tokens.
	 *
	 * @return array<string,int|string>
	 */
	public static function get_design_tokens() {
		$defaults   = self::get_wp_scheme_defaults();
		$colors     = get_option( 'pnlrdb_dashboard_colors', array( 'sidebar_bg' => '#0d003a' ) );
		$font       = get_option( 'pnlrdb_dashboard_font', 'Roboto, Arial, sans-serif' );
		$font_size  = max( 10, min( 22, absint( get_option( 'pnlrdb_dashboard_font_size', 15 ) ) ) );
		$font_color = self::normalize_hex( get_option( 'pnlrdb_dashboard_font_color', $defaults['content_text'] ), $defaults['content_text'] );
		$width      = max( 160, min( 500, absint( get_option( 'pnlrdb_menu_width', 220 ) ) ) );

		$primary    = self::normalize_hex( $colors['primary'] ?? $defaults['primary'], $defaults['primary'] );
		$sidebar_bg = self::normalize_hex( $colors['sidebar_bg'] ?? $defaults['sidebar_bg'], $defaults['sidebar_bg'] );

		$button_text        = self::best_text_color( $primary, '#ffffff', '#1d2327' );
		$menu_text          = self::best_text_color( $sidebar_bg, '#f6f7f7', '#1d2327' );
		$menu_text_muted    = self::mix_colors( $menu_text, $sidebar_bg, 0.34 );
		$menu_text_soft     = self::mix_colors( $menu_text, $sidebar_bg, 0.18 );
		$submenu_bg         = self::mix_colors( $sidebar_bg, '#000000', 0.14 );
		$submenu_border     = self::mix_colors( $menu_text, $sidebar_bg, 0.78 );
		$menu_hover_bg      = self::mix_colors( $sidebar_bg, $menu_text, 0.08 );
		$active_bg          = self::mix_colors( $sidebar_bg, $primary, 0.22 );
		$active_border      = self::mix_colors( $sidebar_bg, $primary, 0.44 );
		$primary_hover      = self::mix_colors( $primary, '#000000', 0.12 );
		$link_color         = self::ensure_contrast( $primary, '#ffffff', 4.5 );
		$link_hover         = self::ensure_contrast( $primary_hover, '#ffffff', 4.5 );
		$primary_focus_ring = self::mix_colors( $primary, '#ffffff', 0.72 );

		return array(
			'font'               => $font,
			'font_size'          => $font_size,
			'font_color'         => $font_color,
			'width'              => $width,
			'primary'            => $primary,
			'primary_hover'      => $primary_hover,
			'link_color'         => $link_color,
			'link_hover'         => $link_hover,
			'primary_focus_ring' => $primary_focus_ring,
			'sidebar_bg'         => $sidebar_bg,
			'button_text'        => $button_text,
			'menu_text'          => $menu_text,
			'menu_text_muted'    => $menu_text_muted,
			'menu_text_soft'     => $menu_text_soft,
			'submenu_bg'         => $submenu_bg,
			'submenu_border'     => $submenu_border,
			'menu_hover_bg'      => $menu_hover_bg,
			'active_bg'          => $active_bg,
			'active_border'      => $active_border,
		);
	}

	/**
	 * Print admin CSS.
	 *
	 * @return void
	 */
	public function inject_styles() {
		ob_start();
		$t = self::get_design_tokens();
		?>
:root {
	--ap773-primary: <?php echo esc_attr( $t['primary'] ); ?>;
	--ap773-primary-hover: <?php echo esc_attr( $t['primary_hover'] ); ?>;
	--ap773-link: <?php echo esc_attr( $t['link_color'] ); ?>;
	--ap773-link-hover: <?php echo esc_attr( $t['link_hover'] ); ?>;
	--ap773-primary-focus-ring: <?php echo esc_attr( $t['primary_focus_ring'] ); ?>;
	--ap773-sidebar: <?php echo esc_attr( $t['sidebar_bg'] ); ?>;
	--ap773-width: <?php echo esc_attr( $t['width'] ); ?>px;
	--ap773-fs: <?php echo esc_attr( $t['font_size'] ); ?>px;
	--ap773-fc: <?php echo esc_attr( $t['font_color'] ); ?>;
	--ap773-btn-text: <?php echo esc_attr( $t['button_text'] ); ?>;
	--ap773-menu-text: <?php echo esc_attr( $t['menu_text'] ); ?>;
	--ap773-menu-text-muted: <?php echo esc_attr( $t['menu_text_muted'] ); ?>;
	--ap773-menu-text-soft: <?php echo esc_attr( $t['menu_text_soft'] ); ?>;
	--ap773-submenu-bg: <?php echo esc_attr( $t['submenu_bg'] ); ?>;
	--ap773-submenu-border: <?php echo esc_attr( $t['submenu_border'] ); ?>;
	--ap773-menu-hover-bg: <?php echo esc_attr( $t['menu_hover_bg'] ); ?>;
	--ap773-active-bg: <?php echo esc_attr( $t['active_bg'] ); ?>;
	--ap773-active-border: <?php echo esc_attr( $t['active_border'] ); ?>;
	--ap773-primary-rgb: <?php echo esc_attr( self::rgb_string( $t['primary'] ) ); ?>;
}

/* ---- WordPress left menu ---- */
#adminmenuback,
#adminmenuwrap,
#adminmenu {
	background: var(--ap773-sidebar) !important;
	width: var(--ap773-width) !important;
}
#adminmenuwrap { overflow-y: auto; overflow-x: hidden; }
#wpcontent, #wpfooter { margin-left: var(--ap773-width) !important; }
.folded #adminmenuback,
.folded #adminmenuwrap,
.folded #adminmenu,
.auto-fold #adminmenuback,
.auto-fold #adminmenuwrap,
.auto-fold #adminmenu {
	width: var(--ap773-width) !important;
}
.folded #wpcontent,
.folded #wpfooter,
.auto-fold #wpcontent,
.auto-fold #wpfooter {
	margin-left: var(--ap773-width) !important;
}
#adminmenu .wp-menu-arrow,
#adminmenu .wp-menu-arrow div { display: none !important; }
#adminmenu .wp-submenu {
	position: static !important;
	left: 0 !important;
	top: 0 !important;
	float: none !important;
	clear: both !important;
	display: none !important;
	width: calc(100% - 8px) !important;
	min-width: calc(100% - 8px) !important;
	margin: 4px 0 0 8px !important;
	padding: 0 !important;
	border: 0 !important;
	border-left: 2px solid var(--ap773-submenu-border) !important;
	border-radius: 0 0 8px 8px !important;
	box-shadow: none !important;
	overflow: hidden;
	background: var(--ap773-submenu-bg) !important;
}
#adminmenu li.wp-has-current-submenu > .wp-submenu,
#adminmenu li.current.wp-has-submenu > .wp-submenu,
#adminmenu li.ap773-open > .wp-submenu { display: block !important; }
#adminmenu .wp-submenu-head { display: none !important; }
#adminmenu > li.menu-top { position: relative; margin-bottom: 2px !important; border-radius: 8px; }
#adminmenu > li.menu-top > a.menu-top {
	position: relative;
	display: flex !important;
	align-items: center;
	width: 100%;
	min-height: 40px;
	box-sizing: border-box;
	padding: 8px 38px 8px 8px !important;
	border-radius: 8px !important;
	border: 1px solid transparent !important;
	transition: background .15s, border-color .15s, color .15s;
}
#adminmenu > li.menu-top > a.menu-top:hover,
#adminmenu li.opensub > a.menu-top {
	background: var(--ap773-menu-hover-bg) !important;
}
#adminmenu li.ap773-open > a.menu-top {
	background: var(--ap773-menu-hover-bg) !important;
	border-bottom-left-radius: 0 !important;
	border-bottom-right-radius: 0 !important;
}
#adminmenu li.current > a.menu-top,
#adminmenu li.wp-has-current-submenu > a.wp-has-current-submenu {
	background: var(--ap773-active-bg) !important;
	border-color: var(--ap773-active-border) !important;
}
#adminmenu a,
#adminmenu div.wp-menu-image:before,
#adminmenu .wp-submenu a,
#adminmenu .wp-menu-name {
	color: var(--ap773-menu-text-muted) !important;
}
#adminmenu li.menu-top:hover > a.menu-top,
#adminmenu li.menu-top:hover > a.menu-top div.wp-menu-image:before,
#adminmenu a:hover,
#adminmenu .wp-submenu a:hover,
#adminmenu li.current a.menu-top,
#adminmenu li.wp-has-current-submenu > a.wp-has-current-submenu,
#adminmenu li.wp-has-current-submenu > a.wp-has-current-submenu div.wp-menu-image:before,
#adminmenu .wp-submenu li.current a {
	color: var(--ap773-menu-text) !important;
}
#adminmenu .ap773-arrow {
	position: absolute;
	top: 50%;
	right: 10px;
	transform: translateY(-50%);
	width: 18px;
	height: 18px;
	display: flex;
	align-items: center;
	justify-content: center;
	opacity: .6;
	transition: transform .15s, opacity .15s;
	pointer-events: auto;
}
#adminmenu .ap773-arrow::after {
	content: '';
	display: block;
	width: 6px;
	height: 6px;
	border-right: 1.5px solid var(--ap773-menu-text-soft);
	border-bottom: 1.5px solid var(--ap773-menu-text-soft);
	transform: rotate(45deg);
	margin-top: -3px;
	transition: transform .15s, border-color .15s;
}
#adminmenu li.menu-top:hover > a.menu-top .ap773-arrow::after,
#adminmenu li.current > a.menu-top .ap773-arrow::after,
#adminmenu li.wp-has-current-submenu > a.wp-has-current-submenu .ap773-arrow::after,
#adminmenu li.ap773-open > a.menu-top .ap773-arrow::after {
	border-right-color: var(--ap773-menu-text);
	border-bottom-color: var(--ap773-menu-text);
}
#adminmenu li.ap773-open > a.menu-top .ap773-arrow::after { transform: rotate(225deg); margin-top: 2px; }
#adminmenu li.ap773-open > a.menu-top .ap773-arrow { opacity: .95; }
#adminmenu .wp-submenu li a {
	width: 100% !important;
	box-sizing: border-box;
	margin: 0 !important;
	padding: 8px 12px 8px 24px !important;
	white-space: normal !important;
	line-height: 1.4 !important;
	font-size: calc(var(--ap773-fs) - 1px) !important;
	border-top: 1px solid <?php echo esc_attr( self::mix_colors( $t['menu_text'], $t['sidebar_bg'], 0.88 ) ); ?>;
}
#adminmenu .wp-submenu li:first-child a { border-top: none; }
#adminmenu .wp-submenu li a:hover,
#adminmenu .wp-submenu li.current a {
	background: var(--ap773-menu-hover-bg) !important;
	color: var(--ap773-menu-text) !important;
}

/* ---- General admin typography ---- */
<?php $pnlrdb_native_wp_content_colors = self::use_native_wp_content_colors(); ?>
<?php if ( ! $pnlrdb_native_wp_content_colors && ! empty( $t['font'] ) ) : ?>
body.wp-admin:not(:has(.ap773-page)),
body.wp-admin:not(:has(.ap773-page)) #wpadminbar,
body.wp-admin:not(:has(.ap773-page)) #adminmenu,
body.wp-admin:not(:has(.ap773-page)) #adminmenu a,
body.wp-admin:not(:has(.ap773-page)) #wpcontent,
body.wp-admin:not(:has(.ap773-page)) input,
body.wp-admin:not(:has(.ap773-page)) select,
body.wp-admin:not(:has(.ap773-page)) textarea,
body.wp-admin:not(:has(.ap773-page)) button {
	font-family: <?php echo esc_attr( $t['font'] ); ?>, sans-serif !important;
}
<?php endif; ?>
/*
 * Keep WordPress content colors native.
 * Panelra may adjust layout typography, but it must not recolor links,
 * primary buttons, Gutenberg components, form focus states or nav tabs inside
 * #wpcontent. WordPress admin color schemes already handle those states and
 * preserve proper contrast across core and third-party admin screens.
 */
body.wp-admin #wpcontent,
body.wp-admin #wpcontent input,
body.wp-admin #wpcontent select,
body.wp-admin #wpcontent textarea,
body.wp-admin #wpcontent button,
body.wp-admin #wpcontent .wrap,
body.wp-admin #wpcontent p,
body.wp-admin #wpcontent li,
#adminmenu a.menu-top,
#adminmenu .wp-submenu a {
	font-size: var(--ap773-fs) !important;
}

/* ---- Panelra panel buttons only ---- */
.ap773-page .ap773-btn--primary,
.ap773-page .ap773-btn--primary:hover,
.ap773-page .ap773-btn--primary:focus {
	color: var(--ap773-btn-text) !important;
}
</style>
		<?php

		$css = ob_get_clean();
		$css = trim( $css );

		wp_register_style( "pnlrdb-dashboard-colors", false, array(), PNLRDB_VERSION );
		wp_enqueue_style( "pnlrdb-dashboard-colors" );
		wp_add_inline_style( "pnlrdb-dashboard-colors", $css );
	}
}
