<?php
/**
 * Daily aggregate notification analytics.
 *
 * @package VoidPulse
 */

namespace VoidPulse\Notifications;

defined( 'ABSPATH' ) || exit;

final class Analytics {
	/**
	 * Longest reporting range, matching how long daily totals are retained.
	 */
	const MAXIMUM_RANGE = 365;

	/**
	 * Register daily retention.
	 *
	 * @return void
	 */
	public function register() {
		add_action( 'voidpulse_cleanup_events', array( $this, 'cleanup' ) );
	}

	/**
	 * Increment an aggregate.
	 *
	 * @param string $metric Metric.
	 * @return void
	 */
	public static function increment( $metric ) {
		if ( ! in_array( $metric, array( 'impressions', 'clicks', 'dismissals' ), true ) ) {
			return;
		}
		$data = get_option( 'voidpulse_analytics_daily', array() );
		$date = gmdate( 'Y-m-d' );
		if ( ! isset( $data[ $date ] ) ) {
			$data[ $date ] = array( 'impressions' => 0, 'clicks' => 0, 'dismissals' => 0 );
		}
		++$data[ $date ][ $metric ];
		update_option( 'voidpulse_analytics_daily', $data, false );
	}

	/**
	 * Return a bounded daily aggregate.
	 *
	 * @param int $range Number of calendar days.
	 * @return array<string,mixed>
	 */
	public static function summary( $range = 30 ) {
		$range  = min( self::MAXIMUM_RANGE, max( 1, absint( $range ) ) );
		$data   = get_option( 'voidpulse_analytics_daily', array() );
		$totals = array( 'impressions' => 0, 'clicks' => 0, 'dismissals' => 0, 'ctr' => 0.0 );
		$days   = array();
		for ( $offset = $range - 1; $offset >= 0; --$offset ) {
			$date        = gmdate( 'Y-m-d', time() - DAY_IN_SECONDS * $offset );
			$impressions = isset( $data[ $date ]['impressions'] ) ? absint( $data[ $date ]['impressions'] ) : 0;
			$clicks      = isset( $data[ $date ]['clicks'] ) ? absint( $data[ $date ]['clicks'] ) : 0;
			$dismissals  = isset( $data[ $date ]['dismissals'] ) ? absint( $data[ $date ]['dismissals'] ) : 0;
			$days[]      = array(
				'date'        => $date,
				'impressions' => $impressions,
				'clicks'      => $clicks,
				'dismissals'  => $dismissals,
				'ctr'         => $impressions ? round( 100 * $clicks / $impressions, 2 ) : 0.0,
			);
			$totals['impressions'] += $impressions;
			$totals['clicks']      += $clicks;
			$totals['dismissals']  += $dismissals;
		}
		$totals['ctr'] = $totals['impressions'] ? round( 100 * $totals['clicks'] / $totals['impressions'], 2 ) : 0.0;
		$totals['days'] = $days;
		return $totals;
	}

	/**
	 * Retain one year so edition changes do not discard local history.
	 *
	 * @return void
	 */
	public function cleanup() {
		$data   = get_option( 'voidpulse_analytics_daily', array() );
		$cutoff = gmdate( 'Y-m-d', time() - self::MAXIMUM_RANGE * DAY_IN_SECONDS );
		foreach ( array_keys( $data ) as $date ) {
			if ( $date < $cutoff ) {
				unset( $data[ $date ] );
			}
		}
		update_option( 'voidpulse_analytics_daily', $data, false );
	}
}
