<?php
/**
 * Public settings response mapper.
 *
 * Phase-8 slice 8b Presentation-layer mapper that translates a
 * {@see \Affilun\Application\Settings\PluginSettings}
 * snapshot into the public-safe array shape returned by the
 * §13.1 `GET /affilun/v1/settings/public` REST endpoint documented
 * in `specifications/rest-api-spec.md`.
 *
 * §13.1 "返してよい情報" — emitted by {@see self::map()}:
 *
 *   - `enabled_providers` — list of provider keys whose
 *     {@see \Affilun\Application\Settings\ProviderCredentials::enabled()}
 *     is true. This is the editor visibility list; some providers such as
 *     Mercari can be useful with only the enable toggle and optional secrets.
 *   - `default_template` — §13.5 default template key.
 *   - `available_templates` — §6.4 whitelist of built-in
 *     templates (sourced from
 *     {@see \Affilun\Application\Render\Template\TemplateKey::validKeys()}).
 *   - `button_labels_default` — §4.3 `affilun/product-card.buttonLabels.default`
 *     initial label map.
 *   - `feature_flags` — bool-valued feature-flag map. Empty in
 *     the Phase-8 minimum; Phase 11 will populate it.
 *   - `per_page_max` — §5.1 pagination cap (50).
 *   - `rendering` — public subset of the §13.5 Rendering tab
 *     (badge / disclaimer / lazy-loading / visual defaults).
 *   - `links` — public subset of the §13.6 Links tab.
 *   - `ai.configured` — whether affilun Cloud AI is configured.
 *   - `openai.configured` — legacy compatibility flag, always false.
 *
 * §13.1 "返してはいけない情報" — explicitly EXCLUDED:
 *
 *   - API キー (provider access keys / app ids).
 *   - シークレット (provider secret keys / affiliate ids).
 *   - 暗号化済み資格情報そのもの (raw credential maps).
 *   - 内部診断詳細 (diagnostics output).
 *   - §13.9 Debug Mode flag.
 *   - §13.7 Sync settings.
 *   - §13.8 Cache settings (TTLs are admin-only state).
 *
 * The mapper is pure: same input → same output, no side
 * effects, no I/O. Per `specifications/security-and-compliance.md`
 * §6.3 / §6.4 the output never carries credential values, so
 * §6.3 masking is unnecessary on this surface (the mapper
 * simply does not read the secrets at all).
 *
 * @package Affilun\Presentation\Rest\Mapper
 */

declare(strict_types=1);

namespace Affilun\Presentation\Rest\Mapper;

use Affilun\Application\Render\Template\TemplateKey;
use Affilun\Application\Settings\PluginSettings;

/**
 * Pure-function mapper from {@see PluginSettings} to the §13.1
 * public-settings response shape.
 *
 * See the file-level docblock for the field-by-field "返してよい
 * 情報" enumeration and the explicit "返してはいけない情報"
 * exclusion list this mapper enforces.
 */
final class PublicSettingsMapper {

	/**
	 * §5.1 pagination cap surfaced by the §13.1 endpoint.
	 */
	private const PER_PAGE_MAX = 50;

	/**
	 * §4.3 `affilun/product-card.buttonLabels.default` initial label
	 * map. The keys mirror the public editor provider taxonomy and are surfaced
	 * verbatim so the editor can seed its label inputs.
	 *
	 * @var array<string, string>
	 */
	private const BUTTON_LABELS_DEFAULT = array(
		'amazon'         => 'Amazon',
		'rakuten'        => '楽天市場',
		'yahoo_shopping' => 'Yahoo!ショッピング',
		'mercari'        => 'メルカリ',
	);

	/**
	 * Map a {@see PluginSettings} snapshot to the §13.1
	 * public-settings response array.
	 *
	 * The output shape is documented verbatim on the file-level
	 * docblock. Every field is computed from `$settings` except
	 * the hardcoded §6.4 template whitelist (sourced from
	 * {@see TemplateKey::validKeys()}), the §4.3 button-labels
	 * default map, and the §5.1 `per_page_max` cap.
	 *
	 * @param PluginSettings $settings Source settings snapshot.
	 *
	 * @return array<string, mixed>
	 */
	public function map( PluginSettings $settings ): array {
		$enabledProviders = array();
		foreach ( $settings->providerCredentials() as $credentials ) {
			if ( $credentials->enabled() ) {
				$enabledProviders[] = $credentials->providerKey();
			}
		}

		$rendering = $settings->rendering();
		$links     = $settings->links();
		$cloud     = $settings->cloud();

		return array(
			'enabled_providers'     => $enabledProviders,
			'default_template'      => $rendering->defaultTemplate(),
			'available_templates'   => TemplateKey::validKeys(),
			'button_labels_default' => self::BUTTON_LABELS_DEFAULT,
			'feature_flags'         => array(),
			'per_page_max'          => self::PER_PAGE_MAX,
			'rendering'             => array(
				'show_provider_badge_by_default' => $rendering->showProviderBadgeByDefault(),
				'show_disclaimer_by_default'     => $rendering->showDisclaimerByDefault(),
				'lazy_load_images'               => $rendering->lazyLoadImages(),
				'default_design_preset'          => $rendering->defaultDesignPreset(),
				'default_button_layout'          => $rendering->defaultButtonLayout(),
				'default_button_shape'           => $rendering->defaultButtonShape(),
				'default_color_scheme'           => $rendering->defaultColorScheme(),
			),
			'links'                 => array(
				'open_in_new_tab_default'  => $links->openInNewTabDefault(),
				'tracking_enabled_default' => $links->trackingEnabledDefault(),
				'add_nofollow'             => $links->addNofollow(),
				'add_sponsored'            => $links->addSponsored(),
				'add_noopener'             => $links->addNoopener(),
				'add_noreferrer'           => $links->addNoreferrer(),
			),
			'ai'                    => array(
				'configured' => $cloud->isConfigured(),
				'source'     => 'cloud',
			),
			'openai'                => array(
				'configured' => false,
			),
			'cloud'                 => array(
				'enabled'    => $cloud->enabled(),
				'configured' => $cloud->isConfigured(),
				'plan'       => $cloud->plan(),
			),
		);
	}
}
