<?php

namespace Fotogenic_AI;

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

/**
 * Authoritative Review evidence for one prepared Store Queue.
 */
final class Store_Queue_Preflight {
	private Store_Queue_Repo $repo;
	private Workflow_Draft_Normalizer $normalizer;
	private Workflow_Accepted_Authority $authority;
	private Workflow_Preflight $preflight;

	public function __construct(
		?Store_Queue_Repo $repo = null,
		?Workflow_Draft_Normalizer $normalizer = null,
		?Workflow_Accepted_Authority $authority = null,
		?Workflow_Preflight $preflight = null
	) {
		$this->repo       = $repo ?? Store_Queue_Repo::instance();
		$this->normalizer = $normalizer ?? new Workflow_Draft_Normalizer();
		$this->authority  = $authority ?? new Workflow_Accepted_Authority();
		$this->preflight  = $preflight ?? new Workflow_Preflight();
	}

	/** @return array|\WP_Error */
	public function review( array $queue, int $user_id, $accepted_authority = null ) {
		if ( $user_id <= 0 || $user_id !== (int) ( $queue['user_id'] ?? 0 ) ) {
			return Messages::error( 'forbidden', 403 );
		}
		$selected_count = (int) ( $queue['selected_count'] ?? 0 );
		if ( $selected_count < 1 ) {
			return new \WP_Error( 'fotogenic_ai_store_queue_empty', __( 'No eligible Products are available in this queue.', 'fotogenic-ai' ), [ 'status' => 400 ] );
		}

		$first = $this->repo->page_items( (int) $queue['id'], $user_id, 1, 1, 'ready' );
		$item  = $first['items'][0] ?? null;
		$draft = $this->decode_snapshot( $queue['draft_snapshot'] ?? '' );
		if ( ! is_array( $item ) || empty( $draft ) ) {
			return Messages::error( 'server_error', 500 );
		}
		$draft['selection'] = [ 'strategy' => 'explicit', 'selectedIds' => [ (int) $item['subject_id'] ], 'excludedIds' => [], 'query' => [] ];
		$draft_object       = $this->normalizer->rehydrate_normalized( $draft );
		if ( is_wp_error( $draft_object ) ) {
			return $draft_object;
		}
		$child = $this->preflight->evaluate( $draft_object );
		if ( is_wp_error( $child ) ) {
			return $child;
		}

		$outputs_per_item = max( 1, (int) ( $child['totalOutputs'] ?? 0 ) );
		$credits_per_item = (float) ( $child['totalCredits'] ?? 0 );
		$total_outputs    = $selected_count * $outputs_per_item;
		$total_credits    = round( $selected_count * $credits_per_item, 4 );
		$balance          = (float) ( $child['balance'] ?? 0 );
		$source_set       = $this->source_set_fingerprint( (int) $queue['id'], $user_id );
		if ( is_wp_error( $source_set ) ) {
			return $source_set;
		}
		$snapshot_fingerprint = hash(
			'sha256',
			implode( ':', [ (string) $queue['request_fingerprint'], $source_set, (string) $selected_count, (string) $total_outputs ] )
		);
		$evidence = [
			'queueUuid'               => (string) $queue['queue_uuid'],
			'revision'                => (int) $queue['revision'],
			'requestFingerprint'      => (string) $queue['request_fingerprint'],
			'snapshotFingerprint'     => $snapshot_fingerprint,
			'sourceSetFingerprint'    => $source_set,
			'contextFingerprint'      => (string) ( $child['authorityEvidence']['contextFingerprint'] ?? '' ),
			'configurationFingerprint'=> (string) ( $child['authorityEvidence']['configurationFingerprint'] ?? '' ),
			'pricingFingerprint'      => (string) ( $child['authorityEvidence']['pricingFingerprint'] ?? '' ),
			'creditsFingerprint'      => (string) ( $child['authorityEvidence']['creditsFingerprint'] ?? '' ),
			'totalItems'              => $selected_count,
			'totalOutputs'            => $total_outputs,
			'totalCredits'            => $total_credits,
			'balance'                 => $balance,
			'balanceAfter'            => round( $balance - $total_credits, 4 ),
		];
		$proof = null === $accepted_authority
			? $this->authority->issue( $evidence )
			: $this->authority->verify( $accepted_authority, $evidence );
		if ( is_wp_error( $proof ) ) {
			return $proof;
		}

		$current_status = (string) ( $queue['status'] ?? '' );
		if ( in_array( $current_status, [ 'reviewing', 'ready' ], true ) ) {
			$this->repo->update_queue_cas(
				(int) $queue['id'],
				$user_id,
				(int) $queue['revision'],
				[
					'status'                 => 'ready',
					'status_reason'          => '',
					'snapshot_fingerprint'   => $snapshot_fingerprint,
					'expected_output_count'  => $total_outputs,
					'estimated_credits'       => (int) ceil( $total_credits ),
				]
			);
		}

		return [
			'queueUuid'           => (string) $queue['queue_uuid'],
			'revision'            => (int) $queue['revision'],
			'snapshotFingerprint' => $snapshot_fingerprint,
			'selectedCount'       => $selected_count,
			'ineligibleCount'     => (int) ( $queue['ineligible_count'] ?? 0 ),
			'totalOutputs'        => $total_outputs,
			'totalCredits'        => $total_credits,
			'balance'             => $balance,
			'balanceAfter'        => round( $balance - $total_credits, 4 ),
			'pricing'             => $child['pricing'] ?? [],
			'authorityEvidence'   => $child['authorityEvidence'] ?? [],
			'authority'           => $proof,
		];
	}

	/** @return string|\WP_Error */
	private function source_set_fingerprint( int $queue_id, int $user_id ) {
		$context = hash_init( 'sha256' );
		$page    = 1;
		do {
			$result = $this->repo->page_items( $queue_id, $user_id, $page, 48 );
			foreach ( (array) $result['items'] as $item ) {
				if ( 'ready' !== (string) ( $item['status'] ?? '' ) ) {
					continue;
				}
				hash_update( $context, (string) $item['item_ordinal'] . ':' . (string) $item['subject_id'] . ':' . (string) $item['source_fingerprint'] . ';' );
			}
			++$page;
		} while ( $page <= (int) $result['totalPages'] );
		$fingerprint = hash_final( $context );
		return 64 === strlen( $fingerprint ) ? $fingerprint : Messages::error( 'server_error', 500 );
	}

	/** @return array<string, mixed> */
	private function decode_snapshot( $value ): array {
		$decoded = is_string( $value ) ? json_decode( $value, true ) : null;
		return is_array( $decoded ) ? $decoded : [];
	}
}
