<?php
/**
 * Builder administration controller.
 *
 * @package EntryFoundry
 */

namespace EntryFoundry\Core\Controllers\Admin;

use EntryFoundry\Core\Models\Template\TemplateRepository;
use EntryFoundry\Core\Views\Admin\BuilderView;
use EntryFoundry\Formidable\FormidableData;

/**
 * Registers and supplies the visual builder admin screen.
 */
final class BuilderAdminController {

	/**
	 * Builder mount view.
	 *
	 * @var BuilderView
	 */
	private $view;

	/**
	 * Template storage model.
	 *
	 * @var TemplateRepository
	 */
	private $templates;

	/**
	 * Neutral Formidable data boundary.
	 *
	 * @var FormidableData
	 */
	private $formidable;

	/**
	 * Per-request template cache.
	 *
	 * @var array<int, array<string, mixed>|null>
	 */
	private $template_cache = array();

	/**
	 * Per-request source label cache.
	 *
	 * @var array<int, string>|null
	 */
	private $source_labels;

	/**
	 * Registered WordPress admin page hook.
	 *
	 * @var string
	 */
	private $page_hook = '';

	/**
	 * Whether this request is rendering the visual builder.
	 *
	 * @var bool
	 */
	private $builder_assets_enqueued = false;

	/**
	 * Constructor.
	 *
	 * @param BuilderView        $view       Builder mount view.
	 * @param TemplateRepository $templates  Template storage model.
	 * @param FormidableData     $formidable Neutral Formidable data boundary.
	 */
	public function __construct( BuilderView $view, TemplateRepository $templates, FormidableData $formidable ) {
		$this->view       = $view;
		$this->templates  = $templates;
		$this->formidable = $formidable;
	}

	/** Register the builder submenu. */
	public function register_menu(): void {
		$this->page_hook = (string) add_submenu_page(
			'edit.php?post_type=' . TemplateRepository::POST_TYPE,
			__( 'Visual Builder', 'entryfoundry-pdf-builder-for-formidable-forms' ),
			__( 'Visual Builder', 'entryfoundry-pdf-builder-for-formidable-forms' ),
			'edit_posts',
			'entryfoundry-builder',
			array( $this, 'render' )
		);
	}

	/**
	 * Redirect the native template add/edit screens to the visual builder.
	 *
	 * @return void
	 */
	public function redirect_native_editor(): void {
		global $pagenow;

		// These read-only route parameters select the admin screen; they do not mutate data.
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$is_new = 'post-new.php' === $pagenow
			&& isset( $_GET['post_type'] )
			&& TemplateRepository::POST_TYPE === sanitize_key( wp_unslash( $_GET['post_type'] ) );

		$template_id = 0;
		if ( 'post.php' === $pagenow && isset( $_GET['post'], $_GET['action'] ) ) {
			$post = get_post( absint( $_GET['post'] ) );
			if ( $post && TemplateRepository::POST_TYPE === $post->post_type && 'edit' === sanitize_key( wp_unslash( $_GET['action'] ) ) ) {
				$template_id = (int) $post->ID;
			}
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		if ( ! $is_new && $template_id < 1 ) {
			return;
		}

		wp_safe_redirect( $this->get_builder_url( $template_id ) );
		exit;
	}

	/**
	 * Enqueue builder assets on the builder page only.
	 *
	 * @param string $hook_suffix Current admin hook.
	 */
	public function enqueue_assets( string $hook_suffix ): void {
		$script_path = ENTRYFOUNDRY_PLUGIN_DIR . 'build/entryfoundry-builder.js';
		$style_path  = ENTRYFOUNDRY_PLUGIN_DIR . 'build/entryfoundry-builder.css';
		$version     = file_exists( $script_path ) ? (string) filemtime( $script_path ) : ENTRYFOUNDRY_VERSION;
		wp_register_style( 'entryfoundry-builder-css', plugins_url( 'build/entryfoundry-builder.css', ENTRYFOUNDRY_PLUGIN_FILE ), array(), file_exists( $style_path ) ? (string) filemtime( $style_path ) : $version );
		wp_register_script( 'entryfoundry-builder', plugins_url( 'build/entryfoundry-builder.js', ENTRYFOUNDRY_PLUGIN_FILE ), array( 'media-editor' ), $version, true );

		if ( $this->page_hook !== $hook_suffix ) {
			return;
		}

		$this->builder_assets_enqueued = true;
		wp_enqueue_style( 'entryfoundry-builder-css' );
		wp_enqueue_media();
		wp_add_inline_script( 'underscore', 'window.entryfoundryWordPressUnderscore = window._;', 'after' );
		wp_add_inline_script( 'shortcode', 'if ( window.entryfoundryWordPressUnderscore ) { window._ = window.entryfoundryWordPressUnderscore; }', 'before' );
		wp_enqueue_script( 'entryfoundry-builder' );
		wp_localize_script(
			'entryfoundry-builder',
			'entryfoundryBuilderConfig',
			array(
				'restUrl'            => esc_url_raw( rest_url( 'entryfoundry/v1/' ) ),
				'nonce'              => wp_create_nonce( 'wp_rest' ),
				'isPro'              => function_exists( 'entryfoundry_is_pro' ) && \entryfoundry_is_pro(),
				'initialTemplateId'  => isset( $_GET['template_id'] ) ? absint( $_GET['template_id'] ) : 0, // phpcs:ignore WordPress.Security.NonceVerification.Recommended
				'formidableAdminUrl' => admin_url( 'admin.php?page=formidable&frm_action=edit&id=' ),
				'pluginUrl'          => plugins_url( '', ENTRYFOUNDRY_PLUGIN_FILE ) . '/',
				'siteLogoId'         => $this->get_site_logo_id(),
				'siteLogoUrl'        => $this->get_site_logo_url(),
				'premadeTemplates'   => $this->get_premade_templates(),
			)
		);
	}

	/**
	 * Restore WordPress Underscore after third-party admin footer scripts run.
	 *
	 * Some admin plugins replace the global `_` object after WordPress loads its
	 * own Underscore build. The media modal's DOM-ready callbacks require the
	 * WordPress implementation, so restore the captured instance at the end of
	 * this builder page only.
	 */
	public function restore_wordpress_underscore(): void {
		if ( ! $this->builder_assets_enqueued ) {
			return;
		}

		wp_print_inline_script_tag(
			'if ( window.entryfoundryWordPressUnderscore ) { window._ = window.entryfoundryWordPressUnderscore; delete window.entryfoundryWordPressUnderscore; }',
			array( 'id' => 'entryfoundry-underscore-restore' )
		);
	}

	/** Render the mount point. */
	public function render(): void {
		$this->view->render();
	}

	/**
	 * Add a visual-builder link to template list rows.
	 *
	 * @param array<string, string> $actions Existing row actions.
	 * @param \WP_Post              $post    Current post.
	 * @return array<string, string>
	 */
	public function add_row_action( array $actions, \WP_Post $post ): array {
		if ( TemplateRepository::POST_TYPE !== $post->post_type ) {
			return $actions;
		}

		$url = $this->get_builder_url( (int) $post->ID );

		$actions['entryfoundry_builder'] = sprintf( '<a href="%s">%s</a>', esc_url( $url ), esc_html__( 'Open Visual Builder', 'entryfoundry-pdf-builder-for-formidable-forms' ) );

		return $actions;
	}

	/**
	 * Add form, profile, and discoverable shortcode columns.
	 *
	 * @param array<string, string> $columns Existing template-list columns.
	 * @return array<string, string>
	 */
	public function add_template_columns( array $columns ): array {
		$date = $columns['date'] ?? null;
		unset( $columns['date'] );

		$columns['entryfoundry_form']      = __( 'Form', 'entryfoundry-pdf-builder-for-formidable-forms' );
		$columns['entryfoundry_profile']   = __( 'Profile', 'entryfoundry-pdf-builder-for-formidable-forms' );
		$columns['entryfoundry_shortcode'] = __( 'Shortcode', 'entryfoundry-pdf-builder-for-formidable-forms' );
		if ( null !== $date ) {
			$columns['date'] = $date;
		}
		return $columns;
	}

	/**
	 * Render a template's canonical shortcode.
	 *
	 * @param string $column  Current column.
	 * @param int    $post_id Template post ID.
	 */
	public function render_template_column( string $column, int $post_id ): void {
		if ( 'entryfoundry_shortcode' === $column ) {
			echo '<code>[entryfoundry_template id=&quot;' . esc_attr( (string) $post_id ) . '&quot; entry=&quot;[id]&quot;]</code>';
			return;
		}

		$template = $this->get_template( $post_id );
		if ( ! $template ) {
			echo '&mdash;';
			return;
		}

		if ( 'entryfoundry_form' === $column ) {
			$form_id = (int) ( $template['template']['source']['form_id'] ?? 0 );
			$label   = $this->get_source_labels()[ $form_id ] ?? __( 'Unknown form', 'entryfoundry-pdf-builder-for-formidable-forms' );
			/* translators: %d: Formidable form ID. */
			$form_number = sprintf( __( 'Form #%d', 'entryfoundry-pdf-builder-for-formidable-forms' ), $form_id );
			echo '<strong>' . esc_html( $label ) . '</strong><br><small>' . esc_html( $form_number ) . '</small>';
			return;
		}

		if ( 'entryfoundry_profile' === $column ) {
			$profile = (string) ( $template['template']['profile'] ?? '' );
			echo esc_html( $this->get_profile_label( $profile ) );
		}
	}

	/**
	 * Load and cache one template for list-table columns.
	 *
	 * @param int $post_id Template post ID.
	 * @return array<string, mixed>|null
	 */
	private function get_template( int $post_id ): ?array {
		if ( ! array_key_exists( $post_id, $this->template_cache ) ) {
			try {
				$this->template_cache[ $post_id ] = $this->templates->get( $post_id );
			} catch ( \Exception $exception ) {
				$this->template_cache[ $post_id ] = null;
			}
		}
		return $this->template_cache[ $post_id ];
	}

	/**
	 * Get source labels keyed by Formidable form ID.
	 *
	 * @return array<int, string>
	 */
	private function get_source_labels(): array {
		if ( null !== $this->source_labels ) {
			return $this->source_labels;
		}

		$this->source_labels = array();
		try {
			foreach ( $this->formidable->get_sources() as $source ) {
				$this->source_labels[ (int) $source['id'] ] = (string) $source['label'];
			}
		} catch ( \Exception $exception ) {
			// The stable Form ID remains visible when Formidable is unavailable.
			return $this->source_labels;
		}
		return $this->source_labels;
	}

	/**
	 * Get the readable profile label for a stored profile ID.
	 *
	 * @param string $profile Stored profile ID.
	 * @return string
	 */
	private function get_profile_label( string $profile ): string {
		$labels = array(
			'certificate' => __( 'Certificate', 'entryfoundry-pdf-builder-for-formidable-forms' ),
			'document'    => __( 'Document / Report', 'entryfoundry-pdf-builder-for-formidable-forms' ),
			'receipt'     => __( 'Receipt / Simple Invoice', 'entryfoundry-pdf-builder-for-formidable-forms' ),
			'invoice'     => __( 'Invoice', 'entryfoundry-pdf-builder-for-formidable-forms' ),
			'id-card'     => __( 'ID Card', 'entryfoundry-pdf-builder-for-formidable-forms' ),
		);
		return $labels[ $profile ] ?? ucwords( str_replace( array( '-', '_' ), ' ', $profile ) );
	}

	/**
	 * Get Lite premade template seed definitions.
	 *
	 * @return array<int, array<string, mixed>>
	 */
	private function get_premade_templates(): array {
		$templates = array();
		$paths     = glob( ENTRYFOUNDRY_PLUGIN_DIR . 'templates/lite/*.json' );
		if ( ! is_array( $paths ) ) {
			return $templates;
		}
		sort( $paths );
		foreach ( $paths as $path ) {
			$template = wp_json_file_decode( $path, array( 'associative' => true ) );
			if ( is_array( $template ) && ! empty( $template['name'] ) && ! empty( $template['profile'] ) && ! empty( $template['elements'] ) ) {
				$template['seed_id'] = basename( $path, '.json' );
				$templates[]         = $template;
			}
		}
		/**
		 * Filters premade builder template seeds.
		 *
		 * Add-ons can append their own seed JSON definitions without bundling
		 * paid or platform-specific templates in the Lite plugin.
		 *
		 * @param array<int, array<string, mixed>> $templates Premade template seeds.
		 */
		return apply_filters( 'entryfoundry_premade_templates', $templates );
	}

	/**
	 * Get the active site logo attachment ID.
	 */
	private function get_site_logo_id(): int {
		return function_exists( 'get_theme_mod' ) ? absint( get_theme_mod( 'custom_logo' ) ) : 0;
	}

	/**
	 * Get the active site logo URL for builder previews.
	 */
	private function get_site_logo_url(): string {
		$logo_id = $this->get_site_logo_id();
		if ( $logo_id > 0 ) {
			$url = wp_get_attachment_image_url( $logo_id, 'full' );
			return is_string( $url ) ? $url : '';
		}
		return function_exists( 'get_site_icon_url' ) ? (string) get_site_icon_url( 128 ) : '';
	}

	/**
	 * Point WordPress edit links for templates at the visual builder.
	 *
	 * @param string $link    Native edit link.
	 * @param int    $post_id Post ID.
	 * @return string
	 */
	public function filter_edit_link( string $link, int $post_id ): string {
		$post = get_post( $post_id );
		return $post && TemplateRepository::POST_TYPE === $post->post_type ? $this->get_builder_url( $post_id ) : $link;
	}

	/**
	 * Build the canonical visual-builder URL.
	 *
	 * @param int $template_id Existing template ID, or zero for a new template.
	 * @return string
	 */
	private function get_builder_url( int $template_id = 0 ): string {
		$args = array(
			'post_type' => TemplateRepository::POST_TYPE,
			'page'      => 'entryfoundry-builder',
		);

		if ( $template_id > 0 ) {
			$args['template_id'] = $template_id;
		}

		return add_query_arg( $args, admin_url( 'edit.php' ) );
	}
}
