<?php
declare(strict_types=1);

namespace Wohno\Plugin\Settings;

use Wohno\Plugin\Ajax\Preview;
use Wohno\Plugin\Api\Client;
use Wohno\Plugin\Security\Secret;

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

/**
 * Admin settings: API-key entry (server-side, `manage_options` only) +
 * a connection test, plus a contract-mismatch update notice.
 */
final class SettingsPage {

	private const OPTION_KEY = 'wohno_api_key';
	private const PAGE_SLUG  = 'wohno-settings';

	/** Settings-API option groups — one per tab so saving a tab never wipes another. */
	private const GROUP_CONNECTION = 'wohno_connection';
	private const GROUP_DISPLAY    = 'wohno_display';

	/** Display-option names. */
	private const OPT_LAYOUT  = 'wohno_default_layout';
	private const OPT_COLUMNS = 'wohno_default_columns';
	private const OPT_ACCENT  = 'wohno_accent_color';
	private const OPT_RADIUS  = 'wohno_card_radius';
	private const OPT_ATTRIB  = 'wohno_show_attribution';

	private const DEFAULT_ACCENT = '#df6900';

	/** Allowed corner-radius presets (value => label key handled in render). */
	private const RADII = array( '0px', '8px', '14px', '18px', '26px' );

	/**
	 * Constructor.
	 *
	 * @param Client $client API client (used for the connection test).
	 */
	public function __construct( private readonly Client $client ) {
	}

	/**
	 * Register admin hooks.
	 *
	 * @return void
	 */
	public function register(): void {
		add_action( 'admin_menu', array( $this, 'add_menu' ) );
		add_action( 'admin_init', array( $this, 'register_settings' ) );
		add_action( 'admin_post_wohno_test_connection', array( $this, 'handle_test' ) );
		add_action( 'admin_notices', array( $this, 'maybe_notice' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_menu_icon_style' ) );

		// Localise WordPress' generic "Settings saved." for our setting groups.
		if ( is_admin() ) {
			add_filter( 'gettext', array( $this, 'translate_saved_message' ), 10, 3 );
		}

		// Invalidate cached pages whenever the API key changes.
		add_action( 'add_option_' . self::OPTION_KEY, array( Client::class, 'flush_cache' ), 10, 0 );
		add_action( 'update_option_' . self::OPTION_KEY, array( Client::class, 'flush_cache' ), 10, 0 );
	}

	/**
	 * Add the settings page under Settings.
	 *
	 * @return void
	 */
	public function add_menu(): void {
		add_menu_page(
			__( 'Wohno – Inserate', 'wohno' ),
			__( 'Wohno', 'wohno' ),
			'manage_options',
			self::PAGE_SLUG,
			array( $this, 'render_page' ),
			WOHNO_PLUGIN_URL . 'assets/img/menu-icon.svg',
			58
		);
	}

	/**
	 * Keep the top-level menu's coloured "W" icon at full opacity in every state
	 * (WordPress dims inactive menu icons to ~0.6 by default).
	 *
	 * Enqueued on every admin page (the menu is global) as an inline style on a
	 * registered handle, rather than echoing a raw `<style>` tag.
	 *
	 * @return void
	 */
	public function enqueue_menu_icon_style(): void {
		wp_register_style( 'wohno-admin-menu', false, array(), \Wohno\Plugin\VERSION );
		wp_enqueue_style( 'wohno-admin-menu' );

		$slug = self::PAGE_SLUG;
		wp_add_inline_style(
			'wohno-admin-menu',
			"#adminmenu #toplevel_page_{$slug} .wp-menu-image,"
			. "#adminmenu #toplevel_page_{$slug} .wp-menu-image img{opacity:1;}"
		);
	}

	/**
	 * Enqueue the live shortcode-generator script on the Wohno settings page only.
	 *
	 * @param string $hook Current admin page hook suffix.
	 * @return void
	 */
	public function enqueue_admin( string $hook ): void {
		if ( ! str_contains( $hook, self::PAGE_SLUG ) ) {
			return;
		}

		// Scoped settings-page chrome (hero, tabs, snippet boxes, amber controls).
		wp_enqueue_style(
			'wohno-admin-settings',
			WOHNO_PLUGIN_URL . 'assets/css/admin-settings.css',
			array(),
			\Wohno\Plugin\VERSION
		);

		// Front-end card styles + behaviour so the live preview matches the site.
		wp_enqueue_style( 'wohno-listings' );
		wp_enqueue_script( 'wohno-listings' );
		wp_enqueue_script( 'wohno-load-more' );

		wp_enqueue_script(
			'wohno-admin-generator',
			WOHNO_PLUGIN_URL . 'assets/js/admin-generator.js',
			array(),
			\Wohno\Plugin\VERSION,
			true
		);
		wp_localize_script(
			'wohno-admin-generator',
			'wohnoGen',
			array(
				'ajaxUrl' => admin_url( 'admin-ajax.php' ),
				'action'  => Preview::ACTION,
				'nonce'   => wp_create_nonce( Preview::NONCE ),
				'loading' => __( 'Vorschau lädt …', 'wohno' ),
				'error'   => __( 'Vorschau konnte nicht geladen werden.', 'wohno' ),
			)
		);
	}

	/**
	 * Register the API-key setting.
	 *
	 * @return void
	 */
	public function register_settings(): void {
		// --- Connection tab ---
		register_setting(
			self::GROUP_CONNECTION,
			self::OPTION_KEY,
			array(
				'type'              => 'string',
				'sanitize_callback' => array( $this, 'sanitize_key' ),
				'default'           => '',
			)
		);

		// --- Display tab ---
		register_setting(
			self::GROUP_DISPLAY,
			self::OPT_LAYOUT,
			array(
				'type'              => 'string',
				'sanitize_callback' => array( $this, 'sanitize_layout' ),
				'default'           => 'grid',
			)
		);
		register_setting(
			self::GROUP_DISPLAY,
			self::OPT_COLUMNS,
			array(
				'type'              => 'integer',
				'sanitize_callback' => array( $this, 'sanitize_columns' ),
				'default'           => 3,
			)
		);
		register_setting(
			self::GROUP_DISPLAY,
			self::OPT_ACCENT,
			array(
				'type'              => 'string',
				'sanitize_callback' => array( $this, 'sanitize_accent' ),
				'default'           => self::DEFAULT_ACCENT,
			)
		);
		register_setting(
			self::GROUP_DISPLAY,
			self::OPT_RADIUS,
			array(
				'type'              => 'string',
				'sanitize_callback' => array( $this, 'sanitize_radius' ),
				'default'           => '18px',
			)
		);
		register_setting(
			self::GROUP_DISPLAY,
			self::OPT_ATTRIB,
			array(
				'type'              => 'string',
				'sanitize_callback' => array( $this, 'sanitize_checkbox' ),
				'default'           => '0',
			)
		);
	}

	/**
	 * Clamp the column count to the supported 1–4 range.
	 *
	 * @param mixed $value Raw submitted value.
	 * @return int A value between 1 and 4.
	 */
	public function sanitize_columns( $value ): int {
		return min( 4, max( 1, (int) $value ) );
	}

	/**
	 * Normalise a checkbox to the stored '1' / '0' string.
	 *
	 * @param mixed $value Raw submitted value.
	 * @return string '1' when checked, otherwise '0'.
	 */
	public function sanitize_checkbox( $value ): string {
		return $value ? '1' : '0';
	}

	/**
	 * Sanitise the saved default layout to a known token.
	 *
	 * @param mixed $value Raw submitted value.
	 * @return string One of: grid, cards, list, map.
	 */
	public function sanitize_layout( $value ): string {
		$value = is_string( $value ) ? strtolower( $value ) : 'grid';

		return in_array( $value, array( 'grid', 'cards', 'list', 'map' ), true ) ? $value : 'grid';
	}

	/**
	 * Sanitise the accent colour to a valid hex value (or the brand default).
	 *
	 * @param mixed $value Raw submitted value.
	 * @return string A `#rrggbb` colour.
	 */
	public function sanitize_accent( $value ): string {
		$hex = sanitize_hex_color( is_string( $value ) ? $value : '' );

		return ( is_string( $hex ) && '' !== $hex ) ? $hex : self::DEFAULT_ACCENT;
	}

	/**
	 * Sanitise the corner-radius preset.
	 *
	 * @param mixed $value Raw submitted value.
	 * @return string One of the allowed radius presets.
	 */
	public function sanitize_radius( $value ): string {
		$value = is_string( $value ) ? $value : '';

		return in_array( $value, self::RADII, true ) ? $value : '18px';
	}

	/**
	 * Replace WordPress' English "Settings saved." with a German message when one
	 * of our setting groups is being saved (the stored notice is created during
	 * the options.php save request, so we localise it there).
	 *
	 * @param string $translation Current translation.
	 * @param string $text        Original text.
	 * @param string $domain      Text domain.
	 * @return string
	 */
	public function translate_saved_message( $translation, $text, $domain ): string {
		if ( 'default' !== $domain || 'Settings saved.' !== $text ) {
			return $translation;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- read-only locale choice; options.php verifies the nonce before saving.
		$page = isset( $_POST['option_page'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['option_page'] ) ) : '';
		if ( in_array( $page, array( self::GROUP_DISPLAY, self::GROUP_CONNECTION ), true ) ) {
			return __( 'Einstellungen gespeichert.', 'wohno' );
		}

		return $translation;
	}

	/**
	 * Sanitise, validate and encrypt the API key on save.
	 *
	 * The form never re-echoes the plaintext key, so an empty submit means
	 * "leave the existing key untouched" (rather than wiping it).
	 *
	 * Copy-pasting a key from a styled dashboard frequently drags along invisible
	 * characters (non-breaking / zero-width / directional spaces, soft hyphen,
	 * word joiner) or surrounding text (a label, quotes). We therefore first strip
	 * all such characters and then **extract** the `sk_` token from whatever
	 * remains, rather than demanding a pristine value. The token is stored
	 * {@see Secret encrypted at rest}.
	 *
	 * @param mixed $value Raw submitted value.
	 * @return string The value to persist (encrypted ciphertext, or the existing one).
	 */
	public function sanitize_key( $value ): string {
		$raw = (string) $value;

		// WordPress runs this sanitiser TWICE per save (Settings API + update_option):
		// the second pass receives the value we already encrypted on the first.
		// Pass an already-encrypted value through unchanged — otherwise we would
		// try to re-validate ciphertext, fail the `sk_` check, and wipe the key.
		if ( Secret::is_encrypted( $raw ) ) {
			return $raw;
		}

		$existing = (string) get_option( self::OPTION_KEY, '' );

		// Drop whitespace + invisible/zero-width/directional characters anywhere.
		$clean = (string) preg_replace(
			'/[\s\x{00A0}\x{00AD}\x{200B}-\x{200F}\x{2060}\x{FEFF}]+/u',
			'',
			(string) $value
		);

		if ( '' === $clean ) {
			return $existing; // Empty submit: keep the current key.
		}

		// Extract the secret-key token even if a label or quotes were copied with
		// it. A Wohno secret key is `sk_` followed by key characters; the length
		// floor avoids matching incidental substrings like "task_force".
		if ( preg_match( '/sk_[A-Za-z0-9_-]{8,}/', $clean, $matches ) === 1 ) {
			return Secret::encrypt( $matches[0] );
		}

		add_settings_error( self::OPTION_KEY, 'wohno_key_format', __( 'Bitte einen geheimen Key (sk_…) mit Scope listings:read einfügen.', 'wohno' ) );

		return $existing; // Reject malformed input, keep the current key.
	}

	/**
	 * Render the settings page.
	 *
	 * @return void
	 */
	public function render_page(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		$plain  = Secret::decrypt( (string) get_option( self::OPTION_KEY, '' ) );
		$is_set = '' !== $plain;
		$masked = $is_set ? 'sk_••••' . substr( $plain, -4 ) : '';
		$tab    = $this->current_tab();
		?>
		<div class="wrap wohno-admin">
			<?php $this->render_hero(); ?>

			<?php // Anchor: WordPress relocates admin notices to just before this. ?>
			<hr class="wp-header-end" />

			<div class="wohno-admin__status <?php echo esc_attr( $is_set ? 'is-ok' : 'is-warn' ); ?>">
				<span class="wohno-admin__dot" aria-hidden="true"></span>
				<?php if ( $is_set ) : ?>
					<strong><?php echo esc_html__( 'Verbunden', 'wohno' ); ?></strong>
					<?php
					/* translators: %s: masked API key */
					echo ' · ' . esc_html( sprintf( __( 'Key %s aktiv', 'wohno' ), $masked ) );
					?>
				<?php else : ?>
					<strong><?php echo esc_html__( 'Noch nicht verbunden', 'wohno' ); ?></strong>
					· <?php echo esc_html__( 'Bitte API-Key im Reiter „Verbindung" eintragen.', 'wohno' ); ?>
				<?php endif; ?>
			</div>

			<?php $this->render_tabs( $tab ); ?>

			<?php
			switch ( $tab ) {
				case 'display':
					$this->render_display_tab();
					break;
				case 'connection':
					$this->render_connection_tab( $is_set, $masked );
					break;
				case 'embed':
					$this->render_embed_tab();
					break;
				case 'help':
					$this->render_help_tab();
					break;
				default:
					$this->render_start_tab( $is_set );
			}
			?>
		</div>
		<?php
	}

	/**
	 * The active settings tab (read-only navigation; no state change).
	 *
	 * @return string One of: display, connection, embed.
	 */
	private function current_tab(): string {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only tab switch, no state change.
		$tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( (string) $_GET['tab'] ) ) : 'start';

		return in_array( $tab, array( 'start', 'display', 'connection', 'embed', 'help' ), true ) ? $tab : 'start';
	}

	/**
	 * Render the gradient brand hero.
	 *
	 * @return void
	 */
	private function render_hero(): void {
		?>
		<div class="wohno-hero">
			<span class="wohno-hero__logo" aria-hidden="true">W</span>
			<div>
				<h1 class="wohno-hero__title"><?php echo esc_html__( 'Wohno – Inserate', 'wohno' ); ?></h1>
				<p class="wohno-hero__lead">
					<?php echo esc_html__( 'Zeige deine Wohno-Inserate nativ und SEO-freundlich auf deiner Seite. Detailseite und Bewerbung laufen sicher auf wohno.de.', 'wohno' ); ?>
				</p>
			</div>
		</div>
		<?php
	}

	/**
	 * Render the tab navigation.
	 *
	 * @param string $active Currently active tab key.
	 * @return void
	 */
	private function render_tabs( string $active ): void {
		$tabs = array(
			'start'      => __( 'Start', 'wohno' ),
			'display'    => __( 'Darstellung', 'wohno' ),
			'connection' => __( 'Verbindung', 'wohno' ),
			'embed'      => __( 'Einbinden', 'wohno' ),
			'help'       => __( 'Hilfe', 'wohno' ),
		);
		echo '<nav class="nav-tab-wrapper wohno-admin__tabs">';
		foreach ( $tabs as $key => $label ) {
			printf(
				'<a href="%s" class="nav-tab%s">%s</a>',
				esc_url( $this->tab_url( $key ) ),
				$active === $key ? ' nav-tab-active' : '',
				esc_html( $label )
			);
		}
		echo '</nav>';
	}

	/**
	 * Build the URL for a given settings tab.
	 *
	 * @param string $key Tab key.
	 * @return string
	 */
	private function tab_url( string $key ): string {
		return add_query_arg(
			array(
				'page' => self::PAGE_SLUG,
				'tab'  => $key,
			),
			admin_url( 'admin.php' )
		);
	}

	/**
	 * Render the "Start" tab: a short overview of what the plugin does and a
	 * status-aware "first steps" guide.
	 *
	 * @param bool $is_set Whether an API key is configured.
	 * @return void
	 */
	private function render_start_tab( bool $is_set ): void {
		?>
		<div class="wohno-card-panel">
			<h2><?php echo esc_html__( 'Willkommen bei Wohno – Inserate', 'wohno' ); ?></h2>
			<p class="description" style="max-width:70ch;font-size:14px;">
				<?php echo esc_html__( 'Mit diesem Plugin zeigst du deine Wohno-Inserate nativ und SEO-freundlich auf deiner WordPress-Seite — als Raster, große Karten, Liste oder interaktive Karte. Deine Besucher können filtern und suchen; ein Klick öffnet eine ansprechende Detailansicht. Bewerbung und Bewerbermappe laufen sicher first-party auf wohno.de.', 'wohno' ); ?>
			</p>

			<h3 class="wohno-start__h3"><?php echo esc_html__( 'Erste Schritte', 'wohno' ); ?></h3>
			<ol class="wohno-start__steps">
				<?php
				$this->render_start_step(
					$is_set,
					__( 'API-Key verbinden', 'wohno' ),
					__( 'Erstelle im Wohno-Dashboard einen Key (Scope listings:read) und hinterlege ihn.', 'wohno' ),
					$is_set ? __( 'Verbindung verwalten', 'wohno' ) : __( 'Jetzt verbinden', 'wohno' ),
					$this->tab_url( 'connection' )
				);
				$this->render_start_step(
					false,
					__( 'Darstellung festlegen', 'wohno' ),
					__( 'Wähle Standard-Layout, Spalten, Akzentfarbe und Rundung deiner Karten.', 'wohno' ),
					__( 'Darstellung öffnen', 'wohno' ),
					$this->tab_url( 'display' )
				);
				$this->render_start_step(
					false,
					__( 'Inserate einbinden', 'wohno' ),
					__( 'Erzeuge im Shortcode-Generator deinen Shortcode (mit Live-Vorschau) oder nutze den Block „Wohno – Inserate".', 'wohno' ),
					__( 'Zum Generator', 'wohno' ),
					$this->tab_url( 'embed' )
				);
				?>
			</ol>
		</div>

		<div class="wohno-card-panel">
			<h2><?php echo esc_html__( 'Was das Plugin kann', 'wohno' ); ?></h2>
			<div class="wohno-start__features">
				<?php
				$this->render_start_feature( 'screenoptions', __( 'Vier Darstellungen', 'wohno' ), __( 'Raster, große Karten, Liste und interaktive Karte — pro Block/Shortcode wählbar.', 'wohno' ) );
				$this->render_start_feature( 'search', __( 'Suche & Filter', 'wohno' ), __( 'Optionale Filterleiste (Stadt, Zimmer, Miete, Typ, WBS, Freitext) für deine Besucher.', 'wohno' ) );
				$this->render_start_feature( 'format-gallery', __( 'Galerie & Detail-Modal', 'wohno' ), __( 'Jede Karte zeigt alle Fotos; ein Klick öffnet Details mit Beschreibung und Buttons.', 'wohno' ) );
				$this->render_start_feature( 'shortcode', __( 'Shortcode-Generator', 'wohno' ), __( 'Optionen einstellen, Shortcode kopieren — inklusive Live-Vorschau.', 'wohno' ) );
				$this->render_start_feature( 'layout', __( 'Block, Widget & Shortcode', 'wohno' ), __( 'Drei Wege zum Einbinden — plus fertige Block-Patterns im Inserter.', 'wohno' ) );
				$this->render_start_feature( 'lock', __( 'SEO-freundlich & sicher', 'wohno' ), __( 'Echtes HTML auf deiner Domain; Bewerbung und Daten bleiben sicher auf wohno.de.', 'wohno' ) );
				?>
			</div>
			<p class="wohno-admin__hint" style="margin-top:1rem;">
				<?php
				printf(
					/* translators: %s: link to the help tab */
					esc_html__( 'Mehr Details, FAQ und Kontakt findest du im Reiter %s.', 'wohno' ),
					'<a href="' . esc_url( $this->tab_url( 'help' ) ) . '">' . esc_html__( 'Hilfe', 'wohno' ) . '</a>'
				);
				?>
			</p>
		</div>
		<?php
	}

	/**
	 * Render one "first steps" item.
	 *
	 * @param bool   $done      Whether the step is already completed.
	 * @param string $title     Step title.
	 * @param string $text      Step description.
	 * @param string $cta_label Call-to-action label.
	 * @param string $cta_url   Call-to-action URL.
	 * @return void
	 */
	private function render_start_step( bool $done, string $title, string $text, string $cta_label, string $cta_url ): void {
		?>
		<li class="wohno-start__step<?php echo esc_attr( $done ? ' is-done' : '' ); ?>">
			<span class="wohno-start__step-mark" aria-hidden="true"><?php echo esc_html( $done ? '✓' : '' ); ?></span>
			<span class="wohno-start__step-body">
				<strong><?php echo esc_html( $title ); ?></strong>
				<span class="wohno-start__step-text"><?php echo esc_html( $text ); ?></span>
			</span>
			<a class="button" href="<?php echo esc_url( $cta_url ); ?>"><?php echo esc_html( $cta_label ); ?></a>
		</li>
		<?php
	}

	/**
	 * Render one feature card on the Start tab.
	 *
	 * @param string $icon  Dashicon name (without the `dashicons-` prefix).
	 * @param string $title Feature title.
	 * @param string $text  Feature description.
	 * @return void
	 */
	private function render_start_feature( string $icon, string $title, string $text ): void {
		?>
		<div class="wohno-start__feature">
			<span class="dashicons dashicons-<?php echo esc_attr( $icon ); ?>" aria-hidden="true"></span>
			<div>
				<strong><?php echo esc_html( $title ); ?></strong>
				<p><?php echo esc_html( $text ); ?></p>
			</div>
		</div>
		<?php
	}

	/**
	 * Render the "Darstellung" tab (default layout, columns, colours, attribution).
	 *
	 * @return void
	 */
	private function render_display_tab(): void {
		$layout  = $this->sanitize_layout( (string) get_option( self::OPT_LAYOUT, 'grid' ) );
		$columns = min( 4, max( 1, (int) get_option( self::OPT_COLUMNS, 3 ) ) );
		$accent  = $this->sanitize_accent( (string) get_option( self::OPT_ACCENT, self::DEFAULT_ACCENT ) );
		$radius  = $this->sanitize_radius( (string) get_option( self::OPT_RADIUS, '18px' ) );
		$attrib  = '1' === (string) get_option( self::OPT_ATTRIB, '0' );

		$layouts = array(
			'grid'  => __( 'Raster', 'wohno' ),
			'cards' => __( 'Karten (groß)', 'wohno' ),
			'list'  => __( 'Liste', 'wohno' ),
			'map'   => __( 'Karte', 'wohno' ),
		);
		$radii   = array(
			'0px'  => __( 'Eckig', 'wohno' ),
			'8px'  => __( 'Leicht gerundet', 'wohno' ),
			'14px' => __( 'Gerundet', 'wohno' ),
			'18px' => __( 'Standard', 'wohno' ),
			'26px' => __( 'Sehr rund', 'wohno' ),
		);
		?>
		<form method="post" action="options.php" class="wohno-card-panel">
			<?php settings_fields( self::GROUP_DISPLAY ); ?>

			<h2><?php echo esc_html__( 'Standard-Darstellung', 'wohno' ); ?></h2>
			<p class="description wohno-admin__hint">
				<?php echo esc_html__( 'Gilt, wenn ein Block oder Shortcode keine eigene Darstellung vorgibt.', 'wohno' ); ?>
			</p>
			<table class="form-table" role="presentation">
				<tr>
					<th scope="row"><label for="wohno_default_layout"><?php echo esc_html__( 'Layout', 'wohno' ); ?></label></th>
					<td>
						<select name="<?php echo esc_attr( self::OPT_LAYOUT ); ?>" id="wohno_default_layout">
							<?php foreach ( $layouts as $value => $label ) : ?>
								<option value="<?php echo esc_attr( $value ); ?>" <?php selected( $layout, $value ); ?>><?php echo esc_html( $label ); ?></option>
							<?php endforeach; ?>
						</select>
					</td>
				</tr>
				<tr>
					<th scope="row"><label for="wohno_default_columns"><?php echo esc_html__( 'Spalten (Raster)', 'wohno' ); ?></label></th>
					<td>
						<input type="number" min="1" max="4" step="1" id="wohno_default_columns"
							name="<?php echo esc_attr( self::OPT_COLUMNS ); ?>" value="<?php echo esc_attr( (string) $columns ); ?>" class="small-text" />
					</td>
				</tr>
			</table>

			<h2><?php echo esc_html__( 'Branding', 'wohno' ); ?></h2>
			<table class="form-table" role="presentation">
				<tr>
					<th scope="row"><label for="wohno_accent_color"><?php echo esc_html__( 'Akzentfarbe', 'wohno' ); ?></label></th>
					<td>
						<input type="color" id="wohno_accent_color" name="<?php echo esc_attr( self::OPT_ACCENT ); ?>"
							value="<?php echo esc_attr( $accent ); ?>" class="wohno-admin__color" />
						<code class="wohno-admin__swatchhex"><?php echo esc_html( $accent ); ?></code>
						<p class="description"><?php echo esc_html__( 'Preis-Pille, Buttons, Links und Hover der Karten.', 'wohno' ); ?></p>
					</td>
				</tr>
				<tr>
					<th scope="row"><label for="wohno_card_radius"><?php echo esc_html__( 'Ecken-Rundung', 'wohno' ); ?></label></th>
					<td>
						<select name="<?php echo esc_attr( self::OPT_RADIUS ); ?>" id="wohno_card_radius">
							<?php foreach ( $radii as $value => $label ) : ?>
								<option value="<?php echo esc_attr( $value ); ?>" <?php selected( $radius, $value ); ?>><?php echo esc_html( $label ); ?></option>
							<?php endforeach; ?>
						</select>
					</td>
				</tr>
			</table>

			<h2><?php echo esc_html__( 'SEO & Attribution', 'wohno' ); ?></h2>
			<table class="form-table" role="presentation">
				<tr>
					<th scope="row"><?php echo esc_html__( 'Wohno-Link', 'wohno' ); ?></th>
					<td>
						<input type="hidden" name="<?php echo esc_attr( self::OPT_ATTRIB ); ?>" value="0" />
						<label class="wohno-admin__switch">
							<input type="checkbox" name="<?php echo esc_attr( self::OPT_ATTRIB ); ?>" value="1" <?php checked( $attrib ); ?> />
							<?php echo esc_html__( '„Bereitgestellt von Wohno" unter den Inseraten anzeigen', 'wohno' ); ?>
						</label>
						<p class="description"><?php echo esc_html__( 'Standardmäßig aus. Wenn du dies aktivierst, erscheint ein kleiner Link zu wohno.de öffentlich unter deinen Inseraten.', 'wohno' ); ?></p>
					</td>
				</tr>
			</table>

			<?php submit_button( __( 'Einstellungen speichern', 'wohno' ) ); ?>
		</form>
		<?php
	}

	/**
	 * Render the "Verbindung" tab (API key + connection test).
	 *
	 * @param bool   $is_set Whether a key is stored.
	 * @param string $masked Masked key hint.
	 * @return void
	 */
	private function render_connection_tab( bool $is_set, string $masked ): void {
		?>
		<form method="post" action="options.php" class="wohno-card-panel">
			<?php settings_fields( self::GROUP_CONNECTION ); ?>
			<h2><?php echo esc_html__( 'API-Key', 'wohno' ); ?></h2>
			<table class="form-table" role="presentation">
				<tr>
					<th scope="row"><label for="wohno_api_key"><?php echo esc_html__( 'API-Key (sk_…)', 'wohno' ); ?></label></th>
					<td>
						<input name="<?php echo esc_attr( self::OPTION_KEY ); ?>" id="wohno_api_key" type="password"
							value="" class="regular-text" autocomplete="off"
							placeholder="<?php echo esc_attr( $is_set ? $masked : 'sk_…' ); ?>" />
						<p class="description">
							<?php echo esc_html__( 'Im Wohno-Dashboard unter API-Keys erstellen — Scope: listings:read.', 'wohno' ); ?>
							<?php if ( $is_set ) : ?>
								<br /><?php echo esc_html__( 'Feld leer lassen, um den gespeicherten Key beizubehalten.', 'wohno' ); ?>
							<?php endif; ?>
						</p>
					</td>
				</tr>
			</table>
			<?php submit_button( __( 'API-Key speichern', 'wohno' ) ); ?>
		</form>

		<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="wohno-card-panel">
			<h2><?php echo esc_html__( 'Verbindung testen', 'wohno' ); ?></h2>
			<p class="description"><?php echo esc_html__( 'Prüft, ob der Key gültig ist und Inserate abgerufen werden können.', 'wohno' ); ?></p>
			<input type="hidden" name="action" value="wohno_test_connection" />
			<?php wp_nonce_field( 'wohno_test_connection' ); ?>
			<?php submit_button( __( 'Verbindung testen', 'wohno' ), 'secondary', 'submit', false ); ?>
		</form>
		<?php
	}

	/**
	 * Render the "Einbinden" tab (copy-ready shortcodes).
	 *
	 * @return void
	 */
	private function render_embed_tab(): void {
		$layouts = array(
			'grid'  => __( 'Raster', 'wohno' ),
			'cards' => __( 'Karten (groß)', 'wohno' ),
			'list'  => __( 'Liste', 'wohno' ),
			'map'   => __( 'Karte', 'wohno' ),
		);
		$types   = array(
			''          => __( 'Alle Typen', 'wohno' ),
			'apartment' => __( 'Wohnung', 'wohno' ),
			'house'     => __( 'Haus', 'wohno' ),
			'studio'    => __( 'Studio', 'wohno' ),
			'wg_room'   => __( 'WG-Zimmer', 'wohno' ),
			'other'     => __( 'Sonstiges', 'wohno' ),
		);
		?>
		<div class="wohno-card-panel">
			<h2><?php echo esc_html__( 'Shortcode-Generator', 'wohno' ); ?></h2>
			<p class="description"><?php echo esc_html__( 'Stelle die Optionen ein — der Shortcode unten aktualisiert sich automatisch. Anschließend kopieren und auf einer Seite einfügen (oder den Block „Wohno – Inserate" verwenden).', 'wohno' ); ?></p>

			<div class="wohno-gen" data-wohno-gen-root>
				<div class="wohno-gen__grid">
					<label class="wohno-gen__field">
						<span><?php echo esc_html__( 'Darstellung', 'wohno' ); ?></span>
						<select data-attr="layout" data-default="grid">
							<?php foreach ( $layouts as $value => $label ) : ?>
								<option value="<?php echo esc_attr( $value ); ?>"><?php echo esc_html( $label ); ?></option>
							<?php endforeach; ?>
						</select>
					</label>
					<label class="wohno-gen__field" data-wohno-gen-columns>
						<span><?php echo esc_html__( 'Spalten (Raster)', 'wohno' ); ?></span>
						<input type="number" min="1" max="4" step="1" data-attr="columns" data-default="3" value="3" />
					</label>
					<label class="wohno-gen__field">
						<span><?php echo esc_html__( 'Anzahl', 'wohno' ); ?></span>
						<input type="number" min="1" max="50" step="1" data-attr="limit" data-default="9" value="9" />
					</label>
					<label class="wohno-gen__field">
						<span><?php echo esc_html__( 'Stadt', 'wohno' ); ?></span>
						<input type="text" data-attr="city" placeholder="<?php echo esc_attr__( 'z. B. Köln', 'wohno' ); ?>" />
					</label>
					<label class="wohno-gen__field">
						<span><?php echo esc_html__( 'PLZ', 'wohno' ); ?></span>
						<input type="text" data-attr="zip" />
					</label>
					<label class="wohno-gen__field">
						<span><?php echo esc_html__( 'Objekttyp', 'wohno' ); ?></span>
						<select data-attr="property_type" data-default="">
							<?php foreach ( $types as $value => $label ) : ?>
								<option value="<?php echo esc_attr( $value ); ?>"><?php echo esc_html( $label ); ?></option>
							<?php endforeach; ?>
						</select>
					</label>
					<label class="wohno-gen__field">
						<span><?php echo esc_html__( 'Zimmer min.', 'wohno' ); ?></span>
						<input type="number" min="0" max="20" step="1" data-attr="rooms_min" />
					</label>
					<label class="wohno-gen__field">
						<span><?php echo esc_html__( 'Zimmer max.', 'wohno' ); ?></span>
						<input type="number" min="0" max="20" step="1" data-attr="rooms_max" />
					</label>
					<label class="wohno-gen__field">
						<span><?php echo esc_html__( 'Max. Miete (€)', 'wohno' ); ?></span>
						<input type="number" min="0" step="50" data-attr="rent_max" />
					</label>
					<label class="wohno-gen__field">
						<span><?php echo esc_html__( 'Suchbegriff', 'wohno' ); ?></span>
						<input type="text" data-attr="q" />
					</label>
				</div>

				<div class="wohno-gen__toggles">
					<label class="wohno-admin__switch"><input type="checkbox" data-attr="search" data-checked="1" /> <?php echo esc_html__( 'Suche & Filter anzeigen', 'wohno' ); ?></label>
					<label class="wohno-admin__switch"><input type="checkbox" data-attr="wbs_only" data-checked="1" /> <?php echo esc_html__( 'Nur WBS-Inserate', 'wohno' ); ?></label>
					<label class="wohno-admin__switch"><input type="checkbox" data-attr="load_more" data-unchecked="0" checked /> <?php echo esc_html__( '„Mehr laden"-Button', 'wohno' ); ?></label>
				</div>

				<div class="wohno-gen__output">
					<code data-wohno-gen-output>[wohno_listings]</code>
					<button type="button" class="button button-primary" data-wohno-gen-copy data-copied="<?php echo esc_attr__( 'Kopiert ✓', 'wohno' ); ?>"><?php echo esc_html__( 'Kopieren', 'wohno' ); ?></button>
				</div>

				<h3 class="wohno-gen__preview-title"><?php echo esc_html__( 'Vorschau', 'wohno' ); ?></h3>
				<div class="wohno-gen__preview" data-wohno-gen-preview></div>
			</div>
		</div>

		<div class="wohno-card-panel">
			<h2><?php echo esc_html__( 'Einzelnes Inserat', 'wohno' ); ?></h2>
			<p class="description"><?php echo esc_html__( 'Wähle ein Inserat aus — der passende Shortcode wird erzeugt. So musst du keine ID heraussuchen.', 'wohno' ); ?></p>
			<?php $listings = $this->listing_options(); ?>
			<?php if ( array() !== $listings ) : ?>
				<div class="wohno-single-pick" data-wohno-single-root>
					<select class="wohno-single-pick__select" data-wohno-single>
						<option value=""><?php echo esc_html__( '— Inserat wählen —', 'wohno' ); ?></option>
						<?php foreach ( $listings as $id => $label ) : ?>
							<option value="<?php echo esc_attr( (string) $id ); ?>"><?php echo esc_html( $label ); ?></option>
						<?php endforeach; ?>
					</select>
					<div class="wohno-gen__output">
						<code data-wohno-single-output>[wohno_listing id="…"]</code>
						<button type="button" class="button button-primary" data-wohno-single-copy data-copied="<?php echo esc_attr__( 'Kopiert ✓', 'wohno' ); ?>"><?php echo esc_html__( 'Kopieren', 'wohno' ); ?></button>
					</div>
				</div>
			<?php else : ?>
				<p class="wohno-admin__hint description">
					<?php echo esc_html__( 'Sobald dein API-Key Inserate liefert, kannst du hier direkt eines auswählen. Alternativ findest du die Inserat-ID in der Adresszeile der Detailseite im Wohno-Dashboard.', 'wohno' ); ?>
				</p>
			<?php endif; ?>
		</div>

		<div class="wohno-card-panel">
			<h2><?php echo esc_html__( 'Beispiele', 'wohno' ); ?></h2>
			<div class="wohno-admin__snippets">
				<?php
				$this->render_snippet( __( 'Suche & Filter', 'wohno' ), '[wohno_listings search="1" limit="12"]' );
				$this->render_snippet( __( 'Karten (groß)', 'wohno' ), '[wohno_listings city="Köln" layout="cards" limit="6"]' );
				$this->render_snippet( __( 'Liste', 'wohno' ), '[wohno_listings city="Köln" layout="list" limit="10"]' );
				$this->render_snippet( __( 'Einzelnes Inserat', 'wohno' ), '[wohno_listing id="…"]' );
				?>
			</div>
		</div>
		<?php
	}

	/**
	 * Render the "Hilfe" tab: quick-start tutorial, FAQ and contact details.
	 *
	 * @return void
	 */
	private function render_help_tab(): void {
		?>
		<div class="wohno-card-panel">
			<h2><?php echo esc_html__( 'In 4 Schritten startklar', 'wohno' ); ?></h2>
			<ol class="wohno-admin__steps">
				<li>
					<strong><?php echo esc_html__( 'API-Key erstellen', 'wohno' ); ?></strong>
					<?php
					printf(
						/* translators: %s: link to the Wohno dashboard */
						esc_html__( 'Im %s unter „API-Keys" einen geheimen Key mit Scope listings:read anlegen.', 'wohno' ),
						'<a href="https://wohno.de/dashboard" target="_blank" rel="noopener">Wohno-Dashboard</a>'
					);
					?>
				</li>
				<li>
					<strong><?php echo esc_html__( 'Verbinden', 'wohno' ); ?></strong>
					<?php echo esc_html__( 'Den Key im Reiter „Verbindung" einfügen, speichern und „Verbindung testen" klicken.', 'wohno' ); ?>
				</li>
				<li>
					<strong><?php echo esc_html__( 'Darstellung wählen', 'wohno' ); ?></strong>
					<?php echo esc_html__( 'Im Reiter „Darstellung" Standard-Layout, Spalten, Farbe und Rundung festlegen.', 'wohno' ); ?>
				</li>
				<li>
					<strong><?php echo esc_html__( 'Inserate einbinden', 'wohno' ); ?></strong>
					<?php echo esc_html__( 'Block „Wohno – Inserate" einfügen, ein Widget nutzen oder einen Shortcode aus dem Reiter „Einbinden" kopieren.', 'wohno' ); ?>
				</li>
			</ol>
			<p class="description wohno-admin__hint">
				<?php
				printf(
					/* translators: %s: link to the detail page on wohno.de */
					esc_html__( 'Ein Klick auf eine Karte öffnet die Detailseite auf %s — dort läuft die komplette Bewerbung (Login, Mappe, DSGVO). Auf deiner Seite entstehen keine Bewerberdaten.', 'wohno' ),
					'wohno.de'
				);
				?>
			</p>
		</div>

		<div class="wohno-card-panel">
			<h2><?php echo esc_html__( 'Häufige Fragen', 'wohno' ); ?></h2>
			<div class="wohno-admin__faq">
				<?php
				$this->render_faq(
					__( 'Warum sehe ich keine Inserate?', 'wohno' ),
					__( 'Prüfe im Reiter „Verbindung" mit „Verbindung testen", ob der Key gültig ist. Sind die Filter (Stadt, Preis …) evtl. zu eng? Antworten werden zudem ~5 Minuten zwischengespeichert — neue Inserate erscheinen kurz verzögert.', 'wohno' )
				);
				$this->render_faq(
					__( 'Brauche ich ein Wohno-Konto?', 'wohno' ),
					__( 'Ja. Du erstellst im Wohno-Dashboard einen API-Key mit dem Scope listings:read.', 'wohno' )
				);
				$this->render_faq(
					__( 'Laufen Bewerbungen über meine Seite?', 'wohno' ),
					__( 'Nein. Detailseite und Bewerbung laufen first-party auf wohno.de. Auf deiner Seite entstehen keine personenbezogenen Bewerberdaten.', 'wohno' )
				);
				$this->render_faq(
					__( 'Werden meine Inserate bei Google indexiert?', 'wohno' ),
					__( 'Ja, die Übersicht wird als echtes HTML auf deiner Domain gerendert. Die einzelnen Detailseiten liegen kanonisch auf wohno.de.', 'wohno' )
				);
				$this->render_faq(
					__( 'Ist mein API-Key sicher?', 'wohno' ),
					__( 'Ja. Der Key wird ausschließlich server-seitig gespeichert (verschlüsselt, sofern der Server openssl bereitstellt) und nur über HTTPS gesendet — nie im Browser, nie im Seitenquelltext.', 'wohno' )
				);
				$this->render_faq(
					__( 'Wie ändere ich das Aussehen der Karten?', 'wohno' ),
					__( 'Im Reiter „Darstellung" (Layout, Akzentfarbe, Rundung). Für volle Kontrolle kannst du das Template wohno/listing-card.php in dein Theme kopieren.', 'wohno' )
				);
				$this->render_faq(
					__( 'Werden auch „diskrete" Inserate angezeigt?', 'wohno' ),
					__( 'Nein. Diskrete Inserate werden von der Wohno-API bewusst nicht ausgeliefert.', 'wohno' )
				);
				?>
			</div>
		</div>

		<div class="wohno-card-panel">
			<h2><?php echo esc_html__( 'Kontakt & Support', 'wohno' ); ?></h2>
			<ul class="wohno-admin__contact">
				<li>
					<span class="dashicons dashicons-admin-site" aria-hidden="true"></span>
					<a href="https://wohno.de" target="_blank" rel="noopener">wohno.de</a>
				</li>
				<li>
					<span class="dashicons dashicons-email" aria-hidden="true"></span>
					<a href="mailto:info@wohno.de">info@wohno.de</a>
				</li>
				<li>
					<span class="dashicons dashicons-format-chat" aria-hidden="true"></span>
					<a href="https://wohno.de/kontakt" target="_blank" rel="noopener"><?php echo esc_html__( 'Kontaktformular', 'wohno' ); ?></a>
				</li>
				<li>
					<span class="dashicons dashicons-location" aria-hidden="true"></span>
					WOHNO UG (haftungsbeschränkt), Bachstr. 36, 52066 Aachen
				</li>
			</ul>
			<p class="wohno-admin__legal">
				<a href="https://wohno.de/agb" target="_blank" rel="noopener"><?php echo esc_html__( 'AGB', 'wohno' ); ?></a> ·
				<a href="https://wohno.de/datenschutz" target="_blank" rel="noopener"><?php echo esc_html__( 'Datenschutz', 'wohno' ); ?></a> ·
				<a href="https://wohno.de/impressum" target="_blank" rel="noopener"><?php echo esc_html__( 'Impressum', 'wohno' ); ?></a>
			</p>
		</div>
		<?php
	}

	/**
	 * Render one FAQ entry as a native (buildless) disclosure.
	 *
	 * @param string $question The question (summary).
	 * @param string $answer   The answer body.
	 * @return void
	 */
	private function render_faq( string $question, string $answer ): void {
		?>
		<details class="wohno-admin__faq-item">
			<summary><?php echo esc_html( $question ); ?></summary>
			<p><?php echo esc_html( $answer ); ?></p>
		</details>
		<?php
	}

	/**
	 * Fetch the org's listings for the single-listing picker (id => label).
	 *
	 * @return array<string, string>
	 */
	private function listing_options(): array {
		$result = $this->client->listings( array( 'limit' => 50 ) );
		if ( is_wp_error( $result ) || empty( $result['listings'] ) ) {
			return array();
		}

		$options = array();
		foreach ( $result['listings'] as $listing ) {
			if ( ! is_array( $listing ) || empty( $listing['id'] ) ) {
				continue;
			}
			$id    = (string) $listing['id'];
			$title = isset( $listing['title'] ) && '' !== $listing['title'] ? (string) $listing['title'] : $id;
			$place = trim( (string) ( $listing['zipCode'] ?? '' ) . ' ' . (string) ( $listing['city'] ?? '' ) );

			$options[ $id ] = '' !== $place ? $title . ' — ' . $place : $title;
		}

		return $options;
	}

	/**
	 * Render a labelled, copy-friendly shortcode snippet.
	 *
	 * @param string $label   Human label for the snippet.
	 * @param string $snippet The shortcode example.
	 * @return void
	 */
	private function render_snippet( string $label, string $snippet ): void {
		?>
		<div class="wohno-admin__snippet">
			<span class="wohno-admin__snippet-label"><?php echo esc_html( $label ); ?></span>
			<code><?php echo esc_html( $snippet ); ?></code>
		</div>
		<?php
	}

	/**
	 * Handle the "test connection" POST.
	 *
	 * @return void
	 */
	public function handle_test(): void {
		if ( ! current_user_can( 'manage_options' ) || ! check_admin_referer( 'wohno_test_connection' ) ) {
			wp_die( esc_html__( 'Nicht erlaubt.', 'wohno' ) );
		}

		$result = $this->client->test_connection();
		$ok     = true === $result;
		set_transient( 'wohno_test_result', $ok ? '1' : ( '0:' . $result->get_error_message() ), 60 );

		wp_safe_redirect( $this->tab_url( 'connection' ) );
		exit;
	}

	/**
	 * Show connection-test feedback and the contract-mismatch notice.
	 *
	 * @return void
	 */
	public function maybe_notice(): void {
		$screen      = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
		$on_our_page = $screen && str_contains( (string) $screen->id, self::PAGE_SLUG );

		$test = get_transient( 'wohno_test_result' );
		if ( false !== $test && $on_our_page ) {
			delete_transient( 'wohno_test_result' );
			if ( '1' === $test ) {
				echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Verbindung erfolgreich.', 'wohno' ) . '</p></div>';
			} else {
				$msg = substr( (string) $test, 2 );
				echo '<div class="notice notice-error is-dismissible"><p>' . esc_html( $msg ) . '</p></div>';
			}
		}

		if ( $this->client->has_contract_mismatch() && current_user_can( 'manage_options' ) ) {
			echo '<div class="notice notice-warning"><p>'
				. esc_html__( 'Das Wohno-Plugin ist veraltet (API-Contract-Mismatch). Bitte aktualisieren.', 'wohno' )
				. '</p></div>';
		}
	}
}
