<?php
/**
 * Preview data factory for Mail Doctor email templates.
 *
 * @package MailDoctor
 */

namespace MailDoctor\Email;

use WC_Order;

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

/**
 * Builds deterministic preview context for live email rendering.
 */
class PreviewDataFactory {

	/**
	 * Build preview context including sample order/customer/store data.
	 *
	 * @param string               $email_id Email identifier.
	 * @param array<string, mixed> $args     Preview arguments (order_id, status, locale).
	 * @return array<string, mixed>
	 */
	public static function make( string $email_id, array $args = array() ): array {
		$email_id     = sanitize_key( $email_id );
		$locale       = isset( $args['locale'] ) ? (string) $args['locale'] : ( function_exists( 'determine_locale' ) ? determine_locale() : get_locale() );
		$order        = self::resolve_order( $args );
		$status       = isset( $args['status'] ) ? sanitize_key( (string) $args['status'] ) : 'processing';
		$preview_mode = ! empty( $args['preview'] );

		$store = self::build_store_snapshot();

		if ( $order instanceof WC_Order ) {
			$customer = array(
				'first_name' => $order->get_billing_first_name(),
				'last_name'  => $order->get_billing_last_name(),
				'full_name'  => $order->get_formatted_billing_full_name(),
				'email'      => $order->get_billing_email(),
				'company'    => $order->get_billing_company(),
				'phone'      => $order->get_billing_phone(),
			);

			$sample = array(
				'order'    => array(),
				'customer' => array(),
				'store'    => $store,
			);
		} elseif ( $preview_mode ) {
			$seed     = $email_id . '|' . $locale . '|' . $status;
			$customer = self::build_sample_customer( $seed );
			$sample   = array(
				'order'    => self::build_sample_order( $seed, $status, $store ),
				'customer' => $customer,
				'store'    => $store,
			);
		} else {
			$customer = array();
			$sample   = array(
				'order'    => array(),
				'customer' => array(),
				'store'    => $store,
			);
		}

		$extra_tokens = array();
		if ( $preview_mode ) {
			$extra_tokens = array(
				'reset_url'     => function_exists( 'wp_lostpassword_url' ) ? wp_lostpassword_url() : site_url( '/my-account/lost-password/' ),
				'customer_note' => self::hash_pick(
					$email_id . '|' . $locale,
					'customer_note',
					array(
						__( 'Thank you for your order! We appreciate your business.', 'mail-doctor' ),
						__( 'Your item is being prepared and will ship soon.', 'mail-doctor' ),
						__( 'We noticed you left feedback - thanks for sharing!', 'mail-doctor' ),
					)
				),
			);
		}

		return array(
			'order'        => $order,
			'customer'     => $customer,
			'store'        => $store,
			'sample'       => $sample,
			'locale'       => $locale,
			'extra_tokens' => $extra_tokens,
		);
	}

	/**
	 * Attempt to load a real order for preview.
	 *
	 * @param array<string, mixed> $args Preview arguments.
	 * @return WC_Order|null
	 */
	protected static function resolve_order( array $args ) {
		if ( isset( $args['order'] ) && $args['order'] instanceof WC_Order ) {
			return $args['order'];
		}

		if ( empty( $args['order_id'] ) ) {
			return null;
		}

		if ( ! function_exists( 'wc_get_order' ) ) {
			return null;
		}

		$order_id = absint( $args['order_id'] );

		if ( ! $order_id ) {
			return null;
		}

		$order = wc_get_order( $order_id );

		return $order instanceof WC_Order ? $order : null;
	}

	/**
	 * Build store metadata snapshot.
	 *
	 * @return array<string, string>
	 */
	protected static function build_store_snapshot(): array {
		$name    = get_bloginfo( 'name' );
		$url     = home_url( '/' );
		$email   = get_option( 'woocommerce_email_from_address', get_option( 'admin_email' ) );
		$logo    = self::resolve_logo_url();
		$brand   = '';
		$logoImg = '';

		if ( $logo ) {
			$logoImg = sprintf(
				'<img src="%1$s" alt="%2$s" style="max-width:200px;height:auto;" />',
				esc_url( $logo ),
				esc_attr( $name )
			);
			$brand   = $logoImg;
		} else {
			$brand = sprintf(
				'<span class="wpmd-brand-text" style="font-weight:700;font-size:20px;">%s</span>',
				esc_html( $name )
			);
		}

		return array(
			'name'     => (string) $name,
			'url'      => (string) $url,
			'email'    => (string) $email,
			'logo_url' => $logo,
			'logo_img' => $logoImg,
			'brand'    => $brand,
		);
	}

	/**
	 * Resolve a logo URL for the store snapshot.
	 *
	 * @return string
	 */
	protected static function resolve_logo_url(): string {
		$logo = (string) get_option( 'woocommerce_email_header_image' );
		if ( $logo ) {
			return esc_url_raw( $logo );
		}

		$custom_logo_id = (int) get_theme_mod( 'custom_logo' );
		if ( $custom_logo_id ) {
			$maybe = wp_get_attachment_image_url( $custom_logo_id, 'full' );
			if ( $maybe ) {
				return esc_url_raw( $maybe );
			}
		}

		$site_icon = get_site_icon_url( 192 );
		if ( $site_icon ) {
			return esc_url_raw( $site_icon );
		}

		return '';
	}

	/**
	 * Build deterministic sample customer data.
	 *
	 * @param string $seed Seed string.
	 * @return array<string, string>
	 */
	protected static function build_sample_customer( string $seed ): array {
		$first = self::hash_pick(
			$seed,
			'first_name',
			array( 'Avery', 'Jordan', 'Riley', 'Dakota', 'Morgan', 'Harper' )
		);
		$last  = self::hash_pick(
			$seed,
			'last_name',
			array( 'Stone', 'Summers', 'Wright', 'Hale', 'Brooks', 'Ellis' )
		);

		$email = strtolower( $first ) . '.' . strtolower( $last ) . '@example.com';

		return array(
			'first_name' => $first,
			'last_name'  => $last,
			'full_name'  => $first . ' ' . $last,
			'email'      => $email,
			'company'    => self::hash_pick(
				$seed,
				'company',
				array( 'Nimbus Co.', 'Aurora Collective', 'Harbor Goods', 'Summit Labs' )
			),
			'phone'      => sprintf( '+1-555-%04d', self::hash_int( $seed, 'phone', 1000, 9999 ) ),
			'nickname'   => $first,
		);
	}

	/**
	 * Build deterministic sample order data (including HTML fragments).
	 *
	 * @param string               $seed  Seed string.
	 * @param string               $status Status slug.
	 * @param array<string,string> $store Store snapshot.
	 * @return array<string, string>
	 */
	protected static function build_sample_order( string $seed, string $status, array $store ): array {
		$order_id = (string) ( 1000 + self::hash_int( $seed, 'order_id', 1, 899 ) );
		$number   = 'WPMD-' . strtoupper( substr( dechex( self::hash_int( $seed, 'order_number', 100000, 999999 ) ), 0, 6 ) );
		$currency = function_exists( 'get_woocommerce_currency' ) ? get_woocommerce_currency() : 'USD';
		$date     = gmdate( 'Y-m-d H:i', time() - self::hash_int( $seed, 'order_age', 1, DAY_IN_SECONDS ) );

		$status_name = function_exists( 'wc_get_order_status_name' )
			? wc_get_order_status_name( $status )
			: ucfirst( $status );

		$items = self::build_sample_items( $seed, $currency );
		$total = array_reduce(
			$items,
			static function ( $carry, $item ) {
				return $carry + (float) $item['total_raw'];
			},
			0.0
		);

		$format_price = static function ( float $amount ) use ( $currency ): string {
			if ( function_exists( 'wc_price' ) ) {
				return (string) wc_price(
					$amount,
					array(
						'currency' => $currency,
					)
				);
			}

			return sprintf( '%s %0.2f', esc_html( $currency ), $amount );
		};

		$billing_lines = array(
			self::hash_pick( $seed, 'billing_name', array( 'Avery Stone', 'Morgan Brooks', 'Dakota Hale' ) ),
			sprintf( '%s %s', self::hash_int( $seed, 'billing_street_num', 120, 980 ), self::hash_pick( $seed, 'billing_street', array( 'Evergreen Way', 'Summit Ave', 'Harbor Street', 'Sunset Blvd' ) ) ),
			sprintf(
				'%s, %s %s',
				self::hash_pick( $seed, 'billing_city', array( 'Portland', 'Seattle', 'Denver', 'Austin' ) ),
				self::hash_pick( $seed, 'billing_state', array( 'OR', 'WA', 'CO', 'TX' ) ),
				self::hash_int( $seed, 'billing_zip', 70000, 99999 )
			),
			self::hash_pick( $seed, 'billing_country', array( 'United States', 'Canada' ) ),
		);

		$shipping_lines = array(
			self::hash_pick( $seed, 'shipping_name', array( 'Jordan Ellis', 'Riley Summers', 'Harper Wright' ) ),
			sprintf( '%s %s', self::hash_int( $seed, 'shipping_street_num', 10, 900 ), self::hash_pick( $seed, 'shipping_street', array( 'Maple Drive', 'Cedar Lane', 'Ocean View', 'Lakefront Way' ) ) ),
			sprintf(
				'%s, %s %s',
				self::hash_pick( $seed, 'shipping_city', array( 'San Francisco', 'Chicago', 'Boston', 'Vancouver' ) ),
				self::hash_pick( $seed, 'shipping_state', array( 'CA', 'IL', 'MA', 'BC' ) ),
				self::hash_int( $seed, 'shipping_zip', 50000, 95555 )
			),
			self::hash_pick( $seed, 'shipping_country', array( 'United States', 'Canada' ) ),
		);

		$items_html = self::build_items_table_html( $items, $currency, $format_price( $total ) );

		$download_links = sprintf(
			'<ul><li><a href="%1$s">%2$s</a></li><li><a href="%3$s">%4$s</a></li></ul>',
			esc_url( home_url( '/download/sample-kit/' ) ),
			esc_html__( 'Sample Design Kit', 'mail-doctor' ),
			esc_url( home_url( '/download/user-guide/' ) ),
			esc_html__( 'User Guide (PDF)', 'mail-doctor' )
		);

		return array(
			'id'               => $order_id,
			'number'           => $number,
			'status'           => $status,
			'status_name'      => $status_name,
			'date'             => $date,
			'currency'         => $currency,
			'total'            => $format_price( $total ),
			'payment_method'   => self::hash_pick(
				$seed,
				'payment_method',
				array( 'Credit Card', 'PayPal', 'Direct Bank Transfer' )
			),
			'shipping_method'  => self::hash_pick(
				$seed,
				'shipping_method',
				array( 'Flat Rate', 'Local Pickup', 'Free Shipping' )
			),
			'items_table'      => $items_html,
			'download_links'   => $download_links,
			'billing_address'  => implode( '<br />', array_map( 'esc_html', $billing_lines ) ),
			'shipping_address' => implode( '<br />', array_map( 'esc_html', $shipping_lines ) ),
			'refund_amount'    => $format_price( 0.00 ),
			'view_url'         => esc_url( home_url( '/my-account/view-order/' . $order_id . '/' ) ),
			'items'            => $items,
			'store'            => $store,
		);
	}

	/**
	 * Build deterministic sample line items.
	 *
	 * @param string $seed     Seed string.
	 * @param string $currency Currency code.
	 * @return array<int, array<string, mixed>>
	 */
	protected static function build_sample_items( string $seed, string $currency ): array {
		$products = array(
			array(
				'name' => __( 'Aurora Lamp', 'mail-doctor' ),
				'sku'  => 'AUR-',
			),
			array(
				'name' => __( 'Harbor Throw', 'mail-doctor' ),
				'sku'  => 'HBR-',
			),
			array(
				'name' => __( 'Summit Mug', 'mail-doctor' ),
				'sku'  => 'SMT-',
			),
			array(
				'name' => __( 'Evergreen Tee', 'mail-doctor' ),
				'sku'  => 'EVG-',
			),
			array(
				'name' => __( 'Cascade Backpack', 'mail-doctor' ),
				'sku'  => 'CSD-',
			),
		);

		$items = array();

		for ( $index = 0; $index < 3; $index++ ) {
			$product = $products[ self::hash_int( $seed, 'item_product_' . $index, 0, count( $products ) - 1 ) ];
			$qty     = self::hash_int( $seed, 'item_qty_' . $index, 1, 3 );
			$price   = self::hash_int( $seed, 'item_price_' . $index, 1200, 8900 ) / 100;
			$total   = $qty * $price;

			$items[] = array(
				'name'      => (string) $product['name'],
				'sku'       => $product['sku'] . self::hash_int( $seed, 'item_sku_' . $index, 100, 999 ),
				'quantity'  => $qty,
				'price'     => $price,
				'total_raw' => $total,
				'currency'  => $currency,
			);
		}

		return $items;
	}

	/**
	 * Render HTML table for sample items.
	 *
	 * @param array<int, array<string, mixed>> $items    Line items.
	 * @param string                           $currency Currency code.
	 * @param string                           $total    Formatted total line.
	 * @return string
	 */
	protected static function build_items_table_html( array $items, string $currency, string $total ): string {
		$rows = '';

		foreach ( $items as $item ) {
			$line_total = self::format_money( (float) $item['total_raw'], $currency );

			$rows .= sprintf(
				'<tr><td style="padding:8px;border-bottom:1px solid #eee;">%1$s<br /><small style="color:#666;">SKU: %2$s</small></td><td style="padding:8px;border-bottom:1px solid #eee;text-align:center;">%3$d</td><td style="padding:8px;border-bottom:1px solid #eee;text-align:right;">%4$s</td></tr>',
				esc_html( $item['name'] ),
				esc_html( $item['sku'] ),
				(int) $item['quantity'],
				esc_html( $line_total )
			);
		}

		$rows .= sprintf(
			'<tr><th colspan="2" style="padding:8px;text-align:right;">%1$s</th><th style="padding:8px;text-align:right;">%2$s</th></tr>',
			esc_html__( 'Order total', 'mail-doctor' ),
			wp_kses_post( $total )
		);

		return sprintf(
			'<table role="presentation" cellpadding="0" cellspacing="0" style="width:100%%;border-collapse:collapse;"><thead><tr><th style="text-align:left;padding:8px;border-bottom:2px solid #333;">%1$s</th><th style="text-align:center;padding:8px;border-bottom:2px solid #333;">%2$s</th><th style="text-align:right;padding:8px;border-bottom:2px solid #333;">%3$s</th></tr></thead><tbody>%4$s</tbody></table>',
			esc_html__( 'Item', 'mail-doctor' ),
			esc_html__( 'Qty', 'mail-doctor' ),
			esc_html__( 'Total', 'mail-doctor' ),
			$rows
		);
	}

	/**
	 * Format a currency string without relying on Woo helpers.
	 *
	 * @param float  $amount   Amount.
	 * @param string $currency Currency code.
	 * @return string
	 */
	protected static function format_money( float $amount, string $currency ): string {
		if ( function_exists( 'wc_price' ) ) {
			return (string) wc_price(
				$amount,
				array(
					'currency' => $currency,
				)
			);
		}

		return sprintf( '%s %0.2f', esc_html( $currency ), $amount );
	}

	/**
	 * Deterministically pick a value from a list using a hash.
	 *
	 * @param string $seed   Seed string.
	 * @param string $key    Context key.
	 * @param array  $values Possible values.
	 * @return string
	 */
	protected static function hash_pick( string $seed, string $key, array $values ): string {
		if ( empty( $values ) ) {
			return '';
		}

		$hash = md5( $seed . '|' . $key );
		$int  = hexdec( substr( $hash, 0, 8 ) );

		return (string) $values[ $int % count( $values ) ];
	}

	/**
	 * Deterministically produce an integer within range.
	 *
	 * @param string $seed Seed string.
	 * @param string $key  Context key.
	 * @param int    $min  Minimum value.
	 * @param int    $max  Maximum value.
	 * @return int
	 */
	protected static function hash_int( string $seed, string $key, int $min, int $max ): int {
		if ( $min >= $max ) {
			return $min;
		}

		$hash = md5( $seed . '|' . $key );
		$int  = hexdec( substr( $hash, 0, 8 ) );

		return ( $int % ( $max - $min + 1 ) ) + $min;
	}
}
