<?php
/**
 * Export Class
 *
 * @package Giraforms
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class GiraForms_Export
 */
class GiraForms_Export {

	/**
	 * Export submissions to CSV.
	 *
	 * @param string $form_id Form ID.
	 * @param array  $args Additional arguments.
	 */
	public static function export_to_csv( $form_id = '', $args = array() ) {
		// Verify nonce
		if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'giraforms_export_csv' ) ) {
			wp_die( esc_html__( 'Security check failed.', 'giraforms' ) );
		}

		// Check permissions
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have the necessary permissions.', 'giraforms' ) );
		}

		// Validate form_id if provided
		if ( ! empty( $form_id ) ) {
			$form_id = sanitize_text_field( $form_id );
			$valid_forms = GiraForms_Submissions::get_form_ids();
			if ( ! in_array( $form_id, $valid_forms, true ) ) {
				wp_die( esc_html__( 'Invalid form ID.', 'giraforms' ) );
			}
		}

		// Get submissions
		$query_args = array_merge(
			array(
				'form_id' => $form_id,
				'limit'   => 9999,
			),
			$args
		);

		$submissions = GiraForms_Submissions::get_submissions( $query_args );

		if ( empty( $submissions ) ) {
			wp_die( esc_html__( 'No submissions to export.', 'giraforms' ) );
		}

		// Prepare CSV field keys and human-readable labels.
		$field_keys  = self::get_csv_field_keys( $submissions );
		$label_map   = self::build_label_map( $submissions );
		$header_row  = self::build_header_row( $field_keys, $label_map );

		// Set headers for download
		$filename = 'giraforms-' . ( $form_id ? sanitize_file_name( $form_id ) . '-' : '' ) . gmdate( 'Y-m-d-H-i-s' ) . '.csv';
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename=' . $filename );
		header( 'Pragma: no-cache' );
		header( 'Expires: 0' );

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

		// Add BOM for Excel UTF-8 compatibility
		fprintf( $output, chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ) );

		// Write headers
		fputcsv( $output, $header_row );

		// Write data
		foreach ( $submissions as $submission ) {
			$row = self::prepare_csv_row( $submission, $field_keys );
			fputcsv( $output, $row );
		}

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
		fclose( $output );
		exit;
	}

	/**
	 * Get ordered field keys (fixed columns + dynamic form fields).
	 *
	 * @param array $submissions Submissions array.
	 * @return array
	 */
	private static function get_csv_field_keys( $submissions ) {
		$keys = array(
			'ID',
			'Form ID',
			'Date',
			'Status',
			'IP Address',
		);

		// Get all unique field keys
		$field_keys = array();
		foreach ( $submissions as $submission ) {
			if ( isset( $submission['data'] ) && is_array( $submission['data'] ) ) {
				foreach ( $submission['data'] as $key => $value ) {
					// Skip internal fields
					if ( strpos( $key, '_' ) === 0 ) {
						continue;
					}
					if ( ! in_array( $key, $field_keys, true ) ) {
						$field_keys[] = $key;
					}
				}
			}
		}

		return array_merge( $keys, $field_keys );
	}

	/**
	 * Build a label map from stored _field_labels meta across all submissions.
	 *
	 * @param array $submissions Submissions array.
	 * @return array Field key => human-readable label.
	 */
	private static function build_label_map( $submissions ) {
		$labels = array();
		foreach ( $submissions as $submission ) {
			if ( isset( $submission['data']['_field_labels'] ) && is_array( $submission['data']['_field_labels'] ) ) {
				foreach ( $submission['data']['_field_labels'] as $key => $label ) {
					if ( ! isset( $labels[ $key ] ) && '' !== $label ) {
						$labels[ $key ] = $label;
					}
				}
			}
		}
		return $labels;
	}

	/**
	 * Build the display header row using labels when available.
	 *
	 * @param array $field_keys Ordered field keys.
	 * @param array $label_map  Field key => label mapping.
	 * @return array
	 */
	private static function build_header_row( $field_keys, $label_map ) {
		$type_labels = array(
			'text'        => 'Text',
			'email'       => 'Email',
			'phone'       => 'Phone',
			'number'      => 'Number',
			'url'         => 'URL',
			'textarea'    => 'Textarea',
			'select'      => 'Select',
			'checkbox'    => 'Checkbox',
			'radio'       => 'Radio',
			'date'        => 'Date',
			'time'        => 'Time',
			'password'    => 'Password',
			'hidden'      => 'Hidden',
			'range'       => 'Range',
			'color'       => 'Color',
			'consent'     => 'Consent',
			'file'        => 'File',
			'rating'      => 'Rating',
			'signature'   => 'Signature',
			'calendar'    => 'Calendar',
			'booking'     => 'Booking',
			'currency'    => 'Currency',
			'geolocation' => 'Geolocation',
		);

		$headers = array();
		foreach ( $field_keys as $key ) {
			if ( isset( $label_map[ $key ] ) ) {
				$headers[] = $label_map[ $key ];
			} else {
				$prefix    = strstr( $key, '_', true );
				$headers[] = ( false !== $prefix && isset( $type_labels[ $prefix ] ) ) ? $type_labels[ $prefix ] : $key;
			}
		}
		return $headers;
	}

	/**
	 * Prepare CSV row data.
	 *
	 * @param array $submission Submission data.
	 * @param array $headers CSV headers.
	 * @return array
	 */
	private static function prepare_csv_row( $submission, $headers ) {
		$row = array();

		foreach ( $headers as $header ) {
			switch ( $header ) {
				case 'ID':
					$row[] = $submission['id'];
					break;
				case 'Form ID':
					$row[] = $submission['form_id'];
					break;
				case 'Date':
					$row[] = $submission['created_at'];
					break;
				case 'Status':
					$row[] = $submission['status'];
					break;
				case 'IP Address':
					$row[] = $submission['user_ip'];
					break;
				default:
					// Field data
					$value = isset( $submission['data'][ $header ] ) ? $submission['data'][ $header ] : '';
					if ( is_array( $value ) ) {
						$value = implode( ', ', $value );
					}
					$row[] = self::sanitize_csv_value( (string) $value );
					break;
			}
		}

		return $row;
	}

	/**
	 * Prevent CSV injection by prefixing values that start with formula characters.
	 *
	 * @param string $value Raw cell value.
	 * @return string Safe cell value.
	 */
	private static function sanitize_csv_value( $value ) {
		if ( '' !== $value && in_array( $value[0], array( '=', '+', '-', '@', "\t", "\r" ), true ) ) {
			return "'" . $value;
		}
		return $value;
	}
}
