<?php
/**
 * CSV exporter.
 *
 * @package SubmissionInbox
 */

namespace SUBIN\Export;

use SUBIN\Security\Capabilities;

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

/**
 * Streams admin CSV exports.
 */
class CsvExporter {
	/**
	 * Export leads.
	 *
	 * @param array<int,array<int,string>> $rows CSV rows.
	 * @param string                       $filename File name.
	 * @return void
	 */
	public function export_leads( array $rows, $filename ) {
		$this->export( $rows, $filename, Capabilities::EXPORT_LEADS );
	}

	/**
	 * Export email events.
	 *
	 * @param array<int,array<int,string>> $rows CSV rows.
	 * @param string                       $filename File name.
	 * @return void
	 */
	public function export_email_events( array $rows, $filename ) {
		$this->export( $rows, $filename, Capabilities::EXPORT_EMAIL_LOG );
	}

	/**
	 * Stream CSV response.
	 *
	 * @param array<int,array<int,string>> $rows       CSV rows.
	 * @param string                       $filename   File name.
	 * @param string                       $capability Required export capability.
	 * @return void
	 */
	private function export( array $rows, $filename, $capability ) {
		if ( ! Capabilities::can_current_user( $capability ) ) {
			wp_die( esc_html__( 'You do not have permission to perform this action.', 'submission-inbox' ) );
		}

		if ( ob_get_length() ) {
			ob_clean();
		}

		nocache_headers();
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="' . sanitize_file_name( $filename ) . '"' );
		header( 'Pragma: no-cache' );
		header( 'Expires: 0' );

		$handle = fopen( 'php://output', 'w' );
		if ( false === $handle ) {
			exit;
		}

		echo "\xEF\xBB\xBF";
		foreach ( $rows as $row ) {
			fputcsv( $handle, array_map( array( $this, 'string_value' ), $row ) );
		}

		exit;
	}

	/**
	 * Normalize CSV cell.
	 *
	 * @param mixed $value Value.
	 * @return string
	 */
	private function string_value( $value ) {
		$value = sanitize_textarea_field( (string) $value );

		/*
		 * Spreadsheet applications may interpret attacker-controlled values as
		 * formulas even when the CSV field is correctly quoted. Prefix dangerous
		 * cells with an apostrophe so they are opened as plain text.
		 */
		if ( preg_match( '/^[\x00-\x20\x{FEFF}]*[=+\-@]/u', $value ) ) {
			$value = "'" . $value;
		}

		return $value;
	}
}
