<?php
/**
 * Link Health grade: a single letter (A–F) site owners can screenshot.
 *
 * Pure logic, unit tested. Rules:
 *  - No checked links yet          → 'pending'
 *  - 0 problems, 0 redirect chains → A
 *  - 0 problems, redirect chains   → B
 *  - problems ≤ 5% of checked      → C
 *  - problems ≤ 15%                → D
 *  - more                          → F
 *  - Stale data (last full scan older than twice the scan interval,
 *    minimum 2 days) degrades the grade one letter — a grade you can't
 *    trust shouldn't look pristine.
 *
 * @package 404Zen
 */

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

class LGBF_Grade {

	const LETTERS = array( 'A', 'B', 'C', 'D', 'F' );

	/**
	 * Computes the letter grade.
	 *
	 * @param array $counts             Status counts (ok, broken, timeout, redirect, …).
	 * @param int   $last_completed     Unix timestamp of the last full scan (0 = never).
	 * @param int   $frequency_seconds  Configured scan interval in seconds.
	 * @param int   $now                Current unix timestamp.
	 * @return string 'A'|'B'|'C'|'D'|'F'|'pending'
	 */
	public static function compute( $counts, $last_completed, $frequency_seconds, $now ) {
		$ok       = isset( $counts['ok'] ) ? (int) $counts['ok'] : 0;
		$broken   = isset( $counts['broken'] ) ? (int) $counts['broken'] : 0;
		$timeout  = isset( $counts['timeout'] ) ? (int) $counts['timeout'] : 0;
		$redirect = isset( $counts['redirect'] ) ? (int) $counts['redirect'] : 0;

		$problems = $broken + $timeout;
		$checked  = $ok + $problems + $redirect;

		if ( 0 === $checked || ! $last_completed ) {
			return 'pending';
		}

		if ( 0 === $problems ) {
			$grade = ( 0 === $redirect ) ? 'A' : 'B';
		} else {
			$ratio = $problems / $checked;
			if ( $ratio <= 0.05 ) {
				$grade = 'C';
			} elseif ( $ratio <= 0.15 ) {
				$grade = 'D';
			} else {
				$grade = 'F';
			}
		}

		if ( self::is_stale( $last_completed, $frequency_seconds, $now ) ) {
			$grade = self::degrade( $grade );
		}

		return $grade;
	}

	/**
	 * Whether scan data is too old to trust.
	 *
	 * @param int $last_completed    Last full scan timestamp.
	 * @param int $frequency_seconds Scan interval.
	 * @param int $now               Current timestamp.
	 * @return bool
	 */
	public static function is_stale( $last_completed, $frequency_seconds, $now ) {
		$allowance = max( 2 * (int) $frequency_seconds, 2 * DAY_IN_SECONDS );

		return ( $now - (int) $last_completed ) > $allowance;
	}

	/**
	 * One letter worse.
	 *
	 * @param string $grade Letter.
	 * @return string
	 */
	public static function degrade( $grade ) {
		$index = array_search( $grade, self::LETTERS, true );
		if ( false === $index ) {
			return $grade;
		}

		return self::LETTERS[ min( $index + 1, count( self::LETTERS ) - 1 ) ];
	}

	/**
	 * Visual tone for a grade (maps to zen-grade-- modifier classes).
	 *
	 * @param string $grade Letter or 'pending'.
	 * @return string good|warn|bad|pending
	 */
	public static function tone( $grade ) {
		if ( 'A' === $grade || 'B' === $grade ) {
			return 'good';
		}
		if ( 'C' === $grade ) {
			return 'warn';
		}
		if ( 'pending' === $grade ) {
			return 'pending';
		}

		return 'bad';
	}
}
