<?php

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

require_once __DIR__ . '/class-content-miner-scoring-exclusions.php';

/** Build the downloadable revüe review workflow bundle from report evidence. */
class Content_Miner_Revue_Workflow_Bundle {
	const VENDOR_DIR = 'vendor/revue-proof-workflow';

	/** @return string */
	public function build_site_brief( array $report, array $pages, array $issue_labels = array() ) {
		$lines = array(
			'# Content Miner Site Brief',
			'',
			sprintf( 'Generated: %s UTC', gmdate( 'c' ) ),
			'',
			'## Summary',
			sprintf( '- Library: %d source pages; %d remembered pages', (int) ( $report['source_total'] ?? 0 ), (int) ( $report['memory_indexed'] ?? 0 ) ),
			sprintf( '- Denominator: %d scored pages; %d inventoried pages excluded. Site readiness averages and recommendation counts apply to scored pages only.', (int) ( $report['scored_count'] ?? 0 ), (int) ( $report['excluded_count'] ?? 0 ) ),
		);
		$input_sources = isset( $report['input_sources'] ) && is_array( $report['input_sources'] ) ? $report['input_sources'] : array();
		$lines[] = sprintf( '- Input sources: %d rendered; %d stored_fallback; %d stored_nonpublic', (int) ( $input_sources['rendered'] ?? 0 ), (int) ( $input_sources['stored_fallback'] ?? 0 ), (int) ( $input_sources['stored_nonpublic'] ?? 0 ) );
		$summary = isset( $report['summary'] ) && is_array( $report['summary'] ) ? $report['summary'] : array();
		$lines[] = sprintf( '- Recommendations: %d keep; %d refresh; %d localize; %d review; %d possible collisions', (int) ( $summary['keep'] ?? 0 ), (int) ( $summary['refresh'] ?? 0 ), (int) ( $summary['localize'] ?? 0 ), (int) ( $summary['review'] ?? 0 ), (int) ( $summary['overlap_pairs'] ?? 0 ) );
		$scores = isset( $report['readiness_scores'] ) && is_array( $report['readiness_scores'] ) ? $report['readiness_scores'] : array();
		if ( $scores ) {
			$lines[] = sprintf( '- Average readiness: SEO %d; AEO %d; GEO %d; AIO %d', (int) ( $scores['seo'] ?? 0 ), (int) ( $scores['aeo'] ?? 0 ), (int) ( $scores['geo'] ?? 0 ), (int) ( $scores['aio'] ?? 0 ) );
		}
		$lines[] = '';
		$lines[] = '## Limitations';
		$lines[] = '- This brief contains bounded report evidence and page-level findings, not full page bodies.';
		$lines[] = '- Honest absence markers such as not_stored and not_measured are preserved verbatim when present.';
		$lines[] = '- Treat missing evidence as missing evidence, not as a zero score or a negative finding.';
		$lines[] = '';
		$lines[] = '## Per-Page Findings';
		if ( empty( $pages ) ) {
			$lines[] = '- No completed page analysis is available in the current report.';
		}
		foreach ( $pages as $page ) {
			if ( is_array( $page ) && ! Content_Miner_Scoring_Exclusions::is_in_scope( $page ) ) {
				continue;
			}
			$lines = array_merge( $lines, $this->page_lines( $page, $issue_labels ) );
		}
		return implode( "\n", $lines ) . "\n";
	}

	/** @return string */
	public function build_readme() {
		return implode(
			"\n",
			array(
				'# Content Miner Review Workflow',
				'',
				'Drop this folder into Claude Code, Codex, or your AI tool and ask it to run the review workflow over `site-brief.md`.',
				'',
				'Use `revue-proof-workflow/SKILL.md` as the workflow instruction source. The brief is generated from this Content Miner scan and preserves honest absence markers exactly as exported.',
				'',
			)
		);
	}

	/** @return string */
	public function build_zip( array $files ) {
		$local = '';
		$central = '';
		$offset = 0;
		foreach ( $files as $name => $body ) {
			$name = ltrim( str_replace( '\\', '/', (string) $name ), '/' );
			$body = (string) $body;
			$crc = crc32( $body );
			$size = strlen( $body );
			$name_length = strlen( $name );
			$local_header = pack( 'VvvvvvVVVvv', 0x04034b50, 20, 0, 0, 0, 0, $crc, $size, $size, $name_length, 0 ) . $name;
			$central_header = pack( 'VvvvvvvVVVvvvvvVV', 0x02014b50, 20, 20, 0, 0, 0, 0, $crc, $size, $size, $name_length, 0, 0, 0, 0, 0, $offset ) . $name;
			$local .= $local_header . $body;
			$central .= $central_header;
			$offset += strlen( $local_header ) + $size;
		}
		return $local . $central . pack( 'VvvvvVVv', 0x06054b50, 0, 0, count( $files ), count( $files ), strlen( $central ), strlen( $local ), 0 );
	}

	/** @return array<string,string> */
	public function workflow_files() {
		$root = CONTENT_MINER_DIR . self::VENDOR_DIR . '/';
		$files = array();
		foreach ( array_merge( array( 'SKILL.md', 'SOURCE_COMMIT.txt' ), glob( $root . 'references/*.md' ) ?: array() ) as $path ) {
			$source = 0 === strpos( $path, $root ) ? $path : $root . $path;
			if ( is_readable( $source ) ) {
				$relative = 0 === strpos( $source, $root ) ? substr( $source, strlen( $root ) ) : basename( $source );
				$files[ 'review-workflow/revue-proof-workflow/' . $relative ] = file_get_contents( $source );
			}
		}
		return $files;
	}

	/** @return string[] */
	private function page_lines( array $page, array $issue_labels ) {
		$title = $this->clean( $page['title'] ?? '' );
		$path = $this->clean( Content_Miner_Prompt_Page_Evidence::path_from_url( $page['view_url'] ?? '' ) );
		$readiness = isset( $page['readiness'] ) && is_array( $page['readiness'] ) ? $page['readiness'] : array();
		$scores = isset( $readiness['scores'] ) && is_array( $readiness['scores'] ) ? $readiness['scores'] : array();
		$recommendation = isset( $page['recommendation'] ) && is_array( $page['recommendation'] ) ? $page['recommendation'] : array();
		$lines = array(
			'',
			sprintf( '### %s', '' !== $title ? $title : '(Untitled)' ),
			sprintf( '- Source: post_id %d; path %s; status %s; type %s', (int) ( $page['id'] ?? 0 ), '' !== $path ? $path : '/', $this->clean( $page['status'] ?? '' ), $this->clean( $page['post_type'] ?? '' ) ),
			sprintf( '- Recommendation: %s; reason: %s', $this->clean( $recommendation['action'] ?? 'Review' ), $this->clean( $recommendation['reason'] ?? '' ) ),
			sprintf( '- Readiness: SEO %d; AEO %d; GEO %d; AIO %d', (int) ( $scores['seo'] ?? 0 ), (int) ( $scores['aeo'] ?? 0 ), (int) ( $scores['geo'] ?? 0 ), (int) ( $scores['aio'] ?? 0 ) ),
		);
		$issues = isset( $readiness['issues'] ) && is_array( $readiness['issues'] ) ? $readiness['issues'] : array();
		if ( $issues ) {
			$labels = array();
			foreach ( $issues as $issue ) {
				$labels[] = $issue_labels[ $issue ] ?? $issue;
			}
			$lines[] = '- Findings: ' . $this->clean( implode( '; ', $labels ) );
		}
		$signals = isset( $page['signals'] ) && is_array( $page['signals'] ) ? $page['signals'] : array();
		$evidence = isset( $readiness['evidence'] ) && is_array( $readiness['evidence'] ) ? $readiness['evidence'] : array();
		foreach ( array( 'author_source', 'published_source', 'modified_source' ) as $key ) {
			if ( array_key_exists( $key, $signals ) && '' !== (string) $signals[ $key ] ) {
				$lines[] = sprintf( '- Evidence %s: %s', $key, $this->clean( $signals[ $key ] ) );
			}
		}
		if ( array_key_exists( 'direct_answer_span', $evidence ) && array_key_exists( 'direct_answer_passed', $evidence ) && null !== $evidence['direct_answer_passed'] && '' !== (string) $evidence['direct_answer_span'] ) {
			$lines[] = '- Evidence direct_answer_excerpt: ' . Content_Miner_Prompt_Page_Evidence::excerpt( $evidence['direct_answer_span'] );
		}
		$not_measured = isset( $readiness['not_measured'] ) && is_array( $readiness['not_measured'] ) ? $readiness['not_measured'] : array();
		if ( $not_measured ) {
			$lines[] = '- Honest absence: ' . wp_json_encode( $not_measured );
		}
		$input_source = isset( $page['analysis_content_source'] ) ? (string) $page['analysis_content_source'] : 'stored_fallback';
		$lines[] = '- Analysis input: ' . $this->clean( $input_source );
		if ( isset( $page['verification']['fallback_reason_code'] ) && '' !== (string) $page['verification']['fallback_reason_code'] ) {
			$lines[] = '- Input warning: rendered fetch unavailable (' . $this->clean( $page['verification']['fallback_reason_code'] ) . ')';
		}
		return $lines;
	}

	/** @return string */
	private function clean( $value ) {
		$value = wp_strip_all_tags( (string) $value );
		return trim( preg_replace( '/\s+/u', ' ', $value ) );
	}
}
