<?php
/**
 * @package Hafenstudios\Wellenbrecher
 */

namespace Hafenstudios\Wellenbrecher\Admin;

use Hafenstudios\Core\Events\EventBus;
use Hafenstudios\Wellenbrecher\Db\SpamLogRepository;

defined( 'ABSPATH' ) || exit;

/**
 * Formular-Quarantaene (Bauplan Kap. 8, WB6/WB10): Liste der quarantinierten
 * Leadlotse-Submits mit strikt escaptem Payload (NIEMALS als HTML gerendert)
 * und den Aktionen Wiederherstellen und Loeschen - je Eintrag (per Auswahl)
 * und als Bulk.
 *
 * Wiederherstellen laeuft ueber den designierten Leadlotse-Restore-Weg (W-L1 c,
 * Filter `hafenstudios/leadlotse_restore_submit`), der den Payload mit
 * Bypass-Flag erneut durch die Submit-Pipeline schickt: der Lead entsteht
 * inklusive DOI/Kurato-Events. Bei Erfolg wird die Log-Zeile GELOESCHT (WB10),
 * sonst zaehlt die Wiederholungstaeter-Regel den rehabilitierten Absender bis
 * zum Ende des Salt-Wochenfensters weiter als Treffer.
 *
 * Die Kommentar-Quarantaene bleibt im nativen WP-Spam-Ordner; die Seite
 * verlinkt nur dorthin.
 */
class QuarantinePage {

	public const SLUG        = 'wellenbrecher-quarantine';
	public const ACTION_BULK = 'wellenbrecher_quarantine_bulk';

	public const PER_PAGE = 20;

	protected SpamLogRepository $log;

	/**
	 * @param SpamLogRepository $log Spam-Log.
	 */
	public function __construct( SpamLogRepository $log ) {
		$this->log = $log;
	}

	/**
	 * Registriert den admin-post-Handler.
	 *
	 * @return void
	 */
	public function register(): void {
		add_action( 'admin_post_' . self::ACTION_BULK, array( $this, 'handle_bulk' ) );
	}

	/**
	 * Rendert die Seite.
	 *
	 * @return void
	 */
	public function render(): void {
		if ( ! current_user_can( 'hs_manage_spam' ) ) {
			wp_die( esc_html__( 'Sie haben keine Berechtigung fuer die Formular-Quarantaene.', 'wellenbrecher' ) );
		}

		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Nur Anzeige/Pagination nach Redirect.
		$page   = isset( $_GET['paged'] ) ? max( 1, absint( wp_unslash( $_GET['paged'] ) ) ) : 1;
		$notice = isset( $_GET['msg'] ) ? sanitize_key( wp_unslash( $_GET['msg'] ) ) : '';
		// phpcs:enable

		$result = $this->log->query(
			array(
				'channel'  => 'leadlotse',
				'verdict'  => SpamLogRepository::VERDICT_QUARANTINED,
				'page'     => $page,
				'per_page' => self::PER_PAGE,
			)
		);

		echo '<div class="wrap">';
		echo '<h1 class="wp-heading-inline">' . esc_html__( 'Wellenbrecher: Formular-Quarantaene', 'wellenbrecher' ) . '</h1>';
		echo '<hr class="wp-header-end" />';

		$this->render_notice( $notice );

		echo '<p>' . esc_html__( 'Diese Leadlotse-Formulare wurden als moeglicher Spam abgefangen und nicht gespeichert. Pruefen Sie den Inhalt. Bei "Wiederherstellen" durchlaeuft die Anfrage die Formular-Pipeline erneut und wird zu einem normalen Lead (inklusive Bestaetigungs-Mails), der Log-Eintrag wird dabei geloescht.', 'wellenbrecher' ) . '</p>';
		echo '<p><a href="' . esc_url( admin_url( 'edit-comments.php?comment_status=spam' ) ) . '">' . esc_html__( 'Quarantinierte Kommentare liegen im WordPress-Spam-Ordner.', 'wellenbrecher' ) . '</a></p>';

		$this->render_table( $result, $page );

		echo '</div>';
	}

	/**
	 * Statusmeldung nach einer Aktion.
	 *
	 * @param string $notice Statuscode.
	 * @return void
	 */
	protected function render_notice( string $notice ): void {
		if ( 'restored' === $notice ) {
			echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Die ausgewaehlten Anfragen wurden wiederhergestellt und als Lead uebernommen.', 'wellenbrecher' ) . '</p></div>';
		} elseif ( 'deleted' === $notice ) {
			echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Die ausgewaehlten Eintraege wurden geloescht.', 'wellenbrecher' ) . '</p></div>';
		} elseif ( 'restore_failed' === $notice ) {
			echo '<div class="notice notice-error"><p>' . esc_html__( 'Mindestens eine Anfrage konnte nicht wiederhergestellt werden. Ist Leadlotse aktiv und das zugehoerige Formular noch vorhanden? Die betroffenen Eintraege bleiben in der Quarantaene.', 'wellenbrecher' ) . '</p></div>';
		}
	}

	/**
	 * Die Quarantaene-Tabelle mit Payload-Ansicht und Bulk-Aktionen.
	 *
	 * @param array<string, mixed> $result Ergebnis von SpamLogRepository::query.
	 * @param int                  $page   Aktuelle Seite.
	 * @return void
	 */
	protected function render_table( array $result, int $page ): void {
		$items = (array) ( $result['items'] ?? array() );
		$total = (int) ( $result['total'] ?? 0 );

		if ( array() === $items ) {
			echo '<p>' . esc_html__( 'Die Quarantaene ist leer. Es wurden keine Formular-Anfragen abgefangen.', 'wellenbrecher' ) . '</p>';
			return;
		}

		echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '">';
		echo '<input type="hidden" name="action" value="' . esc_attr( self::ACTION_BULK ) . '" />';
		wp_nonce_field( self::ACTION_BULK );

		echo '<table class="wp-list-table widefat fixed striped">';
		echo '<thead><tr>';
		echo '<td class="check-column"><input type="checkbox" onclick="this.closest(\'table\').querySelectorAll(\'tbody input[type=checkbox]\').forEach(function(c){c.checked=this.checked}, this)" aria-label="' . esc_attr__( 'Alle auswaehlen', 'wellenbrecher' ) . '" /></td>';
		echo '<th scope="col">' . esc_html__( 'Zeit (UTC)', 'wellenbrecher' ) . '</th>';
		echo '<th scope="col">' . esc_html__( 'Formular', 'wellenbrecher' ) . '</th>';
		echo '<th scope="col">' . esc_html__( 'Punkte', 'wellenbrecher' ) . '</th>';
		echo '<th scope="col">' . esc_html__( 'Inhalt', 'wellenbrecher' ) . '</th>';
		echo '</tr></thead><tbody>';

		foreach ( $items as $item ) {
			$item = (array) $item;
			echo '<tr>';
			echo '<th scope="row" class="check-column"><input type="checkbox" name="wb_ids[]" value="' . esc_attr( (string) (int) ( $item['id'] ?? 0 ) ) . '" /></th>';
			echo '<td>' . esc_html( (string) ( $item['created_at'] ?? '' ) ) . '</td>';
			echo '<td>' . esc_html( (string) (int) ( $item['form_id'] ?? 0 ) ) . '</td>';
			echo '<td>' . esc_html( (string) (int) ( $item['score'] ?? 0 ) ) . '</td>';
			echo '<td>' . $this->payload_html( (string) ( $item['payload'] ?? '' ) ) . '</td>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- payload_html escaped jeden Wert einzeln.
			echo '</tr>';
		}

		echo '</tbody></table>';

		echo '<p>';
		echo '<button type="submit" name="do" value="restore" class="button button-primary">' . esc_html__( 'Ausgewaehlte wiederherstellen', 'wellenbrecher' ) . '</button> ';
		echo '<button type="submit" name="do" value="delete" class="button">' . esc_html__( 'Ausgewaehlte loeschen', 'wellenbrecher' ) . '</button>';
		echo '</p>';
		echo '</form>';

		$this->render_pagination( $total, $page );
	}

	/**
	 * Payload strikt escaped als Feld-Liste (NIE als HTML rendern, Bauplan
	 * Kap. 11). Zeigt die eingereichten Feldwerte, technische Signalfelder
	 * bleiben aussen vor.
	 *
	 * @param string $payload JSON-Payload aus dem Log.
	 * @return string Sicheres HTML (jeder dynamische Wert escaped).
	 */
	protected function payload_html( string $payload ): string {
		$data  = json_decode( $payload, true );
		$input = is_array( $data ) && is_array( $data['input'] ?? null ) ? $data['input'] : array();
		if ( array() === $input ) {
			return esc_html__( '(kein Inhalt gespeichert)', 'wellenbrecher' );
		}

		$skip = array( 'wb_token', 'wb_js', 'wb_events', 'll_ts', 'll_website_url' );
		$rows = array();
		foreach ( $input as $key => $value ) {
			if ( in_array( (string) $key, $skip, true ) ) {
				continue;
			}
			$flat  = is_array( $value ) ? implode( ', ', array_map( 'strval', $value ) ) : (string) $value;
			$flat  = mb_substr( $flat, 0, 300 );
			$rows[] = '<strong>' . esc_html( (string) $key ) . ':</strong> ' . esc_html( $flat );
		}

		return array() === $rows
			? esc_html__( '(kein Inhalt gespeichert)', 'wellenbrecher' )
			: implode( '<br />', $rows );
	}

	/**
	 * Einfache Zurueck/Weiter-Pagination.
	 *
	 * @param int $total Gesamtzahl.
	 * @param int $page  Aktuelle Seite.
	 * @return void
	 */
	protected function render_pagination( int $total, int $page ): void {
		$pages = (int) ceil( $total / self::PER_PAGE );
		if ( $pages <= 1 ) {
			return;
		}
		$base = admin_url( 'admin.php?page=' . self::SLUG );

		echo '<p class="tablenav-pages">';
		if ( $page > 1 ) {
			echo '<a class="button" href="' . esc_url( add_query_arg( 'paged', $page - 1, $base ) ) . '">' . esc_html__( 'Zurueck', 'wellenbrecher' ) . '</a> ';
		}
		/* translators: 1: aktuelle Seite, 2: Seitenzahl gesamt */
		echo esc_html( sprintf( __( 'Seite %1$d von %2$d', 'wellenbrecher' ), $page, $pages ) );
		if ( $page < $pages ) {
			echo ' <a class="button" href="' . esc_url( add_query_arg( 'paged', $page + 1, $base ) ) . '">' . esc_html__( 'Weiter', 'wellenbrecher' ) . '</a>';
		}
		echo '</p>';
	}

	/**
	 * Bulk-Handler (Wiederherstellen oder Loeschen).
	 *
	 * @return void
	 */
	public function handle_bulk(): void {
		if ( ! current_user_can( 'hs_manage_spam' ) ) {
			wp_die( esc_html__( 'Keine Berechtigung.', 'wellenbrecher' ) );
		}
		check_admin_referer( self::ACTION_BULK );

		$ids = isset( $_POST['wb_ids'] ) && is_array( $_POST['wb_ids'] )
			? array_values( array_filter( array_map( 'absint', wp_unslash( $_POST['wb_ids'] ) ) ) )
			: array();
		$do = isset( $_POST['do'] ) ? sanitize_key( wp_unslash( $_POST['do'] ) ) : '';

		$msg = 'none';
		if ( array() !== $ids ) {
			if ( 'restore' === $do ) {
				$msg = $this->restore_ids( $ids );
			} elseif ( 'delete' === $do ) {
				$this->log->delete( $ids );
				$msg = 'deleted';
			}
		}

		wp_safe_redirect( add_query_arg( array( 'page' => self::SLUG, 'msg' => $msg ), admin_url( 'admin.php' ) ) );
		exit;
	}

	/**
	 * Stellt die ausgewaehlten Eintraege wieder her. Bei Erfolg wird die
	 * Log-Zeile geloescht (WB10). Ein Fehlschlag laesst den Eintrag stehen.
	 *
	 * @param array<int, int> $ids Log-IDs.
	 * @return string Statuscode fuer den Redirect.
	 */
	protected function restore_ids( array $ids ): string {
		$restored = 0;
		$failed   = 0;

		foreach ( $ids as $id ) {
			$row = $this->log->find( (int) $id );
			if ( null === $row ) {
				++$failed;
				continue;
			}

			$payload = json_decode( (string) ( $row['payload'] ?? '' ), true );
			$input   = is_array( $payload ) && is_array( $payload['input'] ?? null ) ? $payload['input'] : array();
			$context = is_array( $payload ) && is_array( $payload['context'] ?? null ) ? $payload['context'] : array();
			$form_id = (int) ( $row['form_id'] ?? 0 );

			/**
			 * Designierter Leadlotse-Restore-Weg (W-L1 c): schickt den Payload mit
			 * Bypass-Flag erneut durch die Submit-Pipeline. Rueckgabe: Erfolgs-Array,
			 * WP_Error oder null (Leadlotse nicht aktiv).
			 *
			 * @param mixed                $default null.
			 * @param int                  $form_id Formular-ID.
			 * @param array<string, mixed> $input   Roh-Submit.
			 * @param array<string, mixed> $context Submit-Kontext (source_url, utm_*).
			 */
			$result = EventBus::filter( 'leadlotse_restore_submit', null, $form_id, $input, $context );

			if ( is_array( $result ) && ! empty( $result['success'] ) ) {
				/**
				 * Erfolgreiche Wiederherstellung = Ham-Signal (Pro/Bayes). Der
				 * Bayes-Trainer haengt sich hier ein; ohne Pro ist es ein Noop.
				 * Literal statt Trainer-Konstante, damit die Free-Seite keinen
				 * harten Bezug auf die Pro-Klasse hat (wie SILENT_DROP, WB16).
				 * Feuert VOR dem Loeschen, solange der Payload noch vorliegt.
				 */
				do_action( 'wellenbrecher_quarantine_restored', $row );

				$this->log->delete( array( (int) $id ) ); // WB10: Log-Eintrag bei Erfolg loeschen.
				++$restored;
			} else {
				++$failed;
			}
		}

		return $failed > 0 ? 'restore_failed' : 'restored';
	}
}
