<?php
/**
 * Shared widget template — header, footer, disclaimer.
 *
 * Used by CRToday_Exchange_Rates_Block and CRToday_Converter_Block to guarantee
 * identical chrome (accent, source label, verified badge, footer,
 * disclaimer dialog) across every widget type.  DRY.
 *
 * @package CRTodayCurrencyBlocks
 */

declare(strict_types=1);

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

final class CRToday_Widget_Template {

	private static function disclaimer_text(): string {
		return __('Exchange rates are for informational purposes only and may differ from actual market rates. Data is sourced from third-party providers (aggregator: CurrencyRate.Today) and may be delayed. Do not use for financial transactions without independent verification.', 'currencyrate-today-currency-blocks');
	}

	/* ================================================================
	 * Header
	 * ================================================================ */

	/**
	 * Build the shared widget header.
	 *
	 * @param string $left_html   Arbitrary HTML for the left side (e.g. base flag + label, or empty).
	 * @param string $source_label  Resolved source label text.
	 * @param bool   $is_verified   Whether to show the verified badge.
	 */
	public static function build_header(string $left_html, string $source_label, bool $is_verified): string {
		$escaped_source_label = esc_html($source_label);

		return sprintf(
			'<div class="crtoday-header">%s<span class="crtoday-source-label">%s<span class="crtoday-source-label-text" data-text="%s">%s</span></span></div>',
			$left_html,
			$is_verified ? self::build_verified_badge() : '',
			esc_attr($source_label),
			$escaped_source_label
		);
	}

	/**
	 * Verified badge SVG.
	 */
	public static function build_verified_badge(): string {
		return '<svg class="crtoday-verified-badge" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">'
			. '<path fill="currentColor" fill-rule="evenodd" d="M15.418 5.643a1.25 1.25 0 0 0-1.34-.555l-1.798.413a1.25 1.25 0 0 1-.56 0l-1.798-.413a1.25 1.25 0 0 0-1.34.555l-.98 1.564c-.1.16-.235.295-.395.396l-1.564.98a1.25 1.25 0 0 0-.555 1.338l.413 1.8a1.25 1.25 0 0 1 0 .559l-.413 1.799a1.25 1.25 0 0 0 .555 1.339l1.564.98c.16.1.295.235.396.395l.98 1.564c.282.451.82.674 1.339.555l1.798-.413a1.25 1.25 0 0 1 .56 0l1.799.413a1.25 1.25 0 0 0 1.339-.555l.98-1.564c.1-.16.235-.295.395-.395l1.565-.98a1.25 1.25 0 0 0 .554-1.34L18.5 12.28a1.25 1.25 0 0 1 0-.56l.413-1.799a1.25 1.25 0 0 0-.554-1.339l-1.565-.98a1.25 1.25 0 0 1-.395-.395zm-.503 4.127a.5.5 0 0 0-.86-.509l-2.615 4.426l-1.579-1.512a.5.5 0 1 0-.691.722l2.034 1.949a.5.5 0 0 0 .776-.107z" clip-rule="evenodd"/>'
			. '</svg>';
	}

	/* ================================================================
	 * Footer
	 * ================================================================ */

	/**
	 * Build the shared widget footer.
	 *
	 * Layout: [Optional attribution link] ··· [Disclaimer · Timestamp]
	 */
	public static function build_footer(bool $show_timestamp, string $timestamp, bool $show_attribution = false): string {
		$source_link = sprintf(
			'<span class="crtoday-source-link">%s</span>',
			esc_html__('Source', 'currencyrate-today-currency-blocks')
		);
		if ($show_attribution) {
			$source_link = sprintf(
				'<a class="crtoday-source-link" href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
				esc_url('https://currencyrate.today/'),
				esc_html__('CurrencyRate', 'currencyrate-today-currency-blocks')
			);
		}

		$disclaimer_btn = sprintf(
			'<button type="button" class="crtoday-disclaimer-btn" '
			. 'data-crtoday-disclaimer="%1$s" '
			. 'data-crtoday-plugin-url="%2$s" '
			. 'aria-label="%3$s">%4$s</button>',
			esc_attr(self::disclaimer_text()),
			esc_attr('https://currencyrate.today/'),
			esc_attr(__('Disclaimer', 'currencyrate-today-currency-blocks')),
			esc_html(__('Disclaimer', 'currencyrate-today-currency-blocks'))
		);

		$timestamp_html = ($show_timestamp && $timestamp !== '')
			? sprintf(
				'<span class="crtoday-timestamp">%s</span>',
				esc_html(self::format_timestamp($timestamp))
			)
			: '';

		$right = implode('', array_filter([$disclaimer_btn, $timestamp_html]));

		return sprintf(
			'<div class="crtoday-footer"><div class="crtoday-footer-left">%s</div><div class="crtoday-footer-right">%s</div></div>',
			$source_link,
			$right
		);
	}

	/* ================================================================
	 * Disclaimer Dialog
	 * ================================================================ */

	public static function build_disclaimer_dialog(bool $show_attribution = false): string {
		$links_html = '';
		if ($show_attribution) {
			$links_html = sprintf(
				'<div class="crtoday-disclaimer-links"><a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a></div>',
				esc_url('https://wordpress.org/plugins/currencyrate-today-currency-blocks/'),
				esc_html(__('Plugin page', 'currencyrate-today-currency-blocks'))
			);
		}

		return sprintf(
			'<dialog class="crtoday-disclaimer-dialog">'
			. '<div class="crtoday-disclaimer-dialog-inner">'
			. '<div class="crtoday-disclaimer-dialog-header">'
			.   '<strong>%1$s</strong>'
			.   '<button type="button" class="crtoday-disclaimer-close" aria-label="%2$s">&times;</button>'
			. '</div>'
			. '<p class="crtoday-disclaimer-text">%3$s</p>'
			. '%4$s'
			. '</div>'
			. '</dialog>',
			esc_html(__('Disclaimer', 'currencyrate-today-currency-blocks')),
			esc_attr(__('Close', 'currencyrate-today-currency-blocks')),
			esc_html(self::disclaimer_text()),
			$links_html
		);
	}

	public static function build_disclaimer_script(): string {
		static $printed = false;
		if ($printed) {
			return '';
		}
		$printed = true;

		$js = '(function(){'
			. 'document.addEventListener("click",function(e){'
			.   'var btn=e.target.closest(".crtoday-disclaimer-btn");'
			.   'if(btn){'
			.     'var d=btn.closest(".crtoday-widget").querySelector(".crtoday-disclaimer-dialog");'
			.     'if(d&&d.showModal)d.showModal();'
			.   '}'
			.   'var cl=e.target.closest(".crtoday-disclaimer-close");'
			.   'if(cl){'
			.     'var dlg=cl.closest("dialog");'
			.     'if(dlg&&dlg.close)dlg.close();'
			.   '}'
			.   'var bg=e.target.closest(".crtoday-disclaimer-dialog");'
			.   'if(bg&&e.target===bg&&bg.close)bg.close();'
			. '});'
			. '})();';

		wp_add_inline_script('crtoday-currency-converter-frontend', $js);

		return '';
	}

	/* ================================================================
	 * Structured data
	 * ================================================================ */

	/**
	 * Build deterministic JSON-LD graph with ExchangeRateSpecification entries.
	 *
	 * @param list<array{base:string,quote:string,rateType:string,price:float|int|string,validFrom:string,referenceValue?:float|int|string}> $items
	 */
	public static function build_exchange_rate_json_ld(array $items): string {
		$graph = [];

		foreach ($items as $item) {
			$base = strtoupper((string) ($item['base'] ?? ''));
			$quote = strtoupper((string) ($item['quote'] ?? ''));
			$rate_type = strtolower((string) ($item['rateType'] ?? 'mid'));
			$valid_from = (string) ($item['validFrom'] ?? '');
			$price = (float) ($item['price'] ?? 0);
			$reference_value = (float) ($item['referenceValue'] ?? 1);

			if (preg_match('/^[A-Z]{3}$/', $base) !== 1 || preg_match('/^[A-Z]{3}$/', $quote) !== 1) {
				continue;
			}

			if (! in_array($rate_type, ['mid', 'bid', 'ask', 'effective'], true)) {
				$rate_type = 'mid';
			}

			if ($price <= 0 || $reference_value <= 0 || $valid_from === '') {
				continue;
			}

			$page_url = self::structured_data_page_url();
			$spec_id = $page_url . '#crtoday-rate-' . strtolower($base . '-' . $quote . '-' . $rate_type);

			$graph[] = [
				'@type'    => 'ExchangeRateSpecification',
				'@id'      => $spec_id,
				'name'     => sprintf('%s to %s %s exchange rate', $base, $quote, $rate_type),
				'currency' => $base,
				'currentExchangeRate' => [
					'@type'         => 'UnitPriceSpecification',
					'price'         => $price,
					'priceCurrency' => $quote,
					'referenceQuantity' => [
						'@type'    => 'QuantitativeValue',
						'value'    => $reference_value,
						'unitText' => $base,
					],
					'validFrom' => $valid_from,
				],
			];
		}

		if ($graph === []) {
			return '';
		}

		usort(
			$graph,
			static function (array $left, array $right): int {
				return strcmp((string) ($left['@id'] ?? ''), (string) ($right['@id'] ?? ''));
			}
		);

		$payload = wp_json_encode([
			'@context' => 'https://schema.org',
			'@graph'   => $graph,
		], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

		if (! is_string($payload) || $payload === '') {
			return '';
		}

		return '<script type="application/ld+json">' . $payload . '</script>';
	}

	private static function structured_data_page_url(): string {
		$page_url = '';

		if (function_exists('is_singular') && is_singular()) {
			$permalink = get_permalink();
			if (is_string($permalink)) {
				$page_url = $permalink;
			}
		}

		if ($page_url === '') {
			$page_url = home_url('/');
		}

		return untrailingslashit($page_url);
	}

	/* ================================================================
	 * Helpers
	 * ================================================================ */

	/**
	 * Resolve source label + verified flag from settings.
	 *
	 * @param string $source_id   Block's sourceId attribute.
	 * @param string $deal        Block's deal attribute.
	 * @param string $label_override Per-block label override (empty → auto).
	 * @return array{label: string, verified: bool}
	 */
	public static function resolve_source_label(string $source_id, string $deal, string $label_override): array {
		$resolved = CRToday_Plugin_Settings::resolve_source($source_id, $deal);
		$has_override = trim($label_override) !== '';

		$label = $has_override
			? $label_override
			: ($resolved['label'] ?? strtoupper($source_id));

		$verified = (! $has_override)
			&& is_array($resolved)
			&& (($resolved['type'] ?? '') === 'builtin');

		return ['label' => $label, 'verified' => $verified];
	}

	/**
	 * Format ISO-8601 timestamp to human-readable short format.
	 */
	public static function format_timestamp(string $iso8601): string {
		$timestamp = strtotime($iso8601);
		if ($timestamp === false) {
			return '';
		}

		/* Short format: "13 Feb 14:30" */
		return wp_date('j M H:i', $timestamp);
	}
}
