<?php
/**
 * Bootstrap and registration hooks for email templates.
 *
 * @package MailDoctor
 */

namespace MailDoctor;

use MailDoctor\Email\CacheService;
use MailDoctor\Email\OverrideResolver;
use MailDoctor\Email\TemplateHistory;
use WP_Post;

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

/**
 * Initialisation routines for the templates controller.
 */
trait WPMD_Email_Templates_Init {


	/**
	 * Register runtime hooks.
	 *
	 * @return void
	 */
	public static function init(): void {
		if ( self::$bootstrapped ) {
			return;
		}

		self::$bootstrapped = true;
		self::$init_ran_at  = time();

		add_action( 'init', 'mail_doctor_register_cpt_tax' );
		add_action( 'init', array( __CLASS__, 'ensure_default_option' ), 5 );
		add_action( 'init', array( __CLASS__, 'register_meta_fields' ), 20 );
		add_action( 'save_post_' . self::CPT, array( __CLASS__, 'enforce_single_active_template' ), 10, 3 );
		add_action( 'delete_post', array( __CLASS__, 'flush_template_cache_on_delete' ) );

		// Register subject/heading filters before Woo builds the email queue.
		add_action( 'woocommerce_init', array( __CLASS__, 'register_email_filters' ), 5 );
		add_action( 'woocommerce_email', array( __CLASS__, 'capture_email_context' ), 1, 1 );
		add_action( 'woocommerce_email_sent', array( __CLASS__, 'release_email_context' ), 20 );
		add_action( 'woocommerce_email_after_send', array( __CLASS__, 'release_email_context' ), 20 );
		// WooCommerce 8.x passes ($message, $email, $plain_text).
		add_filter( 'woocommerce_mail_content', array( __CLASS__, 'filter_mail_content' ), 10, 3 );

		add_filter( 'woocommerce_locate_template', 'mail_doctor_locate_template', 10, 3 );
		add_action( 'admin_menu', 'mail_doctor_register_templates_menu' );
		add_action( 'admin_init', array( __CLASS__, 'register_admin_ajax' ), 20 );

		add_filter( 'woocommerce_admin_status_tabs', array( __CLASS__, 'register_status_tab' ) );
		add_action( 'woocommerce_admin_status_content_mail_doctor_email_overrides', array( __CLASS__, 'render_status_panel' ) );

		add_action( 'update_option_' . self::OPTION_ENABLE, array( __CLASS__, 'flush_template_cache' ), 10, 2 );
	}

	/**
	 * Register subject/heading filters once Woo mailer is ready.
	 *
	 * @return void
	 */
	public static function register_email_filters(): void {
		if ( self::$filters_ran_at ) {
			return;
		}

		if ( ! self::is_enabled() || ! class_exists( 'WC_Email' ) ) {
			return;
		}

		self::$filters_ran_at = time();

		foreach ( self::get_supported_email_types() as $email_type => $label ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
			add_filter(
				'woocommerce_email_subject_' . $email_type,
				array( __CLASS__, 'filter_email_subject' ),
				10,
				2
			);

			add_filter(
				'woocommerce_email_heading_' . $email_type,
				array( __CLASS__, 'filter_email_heading' ),
				10,
				2
			);
		}
	}

	/**
	 * Ensure the enable option exists.
	 *
	 * @return void
	 */
	public static function ensure_default_option(): void {
		if ( false === get_option( self::OPTION_ENABLE, false ) ) {
			add_option( self::OPTION_ENABLE, true, '', false );
		}
	}

	/**
	 * Register template CPT and related tax/meta.
	 *
	 * @return void
	 */
	public static function register_content_types(): void {
		$labels = array(
			'name'               => esc_html__( 'Email Templates', 'mail-doctor' ),
			'singular_name'      => esc_html__( 'Email Template', 'mail-doctor' ),
			'add_new'            => esc_html__( 'Add New', 'mail-doctor' ),
			'add_new_item'       => esc_html__( 'Add New Email Template', 'mail-doctor' ),
			'edit_item'          => esc_html__( 'Edit Email Template', 'mail-doctor' ),
			'new_item'           => esc_html__( 'New Email Template', 'mail-doctor' ),
			'view_item'          => esc_html__( 'View Email Template', 'mail-doctor' ),
			'search_items'       => esc_html__( 'Search Email Templates', 'mail-doctor' ),
			'not_found'          => esc_html__( 'No templates found.', 'mail-doctor' ),
			'not_found_in_trash' => esc_html__( 'No templates found in Trash.', 'mail-doctor' ),
		);

		$args = array(
			'labels'              => $labels,
			'public'              => false,
			'exclude_from_search' => true,
			'show_ui'             => true,
			'show_in_menu'        => false,
			'supports'            => array( 'title', 'revisions' ),
			'capability_type'     => 'post',
			'map_meta_cap'        => true,
		);

		register_post_type( self::CPT, $args );
	}

	/**
	 * Register custom meta keys for the CPT.
	 *
	 * @return void
	 */
	public static function register_meta_fields(): void {
		register_post_meta(
			self::CPT,
			self::META_EMAIL_TYPE,
			array(
				'type'              => 'string',
				'single'            => true,
				'show_in_rest'      => false,
				'default'           => '',
				'sanitize_callback' => array( __CLASS__, 'sanitize_email_type' ),
				'auth_callback'     => array( __CLASS__, 'meta_capability' ),
			)
		);

		register_post_meta(
			self::CPT,
			self::META_SUBJECT,
			array(
				'type'              => 'string',
				'single'            => true,
				'default'           => '',
				'sanitize_callback' => array( __CLASS__, 'sanitize_line_field' ),
				'auth_callback'     => array( __CLASS__, 'meta_capability' ),
			)
		);

		register_post_meta(
			self::CPT,
			self::META_HEADING,
			array(
				'type'              => 'string',
				'single'            => true,
				'default'           => '',
				'sanitize_callback' => array( __CLASS__, 'sanitize_line_field' ),
				'auth_callback'     => array( __CLASS__, 'meta_capability' ),
			)
		);

		register_post_meta(
			self::CPT,
			self::META_BODY,
			array(
				'type'              => 'string',
				'single'            => true,
				'default'           => '',
				'sanitize_callback' => array( __CLASS__, 'sanitize_html_field' ),
				'auth_callback'     => array( __CLASS__, 'meta_capability' ),
			)
		);

		register_post_meta(
			self::CPT,
			self::META_CSS,
			array(
				'type'              => 'string',
				'single'            => true,
				'default'           => '',
				'sanitize_callback' => array( __CLASS__, 'sanitize_css_field' ),
				'auth_callback'     => array( __CLASS__, 'meta_capability' ),
			)
		);

		register_post_meta(
			self::CPT,
			self::META_ACTIVE,
			array(
				'type'              => 'boolean',
				'single'            => true,
				'default'           => true,
				'sanitize_callback' => array( __CLASS__, 'sanitize_bool_field' ),
				'auth_callback'     => array( __CLASS__, 'meta_capability' ),
			)
		);
	}

	/**
	 * Add diagnostics tab within WooCommerce → Status.
	 *
	 * @param array<string,string> $tabs Existing tabs.
	 * @return array<string,string>
	 */
	public static function register_status_tab( array $tabs ): array {
		$tabs['mail_doctor_email_overrides'] = esc_html__( 'Email Overrides (WPMD)', 'mail-doctor' );

		return $tabs;
	}

	/**
	 * Render diagnostics panel output.
	 *
	 * @return void
	 */
	public static function render_status_panel(): void {
		if ( ! current_user_can( 'manage_woocommerce' ) && ! current_user_can( 'manage_options' ) ) {
			return;
		}

		$plugin_version     = defined( 'MAIL_DOCTOR_VERSION' ) ? MAIL_DOCTOR_VERSION : esc_html__( 'Unknown', 'mail-doctor' );
		$woo_version        = defined( 'WC_VERSION' ) ? WC_VERSION : esc_html__( 'WooCommerce inactive', 'mail-doctor' );
		$php_version        = PHP_VERSION;
		$cache_diagnostics  = CacheService::diagnostics();
		$db_version         = (int) get_option( 'mail_doctor_db_version', 0 );
		$last_migration     = (int) get_option( 'mail_doctor_db_version_migrated_at', 0 );
		$last_rollback      = TemplateHistory::last_rollback();
		$last_rollback_text = empty( $last_rollback )
			? __( 'Never', 'mail-doctor' )
			: sprintf(
				'%1$s (%2$s)',
				self::format_timestamp( isset( $last_rollback['timestamp'] ) ? (int) $last_rollback['timestamp'] : null ),
				$last_rollback['version_id'] ?? '—'
			);
		$last_preview_time  = get_option( 'mail_doctor_preview_last_render_ms', 0 );

		$email_types = self::get_supported_email_types();
		$selected    = isset( $_GET['mail_doctor_diag_email'] ) ? sanitize_key( wp_unslash( $_GET['mail_doctor_diag_email'] ) ) : key( $email_types ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only.
		if ( ! $selected || ! isset( $email_types[ $selected ] ) ) {
			$selected = key( $email_types );
		}

		$locate_template_name = $selected ? self::template_name_from_email_type( $selected ) : '';
		$default_template     = $locate_template_name ? self::default_template_path( $locate_template_name ) : '';
		$located_template     = $locate_template_name ? self::locate_template( $default_template, $locate_template_name, '' ) : esc_html__( 'N/A', 'mail-doctor' );

		$mail_filter = self::mail_content_filter_details();

		echo '<div class="wpmd-status-panel">';
		echo '<h2>' . esc_html__( 'Mail Doctor Email Overrides', 'mail-doctor' ) . '</h2>';
		echo '<table class="widefat striped">';
		echo '<tbody>';
		echo '<tr><th>' . esc_html__( 'Plugin version', 'mail-doctor' ) . '</th><td>' . esc_html( $plugin_version ) . '</td></tr>';
		echo '<tr><th>' . esc_html__( 'WooCommerce version', 'mail-doctor' ) . '</th><td>' . esc_html( $woo_version ) . '</td></tr>';
		echo '<tr><th>' . esc_html__( 'PHP version', 'mail-doctor' ) . '</th><td>' . esc_html( $php_version ) . '</td></tr>';
		echo '<tr><th>' . esc_html__( 'init() ran', 'mail-doctor' ) . '</th><td>' . esc_html( self::format_timestamp( self::$init_ran_at ) ) . '</td></tr>';
		echo '<tr><th>' . esc_html__( 'register_email_filters() ran', 'mail-doctor' ) . '</th><td>' . esc_html( self::format_timestamp( self::$filters_ran_at ) ) . '</td></tr>';
		/* translators: 1: priority, 2: args count */
		echo '<tr><th>' . esc_html__( 'Mail content filter', 'mail-doctor' ) . '</th><td>' . esc_html( sprintf( esc_html__( 'Priority %1$s / accepted args %2$s', 'mail-doctor' ), $mail_filter['priority'], $mail_filter['accepted_args'] ) ) . '</td></tr>';
		echo '<tr><th>' . esc_html__( 'Resolver', 'mail-doctor' ) . '</th><td>' . esc_html( sprintf( '%1$s@%2$s', OverrideResolver::class, OverrideResolver::version() ) ) . '</td></tr>';
		/* translators: 1: version, 2: hits, 3: misses */
		echo '<tr><th>' . esc_html__( 'HTML cache', 'mail-doctor' ) . '</th><td>' . esc_html( sprintf( esc_html__( 'Version %1$s — hits %2$d / misses %3$d', 'mail-doctor' ), CacheService::version(), (int) $cache_diagnostics['hits'], (int) $cache_diagnostics['misses'] ) ) . '</td></tr>';
		/* translators: %s: milliseconds */
		echo '<tr><th>' . esc_html__( 'Last preview render', 'mail-doctor' ) . '</th><td>' . esc_html( sprintf( esc_html__( '%s ms (latest AJAX preview)', 'mail-doctor' ), number_format_i18n( (float) $last_preview_time, 2 ) ) ) . '</td></tr>';
		$db_version_display = $db_version ? (string) $db_version : __( 'Pending', 'mail-doctor' );
		echo '<tr><th>' . esc_html__( 'Database version', 'mail-doctor' ) . '</th><td>' . esc_html( $db_version_display ) . '</td></tr>';
		echo '<tr><th>' . esc_html__( 'Last migration', 'mail-doctor' ) . '</th><td>' . esc_html( self::format_timestamp( $last_migration ?: null ) ) . '</td></tr>';
		echo '<tr><th>' . esc_html__( 'Last rollback', 'mail-doctor' ) . '</th><td>' . esc_html( $last_rollback_text ) . '</td></tr>';
		echo '</tbody>';
		echo '</table>';

		echo '<h3>' . esc_html__( 'Email Hook Status', 'mail-doctor' ) . '</h3>';
		echo '<table class="widefat striped">';
		echo '<thead><tr><th>' . esc_html__( 'Email ID', 'mail-doctor' ) . '</th><th>' . esc_html__( 'Subject hook', 'mail-doctor' ) . '</th><th>' . esc_html__( 'Heading hook', 'mail-doctor' ) . '</th></tr></thead><tbody>';
		foreach ( $email_types as $email_id => $label ) {
			$subject_hook = has_filter( 'woocommerce_email_subject_' . $email_id, array( __CLASS__, 'filter_email_subject' ) ) ? esc_html__( 'Yes', 'mail-doctor' ) : esc_html__( 'No', 'mail-doctor' );
			$heading_hook = has_filter( 'woocommerce_email_heading_' . $email_id, array( __CLASS__, 'filter_email_heading' ) ) ? esc_html__( 'Yes', 'mail-doctor' ) : esc_html__( 'No', 'mail-doctor' );

			echo '<tr><td><strong>' . esc_html( $email_id ) . '</strong><br /><span class="description">' . esc_html( $label ) . '</span></td><td>' . esc_html( $subject_hook ) . '</td><td>' . esc_html( $heading_hook ) . '</td></tr>';
		}
		echo '</tbody></table>';

		if ( ! empty( $email_types ) ) {
			echo '<h3>' . esc_html__( 'Template Resolution (Dry Run)', 'mail-doctor' ) . '</h3>';
			echo '<form method="get" action="">';
			foreach ( array( 'page', 'tab' ) as $param ) {
				if ( isset( $_GET[ $param ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only.
					// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- read-only diagnostic.
					printf( '<input type="hidden" name="%1$s" value="%2$s" />', esc_attr( $param ), esc_attr( sanitize_text_field( wp_unslash( $_GET[ $param ] ) ) ) );
				}
			}
			echo '<label for="mail_doctor_diag_email" class="screen-reader-text">' . esc_html__( 'Email ID', 'mail-doctor' ) . '</label>';
			echo '<select name="mail_doctor_diag_email" id="mail_doctor_diag_email">';
			foreach ( $email_types as $email_id => $label ) {
				printf( '<option value="%1$s" %3$s>%2$s</option>', esc_attr( $email_id ), esc_html( $label ), selected( $selected, $email_id, false ) );
			}
			echo '</select> ';
			submit_button( esc_html__( 'Check', 'mail-doctor' ), 'secondary', '', false );
			echo '</form>';

			echo '<p><strong>' . esc_html__( 'Template name:', 'mail-doctor' ) . '</strong> ' . esc_html( $locate_template_name ?: esc_html__( 'Unknown', 'mail-doctor' ) ) . '</p>';
			echo '<p><strong>' . esc_html__( 'Default path:', 'mail-doctor' ) . '</strong> ' . esc_html( $default_template ?: esc_html__( 'Unavailable', 'mail-doctor' ) ) . '</p>';
			echo '<p><strong>' . esc_html__( 'Located path:', 'mail-doctor' ) . '</strong> ' . esc_html( $located_template ) . '</p>';
		}

		echo '</div>';
	}

	/**
	 * Format a timestamp for display.
	 *
	 * @param int|null $timestamp Timestamp.
	 * @return string
	 */
	protected static function format_timestamp( ?int $timestamp ): string {
		if ( empty( $timestamp ) ) {
			return esc_html__( 'Pending', 'mail-doctor' );
		}

		return wp_date( 'Y-m-d H:i:s', $timestamp );
	}

	/**
	 * Fetch current mail content filter metadata.
	 *
	 * @return array{priority:string,accepted_args:int}
	 */
	protected static function mail_content_filter_details(): array {
		$priority = has_filter( 'woocommerce_mail_content', array( __CLASS__, 'filter_mail_content' ) );
		$accepted = 0;

		if ( $priority && isset( $GLOBALS['wp_filter']['woocommerce_mail_content'] ) && $GLOBALS['wp_filter']['woocommerce_mail_content'] instanceof \WP_Hook ) {
			$hook      = $GLOBALS['wp_filter']['woocommerce_mail_content'];
			$callbacks = $hook->callbacks[ $priority ] ?? array();
			foreach ( $callbacks as $data ) {
				if ( empty( $data['function'] ) || ! is_array( $data['function'] ) ) {
					continue;
				}

				if ( $data['function'][0] === __CLASS__ && 'filter_mail_content' === $data['function'][1] ) {
					$accepted = (int) ( $data['accepted_args'] ?? 0 );
					break;
				}
			}
		}

		return array(
			'priority'      => $priority ? (string) $priority : esc_html__( 'Not attached', 'mail-doctor' ),
			'accepted_args' => $accepted,
		);
	}

	/**
	 * Derive a default WooCommerce template path.
	 *
	 * @param string $template_name Template relative path.
	 * @return string
	 */
	protected static function default_template_path( string $template_name ): string {
		if ( function_exists( 'WC' ) && WC() ) {
			return trailingslashit( WC()->plugin_path() ) . 'templates/' . ltrim( $template_name, '/' );
		}

		return 'woocommerce/templates/' . ltrim( $template_name, '/' );
	}

	/**
	 * Callback to enforce capability checks for meta operations.
	 *
	 * @return bool
	 */
	public static function meta_capability(): bool {
		return current_user_can( 'manage_woocommerce' ) || current_user_can( 'manage_options' );
	}

	/**
	 * Ensure only one template is active per email type.
	 *
	 * @param int     $post_id Post identifier.
	 * @param WP_Post $post    Post object.
	 * @param bool    $update  Whether this is an update.
	 * @return void
	 */
	public static function enforce_single_active_template( int $post_id, WP_Post $post, bool $update ): void {
	 // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
		if ( self::CPT !== $post->post_type ) {
			return;
		}

		$email_type = get_post_meta( $post_id, self::META_EMAIL_TYPE, true );
		$is_active  = (bool) get_post_meta( $post_id, self::META_ACTIVE, true );

		if ( ! $email_type ) {
			return;
		}

		self::clear_template_cache( $email_type );

		if ( ! $is_active ) {
			return;
		}

		$query = get_posts(
			array(
				'post_type'      => self::CPT,
				'post_status'    => 'any',
				'posts_per_page' => -1,
				// phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in
				'post__not_in'   => array( $post_id ),
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
				'meta_query'     => array(
					array(
						'key'   => self::META_EMAIL_TYPE,
						'value' => $email_type,
					),
					array(
						'key'   => self::META_ACTIVE,
						'value' => '1',
					),
				),
			)
		);

		if ( empty( $query ) ) {
			return;
		}

		remove_action( 'save_post_' . self::CPT, array( __CLASS__, 'enforce_single_active_template' ), 10 );

		foreach ( $query as $other ) {
			update_post_meta( (int) $other->ID, self::META_ACTIVE, 0 );
			self::clear_template_cache( $email_type );
		}

		add_action( 'save_post_' . self::CPT, array( __CLASS__, 'enforce_single_active_template' ), 10, 3 );
	}

	/**
	 * Flush template cache when a template is deleted.
	 *
	 * @param int $post_id Post ID.
	 * @return void
	 */
	public static function flush_template_cache_on_delete( int $post_id ): void {
		if ( self::CPT !== get_post_type( $post_id ) ) {
			return;
		}

		CacheService::invalidate_template( (string) $post_id );

		$email_type = get_post_meta( $post_id, self::META_EMAIL_TYPE, true );
		if ( $email_type ) {
			self::clear_template_cache( $email_type );
		}
	}
}
