<?php
/**
 * 設定ページ - WP Settings API
 *
 * @package CF7MasterPro\Admin
 */

namespace CF7MasterPro\Admin;

defined( 'ABSPATH' ) || exit;

/**
 * cf7mp_settings オプション登録・サニタイズ・保存後リダイレクト制御
 */
class SettingsPage {

	const OPTION_GROUP = 'cf7mp_settings_group';
	const OPTION_NAME  = 'cf7mp_settings';

	/**
	 * 登録
	 */
	public function register() {
		add_action( 'admin_init', array( $this, 'register_settings' ) );
		add_filter( 'wp_redirect', array( $this, 'preserve_tab_on_redirect' ) );
	}

	/**
	 * register_setting
	 */
	public function register_settings() {
		register_setting(
			self::OPTION_GROUP,
			self::OPTION_NAME,
			array(
				'type'              => 'array',
				'sanitize_callback' => array( $this, 'sanitize' ),
				'default'           => array(),
			)
		);
	}

	/**
	 * 設定値サニタイズ - 既存値マージ + フィールド別検証
	 *
	 * @param mixed $input 入力.
	 * @return array
	 */
	public function sanitize( $input ) {
		if ( ! is_array( $input ) ) {
			return array();
		}
		$existing = (array) get_option( self::OPTION_NAME, array() );

		$schema = $this->get_schema();
		$clean  = array();
		foreach ( $schema as $key => $type ) {
			if ( ! array_key_exists( $key, $input ) ) {
				continue;
			}
			$clean[ $key ] = $this->sanitize_value( $input[ $key ], $type );
		}
		// 既存（送信フォームに含まれなかったタブの値）を保持
		return array_merge( $existing, $clean );
	}

	/**
	 * フィールドスキーマ
	 *
	 * @return array<string,string>
	 */
	private function get_schema() {
		return array(
			'enable_confirmation' => 'bool',
			'complete_message'    => 'textarea',
			'redirect_url'        => 'url',
			'data_retention'      => 'int',
			'css_primary'         => 'css_color',
			'css_secondary'       => 'css_color',
			'css_bg'              => 'css_color',
			'css_border'          => 'css_color',
			'css_success'         => 'css_color',
			'css_radius'          => 'css_radius',
			'css_font'            => 'css_font',
			'progress_style'      => 'key',
			'active_tab'          => 'key',
		);
	}

	/**
	 * 値のサニタイズ
	 *
	 * @param mixed  $value 値.
	 * @param string $type 型.
	 * @return mixed
	 */
	private function sanitize_value( $value, $type ) {
		switch ( $type ) {
			case 'int':
				return (int) $value;
			case 'bool':
				return empty( $value ) ? 0 : 1;
			case 'email':
				return sanitize_email( (string) $value );
			case 'url':
				return esc_url_raw( (string) $value );
			case 'key':
				return sanitize_key( (string) $value );
			case 'time':
				return preg_match( '/^\d{2}:\d{2}$/', (string) $value ) ? (string) $value : '';
			case 'textarea':
				return sanitize_textarea_field( (string) $value );
			case 'css_color':
				$color = sanitize_hex_color( (string) $value );
				return $color ? $color : '';
			case 'css_radius':
				if ( ! preg_match( '/^(\d{1,2})(?:px)?$/', trim( (string) $value ), $m ) ) {
					return '';
				}
				return min( 50, (int) $m[1] ) . 'px';
			case 'css_font':
				return $this->sanitize_font_family( (string) $value );
			case 'secret':
			case 'text':
			default:
				return sanitize_text_field( (string) $value );
		}
	}

	/**
	 * CSS font-family の許可リスト化
	 *
	 * @param string $value 入力値.
	 * @return string
	 */
	private function sanitize_font_family( $value ) {
		$allowed = array(
			'system-ui',
			'sans-serif',
			'serif',
			'monospace',
			'Noto Sans JP',
			'Noto Serif JP',
			'Arial',
			'Helvetica',
			'Verdana',
			'Georgia',
			'Times New Roman',
		);
		$parts   = array_map( 'trim', explode( ',', $value ) );
		$clean   = array();
		foreach ( $parts as $part ) {
			$part = trim( $part, "\"'" );
			if ( in_array( $part, $allowed, true ) ) {
				$clean[] = $part;
			}
		}
		return implode( ', ', array_unique( $clean ) );
	}

	/**
	 * options.php 保存後リダイレクトに tab パラメータ復元
	 *
	 * @param string $location リダイレクト先.
	 * @return string
	 */
	public function preserve_tab_on_redirect( $location ) {
		if ( false === strpos( $location, 'page=frontierline-forms-settings' ) ) {
			return $location;
		}
		$active_tab = '';
		if ( isset( $_POST[ self::OPTION_NAME ]['active_tab'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
			$active_tab = sanitize_key( wp_unslash( $_POST[ self::OPTION_NAME ]['active_tab'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
		}
		if ( $active_tab ) {
			$location = add_query_arg( 'tab', $active_tab, $location );
		}
		return $location;
	}
}
