<?php
/**
 * Settings helper with defaults.
 *
 * @package WPLens
 */

namespace WPLens\Utils;

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

final class Options {

	public const OPTION_NAME = 'wplens_settings';

	/**
	 * Default settings tree.
	 *
	 * @return array<string, mixed>
	 */
	public static function defaults(): array {
		return array(
			'version' => '1.0.0',
			'modules' => array(
				'crawler_log'       => true,
				'aeo_scans'         => true,
				'citation_tracking' => false,
				'weekly_report'     => false,
			),
			'crawler' => array(
				'sample_rate'     => 1.0,
				'retention_days'  => 90,
				'log_404s'        => false,
				'log_admin_paths' => false,
				'ip_hashing'      => true,
				'enabled_bots'    => array(), // empty = all enabled
			),
			'scans' => array(
				'default_provider'     => 'openai',
				'auto_scan_on_publish' => false,
				'cache_ttl_minutes'    => 60,
			),
			'citations' => array(
				'schedule'        => 'weekly',
				'providers'       => array( 'openai' ),
				'max_queries'     => 10,
				'target_domain'   => '',
			),
			'reporting' => array(
				'recipients'      => array(),
				'schedule'        => 'weekly',
				'include_pdf'     => true,
				'include_csv'     => false,
				'whitelabel_logo' => null,
			),
			'privacy' => array(
				'analytics_optin'         => false,
				'remove_data_on_uninstall' => false,
			),
			'schema' => array(
				'enabled'        => true,
				'disabled_types' => array(), // slugs of generators to turn off, e.g. array( 'howto' )
				'organization'   => array(
					'name'          => '',   // falls back to bloginfo('name')
					'logo'          => '',   // falls back to custom logo / site icon
					'contact_email' => '',
					'same_as'       => array(),
				),
			),
		);
	}

	/**
	 * Get the full settings tree, merged with defaults.
	 *
	 * @return array<string, mixed>
	 */
	public static function all(): array {
		$saved = get_option( self::OPTION_NAME, array() );
		if ( ! is_array( $saved ) ) {
			$saved = array();
		}
		return self::merge_deep( self::defaults(), $saved );
	}

	/**
	 * Save merged settings.
	 *
	 * @param array<string, mixed> $partial Partial tree to merge in.
	 */
	public static function save( array $partial ): void {
		$current = self::all();
		$merged  = self::merge_deep( $current, $partial );
		update_option( self::OPTION_NAME, $merged );
	}

	/**
	 * Recursive associative-array merge — second array wins.
	 *
	 * @param array<mixed, mixed> $base
	 * @param array<mixed, mixed> $override
	 * @return array<mixed, mixed>
	 */
	private static function merge_deep( array $base, array $override ): array {
		foreach ( $override as $key => $value ) {
			if ( is_array( $value ) && isset( $base[ $key ] ) && is_array( $base[ $key ] ) && self::is_assoc( $value ) && self::is_assoc( $base[ $key ] ) ) {
				$base[ $key ] = self::merge_deep( $base[ $key ], $value );
			} else {
				$base[ $key ] = $value;
			}
		}
		return $base;
	}

	private static function is_assoc( array $arr ): bool {
		if ( array() === $arr ) {
			return true;
		}
		return array_keys( $arr ) !== range( 0, count( $arr ) - 1 );
	}
}
