<?php
/**
 * Shareable Usage & Analytics report.
 *
 * Token-authenticated, read-only standalone page (same trust model as the
 * public leads page): the owner copies the link from Usage & Billing and can
 * share it with their team or agency without a WordPress login. Print-ready.
 *
 * @since      1.34.0
 *
 * @package    SiteStaffr
 * @subpackage SiteStaffr/includes
 */

if ( ! defined( 'WPINC' ) ) {
	die;
}

/**
 * Public usage report route + token.
 */
class SiteStaffr_Usage_Report {

	const TOKEN_OPTION = 'sitestaffr_usage_report_token';

	/**
	 * Get (or mint) the persistent report token.
	 *
	 * @return string
	 */
	public static function get_or_create_token() {
		$token = get_option( self::TOKEN_OPTION, '' );
		if ( ! is_string( $token ) || strlen( $token ) < 32 ) {
			$token = wp_generate_password( 40, false, false );
			update_option( self::TOKEN_OPTION, $token, false );
		}
		return $token;
	}

	/**
	 * Constant-time token check.
	 *
	 * @param string $token Candidate token.
	 * @return bool
	 */
	private static function verify_token( $token ) {
		$stored = get_option( self::TOKEN_OPTION, '' );
		return is_string( $stored ) && strlen( $stored ) >= 32 && hash_equals( $stored, (string) $token );
	}

	/**
	 * Shareable report URL.
	 *
	 * @return string
	 */
	public static function get_page_url() {
		return add_query_arg(
			array(
				'sitestaffr_usage_report' => 1,
				'token'                   => self::get_or_create_token(),
			),
			home_url( '/' )
		);
	}

	/**
	 * Intercept the public report route, verify the token, render standalone HTML.
	 *
	 * @return void
	 */
	public static function maybe_render_report_page() {
		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- bearer token is the credential (same model as the leads page).
		if ( ! isset( $_GET['sitestaffr_usage_report'] ) || ! isset( $_GET['token'] ) ) {
			return;
		}

		if ( ! defined( 'DONOTCACHEPAGE' ) ) {
			define( 'DONOTCACHEPAGE', true );
		}
		do_action( 'litespeed_control_set_nocache', 'sitestaffr usage report' );

		$token        = sanitize_text_field( wp_unslash( $_GET['token'] ) );
		$cycle_offset = isset( $_GET['cycle'] ) ? max( 0, (int) wp_unslash( $_GET['cycle'] ) ) : 0;
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		if ( ! self::verify_token( $token ) ) {
			status_header( 403 );
			wp_die(
				esc_html__( 'This report link is invalid or has been reset.', 'sitestaffr' ),
				esc_html__( 'Invalid Link', 'sitestaffr' ),
				array( 'response' => 403 )
			);
		}

		nocache_headers();
		// This standalone report prints wp_footer(); keep the chat widget out of it.
		if ( class_exists( 'SiteStaffr_Widget_Auto_Display_Handler' ) ) {
			SiteStaffr_Widget_Auto_Display_Handler::suppress();
		}
		header( 'X-Robots-Tag: noindex, nofollow', true );

		// One shared definition of the cycle and its totals — the Usage screen reads
		// the exact same numbers, so the report can no longer disagree with it.
		require_once SITESTAFFR_PLUGIN_DIR . 'includes/class-sitestaffr-usage-cycle.php';
		$stats = SiteStaffr_Usage_Cycle::get_stats( $cycle_offset );

		$window        = $stats['window'];
		$start_dt      = $window['start_dt'];
		$end_dt        = $window['query_end_dt'];
		$counts        = array(
			'total_calls'    => $stats['conversations'],
			'billable_calls' => $stats['billable'],
		);
		$leads_count   = $stats['leads'];
		$avg_seconds   = $stats['avg_seconds'];
		$total_minutes = $stats['minutes_used'];

		// When & where — same shared definition the Usage screen reads.
		$hours_state     = $stats['hours_state'];
		$after_hours     = $stats['after_hours'];
		$top_pages       = $stats['top_pages'];
		$after_hours_pct = $after_hours['after_hours_pct'];

		$minutes_map = array();
		foreach ( $stats['daily_minutes'] as $row ) {
			$minutes_map[ (string) $row->day_key ] = (int) $row->total;
		}
		$volume_map = array();
		foreach ( $stats['daily_volume'] as $row ) {
			$volume_map[ (string) $row->day_key ] = (int) $row->total;
		}

		// Daily table rows spanning the cycle up to today (skip all-zero days).
		$daily = array();
		$cursor = strtotime( gmdate( 'Y-m-d', strtotime( $start_dt ) ) );
		$last   = strtotime( gmdate( 'Y-m-d', strtotime( $end_dt ) ) );
		while ( false !== $cursor && $cursor <= $last ) {
			$key = gmdate( 'Y-m-d', $cursor );
			$conversations = isset( $volume_map[ $key ] ) ? $volume_map[ $key ] : 0;
			$minutes       = isset( $minutes_map[ $key ] ) ? $minutes_map[ $key ] : 0;
			if ( $conversations > 0 || $minutes > 0 ) {
				$daily[] = array(
					'label'         => gmdate( 'M j, Y', $cursor ),
					'conversations' => $conversations,
					'minutes'       => $minutes,
				);
			}
			$cursor = strtotime( '+1 day', $cursor );
		}

		$settings      = get_option( 'sitestaffr_settings', array() );
		$business_name = ! empty( $settings['business_name'] ) ? stripslashes( $settings['business_name'] ) : get_bloginfo( 'name' );
		$logo_url      = SITESTAFFR_PLUGIN_URL . 'assets/images/logo.png';

		$page_url       = self::get_page_url();
		$has_newer      = ( $cycle_offset > 0 );
		$prev_cycle_url = add_query_arg( 'cycle', $cycle_offset + 1, $page_url );
		$next_cycle_url = $has_newer ? add_query_arg( 'cycle', $cycle_offset - 1, $page_url ) : '';
		$cycle_label    = $window['label'];

		wp_enqueue_style(
			'sitestaffr-transcript-viewer',
			SITESTAFFR_PLUGIN_URL . 'assets/css/sitestaffr-transcript-viewer.css',
			array(),
			SITESTAFFR_VERSION
		);

		include SITESTAFFR_PLUGIN_DIR . 'templates/public/usage-report-viewer.php';
		exit;
	}
}
