<?php
/**
 * Entry document generation service.
 *
 * @package EntryFoundry
 */

namespace EntryFoundry\Core\Services\Generation;

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

use EntryFoundry\Core\Models\Template\TemplateRepository;
use EntryFoundry\Core\Services\Assets\AssetDataUri;
use EntryFoundry\Core\Services\Hydrate\HydratePipeline;
use EntryFoundry\Core\Services\Render\HtmlRenderer;
use EntryFoundry\Core\Services\Render\PdfRenderer;
use EntryFoundry\Core\Views\Render\TemplateView;
use EntryFoundry\Formidable\FormidableData;
use EntryFoundry\Formidable\FormidableFieldPolicy;
use RuntimeException;

/** Hydrates stored templates and generates their HTML/PDF representations. */
final class DocumentGenerationService {
	/** @var TemplateRepository */ private $templates;
	/** @var FormidableData */ private $data;
	/** @var HydratePipeline */ private $hydrate;
	/** @var string */ private $plugin_dir;
	/** @var FormidableFieldPolicy|null */ private $field_policy;

	public function __construct( TemplateRepository $templates, FormidableData $data, HydratePipeline $hydrate, string $plugin_dir, ?FormidableFieldPolicy $field_policy = null ) {
		$this->templates    = $templates;
		$this->data         = $data;
		$this->hydrate      = $hydrate;
		$this->plugin_dir   = $plugin_dir;
		$this->field_policy = $field_policy;
	}

	/** @return array{id:int,title:string,template:array<string,mixed>} */
	public function get_document( int $template_id, int $entry_id ): array {
		$stored = $this->templates->get( $template_id );
		if ( ! $stored ) {
			throw new RuntimeException( 'Template not found.' ); }
		if ( $this->field_policy && $this->field_policy->get_restricted_field_ids( $stored['template'] ) ) {
			throw new RuntimeException( 'EntryFoundry Pro is required to generate a document that uses Pro fields.' );
		}
		$form_id            = (int) $stored['template']['source']['form_id'];
		$stored['template'] = $this->hydrate->hydrate(
			$stored['template'],
			array(
				'entry_id'       => $entry_id,
				'fields'         => $this->data->get_fields( $form_id ),
				'values'         => $this->data->get_entry_values( $form_id, $entry_id ),
				'display_values' => $this->data->get_entry_display_values( $form_id, $entry_id ),
			)
		);
		return $stored;
	}

	public function render_html( int $template_id, int $entry_id ): string {
		return $this->render_html_payload( $template_id, $entry_id )['markup'];
	}

	/** @return array{markup:string,styles:string} */
	public function render_html_payload( int $template_id, int $entry_id ): array {
		$stored = $this->get_document( $template_id, $entry_id );
		$html   = new HtmlRenderer( $this->view() );
		return array(
			'markup' => $html->render( $stored['template'] ),
			'styles' => $html->styles( $stored['template'] ),
		);
	}

	public function generate_pdf( int $template_id, int $entry_id ): string {
		$stored    = $this->get_document( $template_id, $entry_id );
		$uploads   = wp_upload_dir();
		$directory = trailingslashit( $uploads['basedir'] ) . 'entryfoundry';
		if ( ! wp_mkdir_p( $directory ) ) {
			throw new RuntimeException( 'Unable to create the EntryFoundry output directory.' ); }
		$path = trailingslashit( $directory ) . 'entryfoundry-' . $template_id . '-' . $entry_id . '.pdf';
		( new PdfRenderer( $this->view(), $directory ) )->write( $stored['template'], $path );
		return $path;
	}

	private function view(): TemplateView {
		return new TemplateView( new AssetDataUri( $this->plugin_dir ) ); }
}
