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

namespace Hafenstudios\Wellenbrecher\Admin;

use Hafenstudios\Wellenbrecher\Db\StatsRepository;

defined( 'ABSPATH' ) || exit;

/**
 * CSV-Export der Langzeit-Statistik hs_spam_stats (Pro-Reports, Bauplan Kap. 8).
 * Aggregiert und OHNE Personenbezug (die Stats-Tabelle enthaelt nur Datum,
 * Kanal, Verdict, Anzahl). Auslieferung ueber admin-post mit Nonce und Cap
 * hs_manage_spam. Nur bei aktivem Pro-Gate verdrahtet.
 *
 * CSV-Format wie der Leadlotse-Teilnehmer-Export (LR1-2): UTF-8-BOM, Semikolon-
 * Trenner (deutsches Excel), CRLF, Anfuehrungszeichen-Escaping und Formel-
 * Entschaerfung gegen CSV-Injection.
 */
class ReportsExport {

	public const ACTION = 'wellenbrecher_export_stats';

	public const RANGES = array( 7, 30, 90 );

	protected StatsRepository $stats;

	/**
	 * @param StatsRepository $stats Tageszaehler.
	 */
	public function __construct( StatsRepository $stats ) {
		$this->stats = $stats;
	}

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

	/**
	 * Streamt die CSV-Datei.
	 *
	 * @return void
	 */
	public function handle(): void {
		if ( ! current_user_can( 'hs_manage_spam' ) ) {
			wp_die( esc_html__( 'Keine Berechtigung.', 'wellenbrecher' ) );
		}
		check_admin_referer( self::ACTION );

		$days = isset( $_GET['days'] ) ? (int) $_GET['days'] : 30;
		if ( ! in_array( $days, self::RANGES, true ) ) {
			$days = 30;
		}

		$csv = self::build_csv( $this->stats->rows( $days ) );

		nocache_headers();
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="wellenbrecher-statistik-' . gmdate( 'Y-m-d' ) . '.csv"' );
		echo $csv; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSV-Datei, jede Zelle in build_csv escaped.
		exit;
	}

	/**
	 * Baut den CSV-Inhalt aus Stats-Zeilen (rein und testbar).
	 *
	 * @param array<int, array<string, mixed>> $rows Stats-Zeilen (stat_date, channel, verdict, cnt).
	 * @return string
	 */
	public static function build_csv( array $rows ): string {
		// UTF-8-BOM: deutsches Excel erkennt die Kodierung.
		$out  = "\xEF\xBB\xBF";
		$out .= self::line(
			array(
				__( 'Datum', 'wellenbrecher' ),
				__( 'Kanal', 'wellenbrecher' ),
				__( 'Verdict', 'wellenbrecher' ),
				__( 'Anzahl', 'wellenbrecher' ),
			)
		);

		foreach ( $rows as $row ) {
			$out .= self::line(
				array(
					(string) ( $row['stat_date'] ?? '' ),
					(string) ( $row['channel'] ?? '' ),
					(string) ( $row['verdict'] ?? '' ),
					(string) (int) ( $row['cnt'] ?? 0 ),
				)
			);
		}

		return $out;
	}

	/**
	 * Eine CSV-Zeile (Semikolon-getrennt, CRLF).
	 *
	 * @param array<int, string> $cells Zellen.
	 * @return string
	 */
	protected static function line( array $cells ): string {
		return implode( ';', array_map( array( self::class, 'cell' ), $cells ) ) . "\r\n";
	}

	/**
	 * Eine Zelle: Formel-Entschaerfung (fuehrendes =,+,-,@ bekommt ein Apostroph)
	 * und Anfuehrungszeichen-Escaping.
	 *
	 * @param string $value Wert.
	 * @return string
	 */
	protected static function cell( string $value ): string {
		if ( '' !== $value && in_array( $value[0], array( '=', '+', '-', '@' ), true ) ) {
			$value = "'" . $value;
		}
		return '"' . str_replace( '"', '""', $value ) . '"';
	}
}
