<?php
/**
 * Suggester Settings.
 *
 * Stores and renders configuration for in-editor internal link suggestions.
 * Deliberately small and sensible-by-default: works out of the box with zero
 * configuration (posts -> posts, 10 suggestions, 2-word minimum).
 *
 * Settings live in their own option (NOT the shared module-toggle option),
 * autoload disabled, so this config is only read on the screens that need it.
 *
 * SECURITY: gated by `manage_options`; saves are nonce-checked and every value
 * is sanitised on the way in.
 *
 * @package Platform\Helm\Modules\Link_Suggester
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\Link_Suggester;

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

final class SuggesterSettings {

	public const OPTION      = 'platform_helm_link_suggester';
	public const PAGE_SLUG   = 'platform-helm-link-suggester';
	public const PARENT_SLUG = 'platform-helm';

	private const CAPABILITY = 'manage_options';

	/**
	 * @return array{enabled:bool,max_suggestions:int,target_post_types:string[],editor_post_types:string[],min_title_words:int,excluded_keywords:string[],external_links:array<int,array{keyword:string,url:string}>}
	 */
	public static function get(): array {
		$saved = get_option( self::OPTION, [] );
		$saved = is_array( $saved ) ? $saved : [];

		return [
			'enabled'           => isset( $saved['enabled'] ) ? (bool) $saved['enabled'] : true,
			'max_suggestions'   => isset( $saved['max_suggestions'] ) ? max( 1, min( 25, (int) $saved['max_suggestions'] ) ) : 10,
			'target_post_types' => ! empty( $saved['target_post_types'] ) && is_array( $saved['target_post_types'] )
				? array_values( array_filter( $saved['target_post_types'], 'is_string' ) )
				: [ 'post' ],
			'editor_post_types' => ! empty( $saved['editor_post_types'] ) && is_array( $saved['editor_post_types'] )
				? array_values( array_filter( $saved['editor_post_types'], 'is_string' ) )
				: [ 'post' ],
			'min_title_words'   => isset( $saved['min_title_words'] ) ? max( 1, min( 6, (int) $saved['min_title_words'] ) ) : 2,
			'excluded_keywords' => isset( $saved['excluded_keywords'] ) && is_array( $saved['excluded_keywords'] )
				? array_values( array_filter( array_map( 'strval', $saved['excluded_keywords'] ) ) )
				: [],
			'external_links'    => isset( $saved['external_links'] ) && is_array( $saved['external_links'] )
				? $saved['external_links']
				: [],
		];
	}

	public function register_hooks(): void {
		add_action( 'admin_menu', [ $this, 'register_menu' ], 40 );
		add_action( 'admin_init', [ $this, 'maybe_save' ] );
	}

	public function register_menu(): void {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			return;
		}
		add_submenu_page(
			self::PARENT_SLUG,
			__( 'Link Suggestions', 'platform-helm' ),
			__( 'Link Suggestions', 'platform-helm' ),
			self::CAPABILITY,
			self::PAGE_SLUG,
			[ $this, 'render' ]
		);
	}

	public function maybe_save(): void {
		if ( ! isset( $_POST['platform_helm_ls_save'] ) ) {
			return;
		}
		if ( ! current_user_can( self::CAPABILITY ) ) {
			return;
		}
		check_admin_referer( 'platform_helm_ls_settings', '_ls_nonce' );

		$all_types = $this->public_post_types();

		$target_types = isset( $_POST['target_post_types'] ) && is_array( $_POST['target_post_types'] )
			? array_values( array_intersect( $all_types, array_map( 'sanitize_key', wp_unslash( $_POST['target_post_types'] ) ) ) )
			: [];
		$editor_types = isset( $_POST['editor_post_types'] ) && is_array( $_POST['editor_post_types'] )
			? array_values( array_intersect( $all_types, array_map( 'sanitize_key', wp_unslash( $_POST['editor_post_types'] ) ) ) )
			: [];

		$value = [
			'enabled'           => isset( $_POST['enabled'] ),
			'max_suggestions'   => isset( $_POST['max_suggestions'] ) ? (int) $_POST['max_suggestions'] : 10,
			'target_post_types' => ! empty( $target_types ) ? $target_types : [ 'post' ],
			'editor_post_types' => ! empty( $editor_types ) ? $editor_types : [ 'post' ],
			'min_title_words'   => isset( $_POST['min_title_words'] ) ? (int) $_POST['min_title_words'] : 2,
			'excluded_keywords' => $this->parse_excluded_keywords( isset( $_POST['excluded_keywords'] ) ? (string) wp_unslash( $_POST['excluded_keywords'] ) : '' ),
			'external_links'    => $this->parse_external_links( isset( $_POST['external_links'] ) ? (string) wp_unslash( $_POST['external_links'] ) : '' ),
		];

		update_option( self::OPTION, $value, false );
		add_settings_error( 'platform_helm_ls', 'saved', __( 'Settings saved.', 'platform-helm' ), 'success' );
	}

	/**
	 * @return string[]
	 */
	private function parse_excluded_keywords( string $raw ): array {
		$lines = preg_split( '/\r\n|\r|\n/', $raw ) ?: [];
		$out   = [];
		foreach ( $lines as $line ) {
			$line = trim( $line );
			if ( '' !== $line ) {
				$out[] = $line;
			}
		}
		return array_values( array_unique( $out ) );
	}

	/**
	 * @return array<int,array{keyword:string,url:string}>
	 */
	private function parse_external_links( string $raw ): array {
		$lines = preg_split( '/\r\n|\r|\n/', $raw ) ?: [];
		$out   = [];
		foreach ( $lines as $line ) {
			$line = trim( $line );
			if ( '' === $line || false === strpos( $line, '|' ) ) {
				continue;
			}
			[ $kw, $url ] = array_map( 'trim', explode( '|', $line, 2 ) );
			$url = esc_url_raw( $url );
			if ( '' !== $kw && '' !== $url ) {
				$out[] = [ 'keyword' => $kw, 'url' => $url ];
			}
		}
		return $out;
	}

	private function excluded_to_text( array $list ): string {
		return implode( "\n", array_map( 'strval', $list ) );
	}

	private function external_to_text( array $list ): string {
		$lines = [];
		foreach ( $list as $rule ) {
			if ( isset( $rule['keyword'], $rule['url'] ) ) {
				$lines[] = $rule['keyword'] . ' | ' . $rule['url'];
			}
		}
		return implode( "\n", $lines );
	}

	public function render(): void {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			wp_die( esc_html__( 'You do not have permission to access this page.', 'platform-helm' ) );
		}
		$s     = self::get();
		$types = $this->public_post_types();
		$actions = '<button type="submit" form="ph-ls-form" name="platform_helm_ls_save" class="btn btn-primary"><i class="ti ti-device-floppy" aria-hidden="true"></i> ' . esc_html__( 'Save Settings', 'platform-helm' ) . '</button>';
		\Platform\Helm\Core\Ui::open_page(
			__( 'Link Suggestions', 'platform-helm' ),
			__( 'Configure the in-editor link suggester — surfaces relevant internal links as you write.', 'platform-helm' ),
			$actions
		);
		settings_errors( 'platform_helm_ls' );

		if ( $s['enabled'] ) {
			\Platform\Helm\Core\Ui::notice(
				'<strong>' . esc_html__( 'Module active.', 'platform-helm' ) . '</strong> '
				. esc_html__( 'Suggestions appear in the block-editor sidebar panel while writing posts and pages.', 'platform-helm' ),
				'success'
			);
		}
		?>
		<form id="ph-ls-form" method="post">
			<?php wp_nonce_field( 'platform_helm_ls_settings', '_ls_nonce' ); ?>
			<div class="main-cols">
				<div style="display:flex;flex-direction:column;gap:16px">

					<?php \Platform\Helm\Core\Ui::card_open( __( 'Relevance & Display', 'platform-helm' ), '', 'ti-adjustments-horizontal' ); ?>
						<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 14px;background:var(--bg-secondary);border-radius:var(--r-md)">
							<div>
								<p style="font-size:12px;font-weight:600;color:var(--text-primary)"><?php esc_html_e( 'Show the suggestions panel in the editor', 'platform-helm' ); ?></p>
								<p style="font-size:11px;color:var(--text-faint);margin-top:2px"><?php esc_html_e( 'Adds the Helm panel to the block-editor sidebar on the selected post types.', 'platform-helm' ); ?></p>
							</div>
							<label class="toggle"><input type="checkbox" name="enabled" value="1" <?php checked( $s['enabled'] ); ?>><span class="toggle-slider"></span></label>
						</div>
						<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px">
							<div class="field-group">
								<label class="field-label" for="ls-max"><?php esc_html_e( 'Max suggestions per post', 'platform-helm' ); ?></label>
								<input id="ls-max" class="field-input" type="number" name="max_suggestions" min="1" max="25" value="<?php echo esc_attr( (string) $s['max_suggestions'] ); ?>">
							</div>
							<div class="field-group">
								<label class="field-label" for="ls-words"><?php esc_html_e( 'Minimum title words', 'platform-helm' ); ?></label>
								<input id="ls-words" class="field-input" type="number" name="min_title_words" min="1" max="6" value="<?php echo esc_attr( (string) $s['min_title_words'] ); ?>">
							</div>
						</div>
						<p style="font-size:11px;color:var(--text-faint);margin-top:8px"><?php esc_html_e( 'Up to 25 suggestions per post. Ignoring very short titles avoids noisy single-word matches.', 'platform-helm' ); ?></p>
					<?php \Platform\Helm\Core\Ui::card_close(); ?>

					<?php \Platform\Helm\Core\Ui::card_open( __( 'Content Scope', 'platform-helm' ), '<span class="text-faint">' . esc_html__( 'Where suggestions come from', 'platform-helm' ) . '</span>', 'ti-filter' ); ?>
						<div class="field-group">
							<label class="field-label"><?php esc_html_e( 'Show editor panel on', 'platform-helm' ); ?></label>
							<?php $this->checkbox_types( 'editor_post_types', $types, $s['editor_post_types'] ); ?>
						</div>
						<div class="field-group" style="margin-top:14px">
							<label class="field-label"><?php esc_html_e( 'Suggest links to', 'platform-helm' ); ?></label>
							<?php $this->checkbox_types( 'target_post_types', $types, $s['target_post_types'] ); ?>
						</div>
						<div class="field-group" style="margin-top:14px">
							<label class="field-label" for="ls-excl"><?php esc_html_e( 'Excluded keywords', 'platform-helm' ); ?></label>
							<textarea id="ls-excl" class="field-input" name="excluded_keywords" rows="4" placeholder="example phrase&#10;another phrase"><?php echo esc_textarea( $this->excluded_to_text( $s['excluded_keywords'] ) ); ?></textarea>
							<p style="font-size:11px;color:var(--text-faint);margin-top:4px"><?php esc_html_e( 'One phrase per line — never suggested as anchor text. Case-insensitive.', 'platform-helm' ); ?></p>
						</div>
					<?php \Platform\Helm\Core\Ui::card_close(); ?>

					<?php \Platform\Helm\Core\Ui::card_open( __( 'External Link Rules', 'platform-helm' ), '', 'ti-external-link' ); ?>
						<div class="field-group">
							<textarea class="field-input" name="external_links" rows="5" placeholder="keyword | https://example.com/&#10;another term | https://example.org/page"><?php echo esc_textarea( $this->external_to_text( $s['external_links'] ) ); ?></textarea>
							<p style="font-size:11px;color:var(--text-faint);margin-top:4px"><?php esc_html_e( 'One rule per line: keyword | https://full-url. When the keyword appears in your content, the editor suggests linking it out (new tab, rel="noopener").', 'platform-helm' ); ?></p>
						</div>
					<?php \Platform\Helm\Core\Ui::card_close(); ?>

				</div>

				<div>
					<?php \Platform\Helm\Core\Ui::card_open( __( 'How it works', 'platform-helm' ), '', 'ti-info-circle' ); ?>
						<ul style="list-style:none;display:flex;flex-direction:column;gap:10px;font-size:12px;color:var(--text-secondary);line-height:1.5">
							<li style="display:flex;gap:8px"><i class="ti ti-pencil" style="color:var(--accent)" aria-hidden="true"></i> <?php esc_html_e( 'Open any post or page in the block editor.', 'platform-helm' ); ?></li>
							<li style="display:flex;gap:8px"><i class="ti ti-wand" style="color:var(--accent)" aria-hidden="true"></i> <?php esc_html_e( 'The Helm panel lists existing posts worth linking to, matched on real body text.', 'platform-helm' ); ?></li>
							<li style="display:flex;gap:8px"><i class="ti ti-eye-off" style="color:var(--accent)" aria-hidden="true"></i> <?php esc_html_e( 'Image alt text, headings and already-linked phrases are ignored.', 'platform-helm' ); ?></li>
							<li style="display:flex;gap:8px"><i class="ti ti-target" style="color:var(--accent)" aria-hidden="true"></i> <?php esc_html_e( 'If Yoast or Rank Math is active, focus keywords sharpen the matches.', 'platform-helm' ); ?></li>
						</ul>
					<?php \Platform\Helm\Core\Ui::card_close(); ?>
				</div>
			</div>
		</form>
		<?php
		\Platform\Helm\Core\Ui::close_page();
	}

	/**
	 * Render the post-type checkbox set as design "chips" for a settings field.
	 *
	 * @param string[] $types
	 * @param string[] $selected
	 */
	private function checkbox_types( string $name, array $types, array $selected ): void {
		echo '<div style="display:flex;flex-wrap:wrap;gap:8px">';
		foreach ( $types as $type ) {
			printf(
				'<label style="display:inline-flex;align-items:center;gap:6px;padding:5px 10px;background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--r-sm);font-size:12px;cursor:pointer"><input type="checkbox" name="%1$s[]" value="%2$s" %3$s> %4$s</label>',
				esc_attr( $name ),
				esc_attr( $type ),
				checked( in_array( $type, $selected, true ), true, false ),
				esc_html( $type )
			);
		}
		echo '</div>';
	}

	/**
	 * @return string[]
	 */
	private function public_post_types(): array {
		$types = get_post_types( [ 'public' => true ], 'names' );
		unset( $types['attachment'] );
		return array_values( $types );
	}
}
