<?php
/**
 * Signed document response controller.
 *
 * @package EntryFoundry
 */

namespace EntryFoundry\Core\Controllers;

// Constructor and hook method types define this focused controller contract.
// phpcs:disable Squiz.Commenting, Generic.Commenting.DocComment

use EntryFoundry\Core\Models\Template\TemplateRepository;
use EntryFoundry\Core\Services\Generation\DocumentGenerationService;
use EntryFoundry\Core\Services\Security\SignedUrlService;
use RuntimeException;

/** Validates signed URLs and streams generated documents. */
final class DocumentController {
	private const ROUTE_VERSION = '1';
	/** @var DocumentGenerationService */ private $generation;
	/** @var SignedUrlService */ private $signer;
	/** @var TemplateRepository */ private $templates;

	public function __construct( DocumentGenerationService $generation, SignedUrlService $signer, TemplateRepository $templates ) {
		$this->generation = $generation;
		$this->signer     = $signer;
		$this->templates  = $templates;
	}

	/** Register the public document paths. */
	public function register_routes(): void {
		add_rewrite_rule(
			'^entryfoundry/(download|view)/([0-9]+)/([0-9]+)/?$',
			'index.php?entryfoundry_document=1&entryfoundry_disposition=$matches[1]&entryfoundry_template_id=$matches[2]&entryfoundry_entry_id=$matches[3]',
			'top'
		);

		if ( self::ROUTE_VERSION !== get_option( 'entryfoundry_document_route_version' ) ) {
			flush_rewrite_rules( false );
			update_option( 'entryfoundry_document_route_version', self::ROUTE_VERSION, false );
		}
	}

	/** @param array<int,string> $vars Public query variables. @return array<int,string> */
	public function register_query_vars( array $vars ): array {
		return array_merge( $vars, array( 'entryfoundry_document', 'entryfoundry_disposition', 'entryfoundry_template_id', 'entryfoundry_entry_id' ) );
	}

	/** Stream a document selected through the public path. */
	public function handle_pretty_route(): void {
		if ( ! get_query_var( 'entryfoundry_document' ) ) {
			return;
		}

		// The HMAC signature and expiry are the request nonce for this read-only URL.
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$args = array(
			'action'      => 'entryfoundry_document',
			'template_id' => absint( get_query_var( 'entryfoundry_template_id' ) ),
			'entry_id'    => absint( get_query_var( 'entryfoundry_entry_id' ) ),
			'format'      => 'pdf',
			'disposition' => sanitize_key( (string) get_query_var( 'entryfoundry_disposition' ) ),
			'expires'     => isset( $_GET['expires'] ) ? absint( $_GET['expires'] ) : 0,
			'signature'   => isset( $_GET['signature'] ) ? sanitize_text_field( wp_unslash( $_GET['signature'] ) ) : '',
		);
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
		$this->serve( $args );
	}

	public function handle(): void {
		// The HMAC signature and expiry are the request nonce for this read-only URL.
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$args = array(
			'action'      => 'entryfoundry_document',
			'template_id' => isset( $_GET['template_id'] ) ? absint( $_GET['template_id'] ) : 0,
			'entry_id'    => isset( $_GET['entry_id'] ) ? absint( $_GET['entry_id'] ) : 0,
			'format'      => isset( $_GET['format'] ) ? sanitize_key( wp_unslash( $_GET['format'] ) ) : '',
			'disposition' => isset( $_GET['disposition'] ) ? sanitize_key( wp_unslash( $_GET['disposition'] ) ) : '',
			'expires'     => isset( $_GET['expires'] ) ? absint( $_GET['expires'] ) : 0,
			'signature'   => isset( $_GET['signature'] ) ? sanitize_text_field( wp_unslash( $_GET['signature'] ) ) : '',
		);
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
		$this->serve( $args );
	}

	/** @param array<string,mixed> $args Signed document arguments. */
	private function serve( array $args ): void {
		if ( ! in_array( $args['disposition'], array( 'view', 'download' ), true ) || ! $this->signer->validate( $args ) || ! $this->authorized( (int) $args['template_id'] ) ) {
			wp_die( esc_html__( 'This EntryFoundry link is invalid or you do not have access.', 'entryfoundry-pdf-builder-for-formidable-forms' ), '', array( 'response' => 403 ) ); }
		try {
			if ( 'html' === $args['format'] ) {
				header( 'Content-Type: text/html; charset=UTF-8' );
				// Shared renderer escapes all entry values and template text.
				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				echo $this->generation->render_html( $args['template_id'], $args['entry_id'] );
				exit; }
			$path = $this->generation->generate_pdf( $args['template_id'], $args['entry_id'] );
			header( 'Content-Type: application/pdf' );
			header( 'Content-Disposition: ' . ( 'download' === $args['disposition'] ? 'attachment' : 'inline' ) . '; filename="entryfoundry-' . $args['template_id'] . '-' . $args['entry_id'] . '.pdf"' );
			header( 'Content-Length: ' . filesize( $path ) );
			readfile( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile
			exit;
		} catch ( RuntimeException $exception ) {
			wp_die( esc_html__( 'EntryFoundry could not generate this document.', 'entryfoundry-pdf-builder-for-formidable-forms' ), '', array( 'response' => 500 ) ); }
	}

	private function authorized( int $template_id ): bool {
		$stored = $this->templates->get( $template_id );
		if ( ! $stored ) {
			return false; }
		$mode = sanitize_key( $stored['template']['access_mode'] ?? 'private' );
		return 'public-token' === $mode || current_user_can( 'edit_post', $template_id );
	}
}
