<?php
/**
 * PDF ticket generation and secure ticket downloads.
 *
 * @package PlugozaEventTicketing
 */

namespace PlugozaEventTicketing;

use Dompdf\Dompdf;
use Dompdf\Options;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\Writer\PngWriter;

defined( 'ABSPATH' ) || exit;

final class Ticket {

	/**
	 * Register download handlers.
	 */
	public function __construct() {
		add_action( 'admin_post_nopriv_plugoza_ett_download_ticket', array( $this, 'download' ) );
		add_action( 'admin_post_plugoza_ett_download_ticket', array( $this, 'download' ) );
		add_action( 'template_redirect', array( $this, 'verify_ticket' ) );
	}

	/**
	 * Display the public ticket verification result requested by a QR code.
	 *
	 * This is a read-only endpoint. The random QR token is the ticket's
	 * verification credential, so no customer details are exposed.
	 */
	public function verify_ticket() {
		if ( ! isset( $_GET['plugoza_ett_verify'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public, read-only QR verification endpoint.
			return;
		}

		$token = sanitize_text_field( wp_unslash( $_GET['plugoza_ett_verify'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- High-entropy QR token is the verification credential.

		if ( ! preg_match( '/^[a-zA-Z0-9-]{20,64}$/', $token ) ) {
			$this->render_verification_page();
		}

		global $wpdb;

		$ticket = $wpdb->get_row(
			$wpdb->prepare(
				'SELECT b.booking_number, b.quantity, b.booking_status, b.payment_status, e.name AS event_name, e.venue, e.start_date, t.name AS ticket_name, ci.checked_in, ci.checked_in_at FROM %i b INNER JOIN %i e ON e.id = b.event_id INNER JOIN %i t ON t.id = b.ticket_id LEFT JOIN %i ci ON ci.booking_id = b.id WHERE b.qr_code = %s',
				Repository::table( 'bookings' ),
				Repository::table( 'events' ),
				Repository::table( 'tickets' ),
				Repository::table( 'checkins' ),
				$token
			)
		);

		$this->render_verification_page( $ticket );
	}

	/**
	 * Render an isolated, mobile-friendly QR verification page.
	 *
	 * @param object|null $ticket Ticket data, if found.
	 */
	private function render_verification_page( $ticket = null ) {
		wp_enqueue_style(
			'plugoza-ett-verification',
			PLUGOZA_ETT_URL . 'assets/css/verification.css',
			array(),
			PLUGOZA_ETT_VERSION
		);

		$valid      = $ticket && 'confirmed' === $ticket->booking_status && empty( $ticket->checked_in );
		$checked_in = $ticket && ! empty( $ticket->checked_in );
		$title      = $valid ? __( 'Ticket valid', 'plugoza-event-ticketing' ) : __( 'Ticket not valid', 'plugoza-event-ticketing' );
		$message    = $valid ? __( 'This ticket is valid for entry.', 'plugoza-event-ticketing' ) : __( 'This ticket could not be used for entry.', 'plugoza-event-ticketing' );

		if ( $checked_in ) {
			$title   = __( 'Ticket already checked in', 'plugoza-event-ticketing' );
			$message = __( 'This ticket has already been used for entry.', 'plugoza-event-ticketing' );
		}

		status_header( $valid ? 200 : 404 );
		nocache_headers();
		?>
		<!doctype html>
		<html <?php language_attributes(); ?>>
		<head>
			<meta charset="<?php bloginfo( 'charset' ); ?>">
			<meta name="viewport" content="width=device-width, initial-scale=1">
			<title><?php echo esc_html( $title ); ?></title>
			<?php wp_print_styles( array( 'plugoza-ett-verification' ) ); ?>
		</head>
		<body>
			<main class="plugoza-ett-verify <?php echo esc_attr( $valid ? 'plugoza-ett-verify--valid' : 'plugoza-ett-verify--invalid' ); ?>">
				<section class="plugoza-ett-verify__status">
					<h1><?php echo esc_html( $title ); ?></h1>
					<p><?php echo esc_html( $message ); ?></p>
				</section>
				<?php if ( $ticket ) : ?>
					<section class="plugoza-ett-verify__details">
						<div class="plugoza-ett-verify__row"><span class="plugoza-ett-verify__label"><?php esc_html_e( 'Event', 'plugoza-event-ticketing' ); ?></span><span class="plugoza-ett-verify__value"><?php echo esc_html( $ticket->event_name ); ?></span></div>
						<div class="plugoza-ett-verify__row"><span class="plugoza-ett-verify__label"><?php esc_html_e( 'Date and time', 'plugoza-event-ticketing' ); ?></span><span class="plugoza-ett-verify__value"><?php echo esc_html( wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $ticket->start_date ) ) ); ?></span></div>
						<div class="plugoza-ett-verify__row"><span class="plugoza-ett-verify__label"><?php esc_html_e( 'Ticket type', 'plugoza-event-ticketing' ); ?></span><span class="plugoza-ett-verify__value"><?php echo esc_html( $ticket->ticket_name ); ?></span></div>
						<div class="plugoza-ett-verify__row"><span class="plugoza-ett-verify__label"><?php esc_html_e( 'Entry quantity', 'plugoza-event-ticketing' ); ?></span><span class="plugoza-ett-verify__value"><?php echo esc_html( number_format_i18n( absint( $ticket->quantity ) ) ); ?></span></div>
						<?php if ( $checked_in ) : ?><div class="plugoza-ett-verify__row"><span class="plugoza-ett-verify__label"><?php esc_html_e( 'Checked in', 'plugoza-event-ticketing' ); ?></span><span class="plugoza-ett-verify__value"><?php echo esc_html( wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $ticket->checked_in_at ) ) ); ?></span></div><?php endif; ?>
					</section>
				<?php endif; ?>
			</main>
		</body>
		</html>
		<?php
		exit;
	}

	/**
	 * Generate and email a booking ticket.
	 *
	 * @param int $booking_id Booking ID.
	 * @param bool $send_email Whether to email the ticket attachment.
	 * @return string|false Absolute PDF path on success.
	 */
	public static function create( $booking_id, $send_email = true ) {
		$booking = self::get_booking( $booking_id );

		if ( ! $booking || ! class_exists( Dompdf::class ) ) {
			return false;
		}

		$upload_dir = wp_upload_dir();
		$ticket_dir = trailingslashit( $upload_dir['basedir'] ) . 'plugoza-ett-tickets/';

		if ( ! wp_mkdir_p( $ticket_dir ) ) {
			return false;
		}

		$file_path = $ticket_dir . sanitize_file_name( $booking->booking_number ) . '.pdf';
		$pdf       = self::render_pdf( $booking );

		if ( false === $pdf || false === file_put_contents( $file_path, $pdf ) ) {
			return false;
		}

		if ( $send_email ) {
			wp_mail(
				$booking->email,
				sprintf(
					/* translators: %s: event name. */
					__( 'Booking confirmation - %s', 'plugoza-event-ticketing' ),
					$booking->event_name
				),
				self::email_html( $booking ),
				array( 'Content-Type: text/html; charset=UTF-8' ),
				array( $file_path )
			);
		}

		return $file_path;
	}

	/**
	 * Serve a ticket after validating its private booking key.
	 */
	public function download() {
		$booking_id = absint( $_GET['booking_id'] ?? 0 );
		$key        = sanitize_text_field( wp_unslash( $_GET['key'] ?? '' ) );
		$nonce      = sanitize_text_field( wp_unslash( $_GET['plugoza_ett_ticket_nonce'] ?? '' ) );

		if ( ! $booking_id || ! wp_verify_nonce( $nonce, 'plugoza_ett_download_ticket_' . $booking_id ) ) {
			wp_die( esc_html__( 'Invalid ticket link.', 'plugoza-event-ticketing' ), '', array( 'response' => 403 ) );
		}
		$booking    = self::get_booking( $booking_id );

		if ( ! $booking || empty( $booking->qr_code ) || ! hash_equals( $booking->qr_code, $key ) ) {
			wp_die( esc_html__( 'Invalid ticket link.', 'plugoza-event-ticketing' ), '', array( 'response' => 403 ) );
		}

		$file_path = self::create( $booking_id, false );

		if ( ! $file_path || ! file_exists( $file_path ) ) {
			wp_die( esc_html__( 'The ticket could not be generated. Please try again later.', 'plugoza-event-ticketing' ), '', array( 'response' => 500 ) );
		}

		nocache_headers();
		header( 'Content-Type: application/pdf' );
		header( 'Content-Disposition: attachment; filename="' . sanitize_file_name( $booking->booking_number ) . '.pdf"' );
		header( 'Content-Length: ' . (string) filesize( $file_path ) );

		require_once ABSPATH . 'wp-admin/includes/file.php';
		global $wp_filesystem;
		WP_Filesystem();
		// The response is a PDF attachment, not HTML output.
		echo $wp_filesystem->get_contents( $file_path ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		exit;
	}

	/**
	 * Retrieve a booking and the ticket data needed for its PDF.
	 *
	 * @param int $booking_id Booking ID.
	 * @return object|null
	 */
	private static function get_booking( $booking_id ) {
		global $wpdb;

		return $wpdb->get_row(
			$wpdb->prepare(
				'SELECT b.*, e.name AS event_name, e.venue, e.start_date, c.first_name, c.last_name, c.email, t.name AS ticket_name FROM %i b INNER JOIN %i e ON e.id = b.event_id INNER JOIN %i c ON c.id = b.customer_id INNER JOIN %i t ON t.id = b.ticket_id WHERE b.id = %d',
				Repository::table( 'bookings' ),
				Repository::table( 'events' ),
				Repository::table( 'customers' ),
				Repository::table( 'tickets' ),
				absint( $booking_id )
			)
		);
	}

	/**
	 * Render the ticket with Dompdf.
	 *
	 * @param object $booking Booking data.
	 * @return string|false
	 */
	private static function render_pdf( $booking ) {
		try {
			$options = new Options();
			$options->set( 'defaultFont', 'DejaVu Sans' );
			$options->set( 'isRemoteEnabled', false );
			$options->set( 'isHtml5ParserEnabled', true );
			$options->setChroot( PLUGOZA_ETT_PATH );

			$dompdf = new Dompdf( $options );
			$dompdf->setPaper( 'A5', 'landscape' );
			$dompdf->loadHtml( self::ticket_html( $booking ), 'UTF-8' );
			$dompdf->getCss()->load_css_file( PLUGOZA_ETT_PATH . 'assets/css/ticket-pdf.css' );
			$dompdf->render();

			return $dompdf->output();
		} catch ( \Throwable $exception ) {
			return false;
		}
	}

	/**
	 * Build the customer-facing booking confirmation email.
	 *
	 * @param object $booking Booking data.
	 * @return string
	 */
	private static function email_html( $booking ) {
		$event_date     = wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $booking->start_date ) );
		$holder         = trim( $booking->first_name . ' ' . $booking->last_name );
		$currency       = sanitize_text_field( get_option( 'plugoza_ett_settings', array() )['currency'] ?? 'USD' );
		$payment_method = 'bank_transfer' === $booking->payment_method ? __( 'Manual Bank Transfer', 'plugoza-event-ticketing' ) : __( 'Manual Pay', 'plugoza-event-ticketing' );
		$payment_status = ucfirst( str_replace( '_', ' ', $booking->payment_status ) );
		$location       = ! empty( $booking->venue ) ? $booking->venue : __( 'Online event', 'plugoza-event-ticketing' );
		$bank           = Payment_Gateways::settings()['bank_transfer'];
		$bank_rows      = array_filter(
			array(
				__( 'Bank', 'plugoza-event-ticketing' )            => $bank['bank_name'] ?? '',
				__( 'Account name', 'plugoza-event-ticketing' )    => $bank['account_name'] ?? '',
				__( 'Account number', 'plugoza-event-ticketing' )  => $bank['account_number'] ?? '',
				__( 'IFSC / SWIFT', 'plugoza-event-ticketing' )    => $bank['ifsc_swift'] ?? '',
				__( 'Branch', 'plugoza-event-ticketing' )          => $bank['branch'] ?? '',
				__( 'UPI ID', 'plugoza-event-ticketing' )          => $bank['upi_id'] ?? '',
			)
		);
		$rows = array(
			__( 'Booking reference', 'plugoza-event-ticketing' ) => $booking->booking_number,
			__( 'Guest', 'plugoza-event-ticketing' )             => $holder,
			__( 'Event', 'plugoza-event-ticketing' )             => $booking->event_name,
			__( 'Date and time', 'plugoza-event-ticketing' )     => $event_date,
			__( 'Location', 'plugoza-event-ticketing' )          => $location,
			__( 'Ticket type', 'plugoza-event-ticketing' )       => $booking->ticket_name,
			__( 'Entry quantity', 'plugoza-event-ticketing' )    => number_format_i18n( absint( $booking->quantity ) ),
			__( 'Total amount', 'plugoza-event-ticketing' )      => number_format_i18n( (float) $booking->amount, 2 ) . ' ' . $currency,
			__( 'Payment method', 'plugoza-event-ticketing' )    => $payment_method,
			__( 'Payment status', 'plugoza-event-ticketing' )    => $payment_status,
		);

		if ( ! empty( $booking->transaction_id ) ) {
			$rows[ __( 'Transaction ID', 'plugoza-event-ticketing' ) ] = $booking->transaction_id;
		}

		$html  = '<!doctype html><html><body style="background:#f4f7fb;color:#172b4d;font-family:Arial,sans-serif;margin:0;padding:24px">';
		$html .= '<table role="presentation" width="100%" cellspacing="0" cellpadding="0"><tr><td align="center"><table role="presentation" width="620" cellspacing="0" cellpadding="0" style="background:#fff;border:1px solid #dce7f2;border-radius:12px;max-width:620px;overflow:hidden">';
		$html .= '<tr><td style="background:#102a43;color:#fff;padding:26px 30px"><h1 style="font-size:24px;margin:0 0 8px">' . esc_html__( 'Booking confirmed', 'plugoza-event-ticketing' ) . '</h1><p style="margin:0">' . esc_html__( 'Thank you for your booking. Your PDF ticket is attached to this email.', 'plugoza-event-ticketing' ) . '</p></td></tr>';
		/* translators: %s: customer first name. */
		$greeting = sprintf( esc_html__( 'Hello %s,', 'plugoza-event-ticketing' ), esc_html( $booking->first_name ) );
		$html    .= '<tr><td style="padding:26px 30px"><p style="margin:0 0 20px">' . $greeting . '</p><table role="presentation" width="100%" cellspacing="0" cellpadding="0">';
		foreach ( $rows as $label => $value ) {
			$html .= '<tr><td style="border-bottom:1px solid #e6edf5;color:#627d98;font-size:12px;padding:9px 0;width:42%">' . esc_html( $label ) . '</td><td style="border-bottom:1px solid #e6edf5;font-size:13px;font-weight:bold;padding:9px 0">' . esc_html( $value ) . '</td></tr>';
		}
		$html .= '</table>';

		if ( 'bank_transfer' === $booking->payment_method && $bank_rows ) {
			$html .= '<h2 style="font-size:17px;margin:24px 0 10px">' . esc_html__( 'Bank transfer details', 'plugoza-event-ticketing' ) . '</h2><table role="presentation" width="100%" cellspacing="0" cellpadding="0">';
			foreach ( $bank_rows as $label => $value ) {
				$html .= '<tr><td style="color:#627d98;font-size:12px;padding:4px 0;width:42%">' . esc_html( $label ) . '</td><td style="font-size:13px;padding:4px 0">' . esc_html( $value ) . '</td></tr>';
			}
			$html .= '</table><p style="background:#fff8e5;border-radius:6px;font-size:13px;padding:12px">' . esc_html__( 'Your booking will be confirmed after the payment is verified by the event administrator.', 'plugoza-event-ticketing' ) . '</p>';
		}

		$html .= '<p style="color:#50575e;font-size:12px;line-height:1.6;margin:24px 0 0">' . esc_html__( 'By completing this booking, you confirmed that you accept the event Terms & Conditions, Privacy Policy, and Refund Policy.', 'plugoza-event-ticketing' ) . '</p>';
		$html .= '<p style="color:#50575e;font-size:12px;line-height:1.6;margin:14px 0 0">' . esc_html__( 'Please present the attached PDF ticket at entry. Keep this email for your records.', 'plugoza-event-ticketing' ) . '</p>';
		$html .= '</td></tr></table></td></tr></table></body></html>';

		return $html;
	}

	/**
	 * Build safe ticket markup compatible with Dompdf's CSS support.
	 *
	 * @param object $booking Booking data.
	 * @return string
	 */
	private static function ticket_html( $booking ) {
		$verification_url = add_query_arg( 'plugoza_ett_verify', $booking->qr_code, home_url( '/' ) );
		$qr_code          = ( new PngWriter() )->write(
			new QrCode(
				data: $verification_url,
				size: 180
			)
		)->getDataUri();
		$event_date       = wp_date( get_option( 'date_format' ) . ' - ' . get_option( 'time_format' ), strtotime( $booking->start_date ) );
		$booking_date     = wp_date( get_option( 'date_format' ) . ' - ' . get_option( 'time_format' ), strtotime( $booking->booking_date ) );
		$holder           = trim( $booking->first_name . ' ' . $booking->last_name );

		return '<!doctype html><html><head><meta charset="utf-8"></head><body><div class="ticket"><div class="header"><div class="title">' . esc_html( $booking->event_name ) . '</div><p class="subtitle">' . esc_html( $event_date ) . ' | ' . esc_html( $booking->venue ) . '</p></div><div class="body"><table class="details"><tr><td style="padding-right:24px; vertical-align:top; width:66%;"><div class="detail-cell"><div class="label">' . esc_html__( 'TICKET HOLDER', 'plugoza-event-ticketing' ) . '</div><div class="value">' . esc_html( $holder ) . '</div></div><div class="detail-cell"><div class="label">' . esc_html__( 'TICKET TYPE', 'plugoza-event-ticketing' ) . '</div><div class="value">' . esc_html( $booking->ticket_name ) . '</div></div><div class="detail-cell"><div class="label">' . esc_html__( 'BOOKING REFERENCE', 'plugoza-event-ticketing' ) . '</div><div class="value">' . esc_html( $booking->booking_number ) . '</div></div><div class="detail-cell"><div class="label">' . esc_html__( 'BOOKING DATE', 'plugoza-event-ticketing' ) . '</div><div class="value">' . esc_html( $booking_date ) . '</div></div><div class="detail-cell"><div class="label">' . esc_html__( 'ENTRY QUANTITY', 'plugoza-event-ticketing' ) . '</div><div class="value">' . absint( $booking->quantity ) . '</div></div></td><td style="vertical-align:top; width:34%;"><div class="qr-wrap"><img src="' . esc_attr( $qr_code ) . '" alt="' . esc_attr__( 'Ticket verification QR code', 'plugoza-event-ticketing' ) . '"><p class="qr-label">' . esc_html__( 'Scan to verify', 'plugoza-event-ticketing' ) . '</p></div></td></tr></table></div><div class="footer">' . esc_html__( 'Please present this ticket at entry. One QR code is valid for the entry quantity shown above.', 'plugoza-event-ticketing' ) . '</div></div></body></html>';
	}
}
