<?php
/**
 * Data Digest.
 *
 * Assembles a compact, plain-text snapshot of the site's own SEO state from
 * the plugin's stores (audit, Search Console, cannibalization, link health).
 * Shared by the Weekly Briefing and the "Ask your data" co-pilot so the AI
 * answers from real numbers, not guesses. Each section is guarded so a missing
 * table or unrun module never breaks the digest.
 *
 * @package Platform\Helm\Modules\Ai
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\Ai;

use Platform\Helm\Modules\Content_Auditor\AuditScorer;
use Platform\Helm\Modules\Content_Auditor\AuditStore;
use Platform\Helm\Modules\GSC\GscQueryStore;
use Platform\Helm\Modules\GSC\GscSnapshotStore;
use Platform\Helm\Modules\GSC\GscSync;
use Platform\Helm\Modules\Link_Health\LinkGraphStore;

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

final class DataDigest {

	public static function text(): string {
		$lines   = [];
		$lines[] = 'SITE: ' . (string) wp_parse_url( home_url(), PHP_URL_HOST );

		// Search performance (site totals over time).
		try {
			$hist = ( new GscSnapshotStore() )->history( 0, 30 );
			if ( ! empty( $hist ) ) {
				$latest = end( $hist );
				$c      = (int) $latest['clicks'];
				$im     = (int) $latest['impressions'];
				$line   = 'SEARCH (latest snapshot): ' . number_format( $c ) . ' clicks, ' . number_format( $im ) . ' impressions, avg position ' . number_format( (float) $latest['position'], 1 );
				if ( count( $hist ) >= 2 ) {
					$prev = $hist[ count( $hist ) - 2 ];
					$pc   = (int) $prev['clicks'];
					if ( $pc > 0 ) {
						$d     = (int) round( ( ( $c - $pc ) / $pc ) * 100 );
						$line .= ' (clicks ' . ( $d >= 0 ? '+' : '' ) . $d . '% vs previous snapshot)';
					}
				}
				$lines[] = $line;
			} else {
				$lines[] = 'SEARCH: no snapshot history yet.';
			}
		} catch ( \Throwable $e ) {
			$lines[] = 'SEARCH: data unavailable.';
		}

		// Content audit.
		try {
			$store  = new AuditStore();
			$counts = $store->counts();
			$total  = array_sum( $counts );
			if ( $total > 0 ) {
				$lines[] = 'CONTENT AUDIT (' . $total . ' posts scored): Keep ' . $counts[ AuditScorer::KEEP ]
					. ' · Refresh ' . $counts[ AuditScorer::REFRESH ]
					. ' · Merge ' . $counts[ AuditScorer::MERGE ]
					. ' · Delete ' . $counts[ AuditScorer::DELETE ];
				$top  = $store->query( AuditScorer::REFRESH, 'impressions', 'desc', 1, 5, true );
				$rows = $top['rows'] ?? [];
				if ( ! empty( $rows ) ) {
					$lines[] = 'Top refresh opportunities (highest impressions, not yet handled):';
					$i       = 1;
					foreach ( $rows as $r ) {
						$lines[] = '  ' . $i++ . '. ' . (string) $r['title'] . ' — ' . number_format( (int) $r['impressions'] ) . ' impr, pos ' . number_format( (float) $r['position'], 1 );
					}
				}
			} else {
				$lines[] = 'CONTENT AUDIT: not run yet.';
			}
		} catch ( \Throwable $e ) {
			$lines[] = 'CONTENT AUDIT: data unavailable.';
		}

		// Cannibalization.
		try {
			$groups = ( new GscQueryStore() )->cannibalized_queries( 2, 50, 5 );
			if ( ! empty( $groups ) ) {
				$lines[] = 'CANNIBALIZATION: ' . count( $groups ) . '+ queries with competing pages. Worst:';
				$i       = 1;
				foreach ( $groups as $g ) {
					$lines[] = '  ' . $i++ . '. "' . (string) $g['query'] . '" — ' . (int) $g['pages'] . ' pages, ' . number_format( (int) $g['impressions'] ) . ' impr';
				}
			} else {
				$lines[] = 'CANNIBALIZATION: none above threshold (or no query data).';
			}
		} catch ( \Throwable $e ) {
			$lines[] = 'CANNIBALIZATION: data unavailable.';
		}

		// Internal links.
		try {
			$g       = new LinkGraphStore();
			$lines[] = 'INTERNAL LINKS: ' . $g->count_orphans() . ' orphaned pages, '
				. $g->count_by_type( LinkGraphStore::TYPE_BROKEN ) . ' broken links, '
				. $g->count_by_type( LinkGraphStore::TYPE_REDIRECT ) . ' redirect hops.';
		} catch ( \Throwable $e ) {
			$lines[] = 'INTERNAL LINKS: data unavailable.';
		}

		// Last sync.
		$ls = GscSync::last_sync();
		if ( $ls && ! empty( $ls['time'] ) ) {
			$lines[] = 'LAST SEARCH CONSOLE SYNC: ' . human_time_diff( (int) $ls['time'], time() ) . ' ago ('
				. (int) ( $ls['matched'] ?? 0 ) . ' posts matched).';
		}

		return implode( "\n", $lines );
	}
}
