<?php
/**
 * File Path: includes/export/class-mbs-exporter-csv.php
 *
 * CSV Exporter (PRO)
 *
 * Streams all published mbs_book posts and their active format rows as a
 * downloadable CSV file. Column headers match MBS_Importer_CSV::ACCEPTED_COLUMNS
 * exactly, enabling clean round-trip import/export without manual remapping.
 *
 * Each format row is exported as one CSV row. A book with three formats
 * (paperback, ebook, hardcover) produces three rows, all sharing the same
 * title, author, publisher, and post-level metadata.
 *
 * Data helpers (column_headers, get_book_data, build_row, safe_cell) are
 * provided by MBS_Book_Export_Data (D-001, D-002, D-003).
 *
 * Gates: mbs_is_registered() + mbs_is_pro() (GP-T-1).
 * Output: direct HTTP stream -- calls exit on completion.
 * SQL: all queries go through MBS_Format_Row_DAO (GP-SQL-1).
 *
 * @package MyBookShowroom
 * @since   1.0.0
 */
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class MBS_Exporter_CSV { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- mbs_/MBS_ prefix is correct; scanner not configured with plugin prefix

	/**
	 * Stream a CSV export to the browser and exit.
	 *
	 * Called directly by the mbs_export_csv AJAX handler after nonce and
	 * capability checks have already passed. This method enforces its own
	 * license gates as a defense-in-depth measure (GP-T-1).
	 *
	 * @return void Does not return -- exits after streaming.
	 */
	public static function download(): void {
		if ( ! mbs_is_registered() ) {
			wp_die( esc_html__( 'A valid license is required to export books.', 'my-book-showroom' ), 403 );
		}

		if ( ! mbs_is_pro() ) {
			wp_die( esc_html__( 'CSV export requires a PRO license.', 'my-book-showroom' ), 403 );
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have permission to export books.', 'my-book-showroom' ), 403 );
		}

		$filename = 'mbs-books-' . gmdate( 'Y-m-d' ) . '.csv';

		// Disable output buffering so fputcsv streams directly.
		while ( ob_get_level() ) {
			ob_end_clean();
		}

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

		$output = fopen( 'php://output', 'w' );

		// UTF-8 BOM so Excel opens the file correctly without garbling accented characters.
		fwrite( $output, "\xEF\xBB\xBF" ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite -- WP_Filesystem migration deferred to PC-FILESYS sprint; PHP native file ops are safe here (temp files in get_temp_dir(), never inside wp-content)

		// Header row -- must match ACCEPTED_COLUMNS for round-trip compatibility.
		fputcsv( $output, MBS_Book_Export_Data::column_headers() );

		// Query all published books. No post limit -- this is an admin export.
		$query = new WP_Query( MBS_Book_Export_Data::get_all_books_query_args() );

		while ( $query->have_posts() ) {
			$query->the_post();
			$post_id = get_the_ID();

			// Shared book-level data -- same on every format row for this book.
			$book_data = MBS_Book_Export_Data::get_book_data( $post_id );

			// Get all active format rows via DAO (GP-SQL-1).
			$format_rows = MBS_Format_Row_DAO::get_by_post( $post_id );

			if ( empty( $format_rows ) ) {
				// Book exists but has no format rows -- export as a single row
				// with empty format-level fields so the book title is preserved.
				fputcsv( $output, MBS_Book_Export_Data::build_row( $book_data, null ) );
			} else {
				foreach ( $format_rows as $format_row ) {
					fputcsv( $output, MBS_Book_Export_Data::build_row( $book_data, $format_row ) );
				}
			}
		}

		wp_reset_postdata();
		fclose( $output ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- WP_Filesystem migration deferred to PC-FILESYS sprint; PHP native file ops are safe here (temp files in get_temp_dir(), never inside wp-content)

		exit;
	}
}
