<?php
/**
 * Cache module — Web Vitals dashboard
 *
 * @var Blaminhor_Essentials_Module_Cache $module
 * @var array                             $settings
 *
 * @package BlaminhorEssentials
 */

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

$enabled = ! empty( $settings['webvitals_enabled'] );
$data    = $module->webvitals_aggregator->get_dashboard_data( 30 );
?>

<h2><?php esc_html_e( 'Real-User Monitoring', 'blaminhor-essentials' ); ?></h2>

<table class="form-table">
	<tr>
		<th scope="row"><?php esc_html_e( 'Enable RUM collection', 'blaminhor-essentials' ); ?></th>
		<td>
			<label>
				<input type="checkbox" name="webvitals_enabled" value="1" <?php checked( $enabled ); ?>>
				<?php esc_html_e( 'Collect Core Web Vitals from real visitors', 'blaminhor-essentials' ); ?>
			</label>
			<p class="description" style="color:#b35900;">
				<?php esc_html_e( 'Privacy: we only record the technical speed measurements made by the browser (display time, smoothness, etc.), the URL visited and the device type (mobile / tablet / desktop). No personal data. No IP address is stored — only an anonymised fingerprint to prevent the same visitor from skewing the stats by refreshing. Considered purely technical measurement in most jurisdictions, so no cookie banner is required — but check your local regulations if unsure.', 'blaminhor-essentials' ); ?>
			</p>
		</td>
	</tr>
	<tr>
		<th scope="row">
			<label for="be-rum-sample"><?php esc_html_e( 'Sample rate', 'blaminhor-essentials' ); ?></label>
		</th>
		<td>
			<input type="number" id="be-rum-sample" name="webvitals_sample_rate" min="1" max="100" value="<?php echo esc_attr( (int) $settings['webvitals_sample_rate'] ); ?>" class="small-text"> %
			<p class="description"><?php esc_html_e( 'How many of your visitors get measured. 100% = most reliable data. If your site gets a lot of traffic, lower to 25% or 10% to keep the table small — the average stays accurate.', 'blaminhor-essentials' ); ?></p>
		</td>
	</tr>
	<tr>
		<th scope="row">
			<label for="be-rum-retention"><?php esc_html_e( 'Retention (days)', 'blaminhor-essentials' ); ?></label>
		</th>
		<td>
			<input type="number" id="be-rum-retention" name="webvitals_retention_days" min="7" max="365" value="<?php echo esc_attr( (int) $settings['webvitals_retention_days'] ); ?>" class="small-text">
			<p class="description"><?php esc_html_e( 'Individual measurements are deleted after this many days. Daily averages (used for the trend graphs) are kept for 90 days no matter what.', 'blaminhor-essentials' ); ?></p>
		</td>
	</tr>
</table>

<?php if ( $enabled ) : ?>

	<h3><?php esc_html_e( 'Last 30 days — p75', 'blaminhor-essentials' ); ?></h3>

	<?php
	if ( empty( $data['series'] ) ) {
		echo '<p class="description">' . esc_html__( 'No data yet. The dashboard will populate as visitors browse the site.', 'blaminhor-essentials' ) . '</p>';
	} else {
		// Pivot rows by metric for the SVG renderer.
		$by_metric = array();
		foreach ( $data['series'] as $row ) {
			$by_metric[ $row['metric'] ][] = array(
				'date'    => $row['period_date'],
				'device'  => $row['device'],
				'value'   => (float) $row['value'],
				'samples' => (int) $row['samples'],
			);
		}

		$metrics_meta = array(
			'LCP'  => array( 'label' => 'LCP (ms)',  'good' => 2500, 'poor' => 4000 ),
			'INP'  => array( 'label' => 'INP (ms)',  'good' => 200,  'poor' => 500 ),
			'CLS'  => array( 'label' => 'CLS',       'good' => 0.1,  'poor' => 0.25 ),
			'FCP'  => array( 'label' => 'FCP (ms)',  'good' => 1800, 'poor' => 3000 ),
			'TTFB' => array( 'label' => 'TTFB (ms)', 'good' => 800,  'poor' => 1800 ),
		);

		echo '<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;">';
		foreach ( $metrics_meta as $metric => $meta ) {
			if ( empty( $by_metric[ $metric ] ) ) {
				continue;
			}
			$series = $by_metric[ $metric ];
			echo '<div class="blaminhor-essentials-card" style="padding:12px;">';
			echo '<strong>' . esc_html( $meta['label'] ) . '</strong>';
			// render_be_rum_svg_chart() builds an SVG from internal numeric values
			// and escapes its only variable string with esc_attr() before injection.
			echo render_be_rum_svg_chart( $series, $meta ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SVG built from numeric values; the one variable string ($d_attr) is escaped inside the function.
			echo '</div>';
		}
		echo '</div>';
	}

	if ( ! empty( $data['worst'] ) ) :
		?>
		<h3><?php esc_html_e( 'Worst URLs (last 7 days)', 'blaminhor-essentials' ); ?></h3>
		<table class="widefat striped" style="max-width:1000px;">
			<thead>
				<tr>
					<th><?php esc_html_e( 'URL', 'blaminhor-essentials' ); ?></th>
					<th><?php esc_html_e( 'Device', 'blaminhor-essentials' ); ?></th>
					<th><?php esc_html_e( 'Metric', 'blaminhor-essentials' ); ?></th>
					<th><?php esc_html_e( 'p75', 'blaminhor-essentials' ); ?></th>
					<th><?php esc_html_e( 'Samples', 'blaminhor-essentials' ); ?></th>
				</tr>
			</thead>
			<tbody>
				<?php foreach ( $data['worst'] as $row ) : ?>
					<tr>
						<td><a href="<?php echo esc_url( $row['url'] ); ?>" target="_blank"><?php echo esc_html( wp_make_link_relative( $row['url'] ) ); ?></a></td>
						<td><?php echo esc_html( $row['device'] ); ?></td>
						<td><code><?php echo esc_html( $row['metric'] ); ?></code></td>
						<td><?php echo esc_html( number_format_i18n( (float) $row['value'], 'CLS' === $row['metric'] ? 3 : 0 ) ); ?></td>
						<td><?php echo esc_html( (int) $row['samples'] ); ?></td>
					</tr>
				<?php endforeach; ?>
			</tbody>
		</table>
	<?php endif; ?>

<?php endif; ?>

<?php
/**
 * Inline SVG line chart (no external lib).
 *
 * @param array $series Rows {date, device, value}.
 * @param array $meta   {label, good, poor} thresholds.
 * @return string Inline SVG markup.
 */
function render_be_rum_svg_chart( $series, $meta ) {
	$w = 360;
	$h = 130;
	$pad = 24;

	// Average per date (across devices).
	$by_date = array();
	foreach ( $series as $r ) {
		$d = $r['date'];
		if ( ! isset( $by_date[ $d ] ) ) {
			$by_date[ $d ] = array( 'sum' => 0, 'n' => 0 );
		}
		$by_date[ $d ]['sum'] += $r['value'];
		$by_date[ $d ]['n']   += 1;
	}
	ksort( $by_date );
	$points = array();
	foreach ( $by_date as $d => $agg ) {
		$points[] = array( 'date' => $d, 'value' => $agg['sum'] / max( 1, $agg['n'] ) );
	}
	if ( count( $points ) < 2 ) {
		return '<p class="description" style="margin:8px 0 0;">' . esc_html__( 'Not enough data points yet — need at least two days.', 'blaminhor-essentials' ) . '</p>';
	}

	$values = wp_list_pluck( $points, 'value' );
	$max    = max( $values );
	$min    = min( $values );
	$range  = max( 1e-6, $max - $min );

	$d_attr = '';
	$step   = ( $w - 2 * $pad ) / ( count( $points ) - 1 );
	foreach ( $points as $i => $p ) {
		$x = $pad + $i * $step;
		$y = $h - $pad - ( ( $p['value'] - $min ) / $range ) * ( $h - 2 * $pad );
		$d_attr .= ( 0 === $i ? 'M' : 'L' ) . round( $x, 1 ) . ' ' . round( $y, 1 ) . ' ';
	}

	// Reference lines for "good" and "poor" thresholds.
	$thresh_lines = '';
	foreach ( array( 'good' => '#3a8a4a', 'poor' => '#c33' ) as $k => $color ) {
		$tv = $meta[ $k ];
		if ( $tv >= $min && $tv <= $max ) {
			$y = $h - $pad - ( ( $tv - $min ) / $range ) * ( $h - 2 * $pad );
			$thresh_lines .= '<line x1="' . $pad . '" y1="' . round( $y, 1 ) . '" x2="' . ( $w - $pad ) . '" y2="' . round( $y, 1 ) . '" stroke="' . $color . '" stroke-dasharray="3 3" stroke-width="1" opacity=".5"/>';
		}
	}

	// Latest value highlight.
	$last = end( $points );
	$last_color = '#0073aa';
	if ( $last['value'] > $meta['poor'] ) {
		$last_color = '#c33';
	} elseif ( $last['value'] > $meta['good'] ) {
		$last_color = '#b35900';
	} else {
		$last_color = '#3a8a4a';
	}

	$svg  = '<svg viewBox="0 0 ' . $w . ' ' . $h . '" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;display:block;">';
	$svg .= $thresh_lines;
	$svg .= '<path d="' . esc_attr( trim( $d_attr ) ) . '" fill="none" stroke="' . $last_color . '" stroke-width="2" stroke-linejoin="round"/>';
	$svg .= '<text x="' . ( $w - $pad ) . '" y="' . $pad . '" text-anchor="end" font-size="14" fill="' . $last_color . '">' . esc_html( number_format_i18n( $last['value'], 0 === $meta['good'] || $meta['good'] >= 1 ? 0 : 2 ) ) . '</text>';
	$svg .= '</svg>';
	return $svg;
}
