<?php
/**
 * Tickets controller.
 *
 * @since 1.0
 */

declare( strict_types=1 );
namespace FeData\FastEvents\RestAPI\Public\Download;

defined( 'ABSPATH' ) || exit;

use FeData\FastEvents\Helpers\SeatsHelper;
use FeData\FastEvents\Utilities\PluginUtil;
use stdClass;
use TCPDF;

/**
 * Tickets class.
 */
class EventTickets {

	private const FONTNAME = 'helvetica';

	/**
	 * PDF Class variable.
	 *
	 * @since 1.0
	 * @var TCPDF
	 */
	private TCPDF $pdf;

	/**
	 * X-position in the PDF page.
	 *
	 * @since 1.0
	 * @var float
	 */
	private float $x;

	/**
	 * Y-position in the PDF page.
	 *
	 * @since 1.0
	 * @var float
	 */
	private float $y;

	/**
	 * Rotation by degree.
	 *
	 * @since 1.0
	 * @var float
	 */
	private float $rotate;

	/**
	 * Scaling percentage.
	 *
	 * @since 1.7
	 * @var float
	 */
	private float $scale;

	/**
	 * 1 = No border around the qrcode block.
	 *
	 * @since 1.4
	 * @var  int
	 */
	private int $no_border;

	/**
	 * Template id used for all tickets if $_per_type = 0.
	 *
	 * @since 1.0
	 * @var int
	 */
	private int $id;

	/**
	 * Last used template id.
	 *
	 * @since 1.0
	 * @var int
	 */
	private int $last_template_id = 0;

	/**
	 * Associate array with ticket names(key) and the layout fields.
	 * If it's not empty, it contains a comma-separated list of field names (max 6)
	 * The field names can be:
	 * - Order-id   Order id
	 * - Name       The name of the person who ordered the tickets
	 * - Email      The emailaddress of the person who ordered the tickets
	 * - [order]    Any input field name on order level
	 * - [ticket]   Any input field that has been personalised
	 *
	 * @since 2.1.0
	 * @var array
	 */
	private array $layout;

	/**
	 * Array of print positions for personalised tickets.
	 * A maximum of 6 fields can be printed, hence an array of 6 arrays (1 field, 2 fields, etc.)
	 * Positions: - 0 -> Eventname
	 *              1 -> Ticket type
	 *              2 -> Event date
	 *              3 -> Separator line
	 *              4 -> The personalised fields
	 *              ...
	 *
	 * @since 2.1.0
	 * @var array
	 */
	private static array $positions = array(
		array( 4, 9, 14, 28, 32 ),
		array( 4, 9, 14, 24, 28, 32 ),
		array( 4, 9, 14, 22, 24, 28, 32 ),
		array( 4, 9, 14, 19.5, 20, 24, 28, 32 ),
		array( 4, 9, 14, 19.5, 20, 24, 28, 32, 36 ),
		array( 4, 8.5, 13, 18, 18.5, 22, 25.5, 29, 32.5, 36 ),
	);

	/**
	 * Templates per ticket-type (Can be null when used in defining ticket in the 'Pdf template' tab).
	 *
	 * @since 1.0
	 * @var ?stdClass
	 */
	private ?stdClass $templates;


	/**
	 * Tickets constructor.
	 *
	 * @param string $author   The name of the author (SMTP Sender Name).
	 * @param string $pdf_info JSON string of PDF page definition.
	 * @param array  $layout   Associative array with ticket names(key) and fields to use in the qrcode info block (comma-separated).
	 *
	 * @since 1.0
	 * @since 2.1.0 Added layout parameter.
	 * @since 2.2.2 Selection of passe-partout templates per ticket.
	 */
	public function __construct( string $author, string $pdf_info, array $layout ) {
		// Prepare the PDF.
		include_once ABSPATH . 'wp-admin/includes/file.php';

		$this->pdf    = new EventPdf();
		$this->layout = $layout;

		// Set properties.
		$this->pdf->SetCreator( PluginUtil::get_user_agent() );
		$this->pdf->SetAuthor( $author );
		$this->pdf->SetTextColor();
		$this->pdf->setFontSubsetting( false );
	}


	/**
	 * Load the right template for the ticket-type.
	 *
	 * @param string $ticket_type Ticket type.
	 *
	 * @since 2.0.1 'pertype' field is no longer used.
	 *              Only use ticket_type as argument.
	 *
	 * @since 1.0
	 */
	private function set_template( string $ticket_type ): void {

		// Find the template id to use for the specific ticket-type.
		$tmp_id = $this->templates->{$ticket_type} ?? $this->id;

		// Is the template already loaded?
		if ( $tmp_id !== $this->last_template_id ) {
			$this->pdf->load_template( $tmp_id );
			$this->last_template_id = $tmp_id;
		}

		// Use the template.
		$this->pdf->use_template();
	}


	/**
	 * Print the qrcode block.
	 *
	 * @param array $results {
	 *      Array of qrcode entries.
	 *
	 * @type string $id The unique order id
	 * @type string $name Name of the buyer
	 * @type string $email Emailaddress of the buyer
	 * @type string $payment_status E.g.: 'paid', 'dashboard', ...
	 * @type string $order_input Order input data (JSON))
	 * @type string $event_name Name of the event
	 * @type string $event_date Date of the event (mysql format: YYYY-MM-DD HH:MM:SS)
	 * @type string $event_date_format PHP datetime format string
	 * @type string $event_input Definitions of input fields and tickets (JSON)
	 * @type string $tickets_needed Are tickets needed (0=no, 1=yes)
	 * @type string $seats_needed Are seats used (0=no, 1=yes)
	 * @type string $webhooks_needed Are webhooks used (0=no, 1=yes)
	 * @type string $tracking_needed Is tracking used (0=no, 1=yes)
	 * @type string $pdf_info JSON describing position qrcode-block in PDF
	 * @type string $qrcode_id The unique qrcode id
	 * @type string $qrcode The qrcode
	 * @type string $ticket_type The ticket type
	 * @type string $event_id The unique event id
	 * @type string $personalised_iniput Personalised data (JSON)
	 * }
	 * @since 1.7   Added scaling.
	 * @since 2.2.2 Selection of passe-partout templates per ticket.
	 *
	 * @since 1.0
	 */
	public function print_qrcodes( array $results ): void {

		// Qrcode style.
		$style = array(
			'border'        => false,
			'vpadding'      => 'auto',
			'hpadding'      => 'auto',
			'fgcolor'       => array( 0, 0, 0 ),
			'bgcolor'       => false, // no background color.
			'module_width'  => 1,     // width of a single module in points.
			'module_height' => 1,     // height of a single module in points.
		);

		// Set title and subject.
		$this->pdf->SetTitle( __( 'Tickets', 'fast-events' ) . ' ' . $results[0]->event_name );
		$this->pdf->SetSubject( __( 'Order', 'fast-events' ) . ' #' . $results[0]->id );

		// Loop through all tickets.
		foreach ( $results as $result ) {
			$this->pdf->AddPage();

			// Get the PDF-template.
			$pdf             = json_decode( $result->pdf_info );
			$this->id        = (int) $pdf->ticket->id;
			$this->x         = (float) $pdf->ticket->x;
			$this->y         = (float) $pdf->ticket->y;
			$this->rotate    = (float) $pdf->ticket->rotate;
			$this->scale     = isset( $pdf->ticket->scale ) ? (float) $pdf->ticket->scale : 100.0;
			$this->no_border = (int) $pdf->ticket->no_border;
			$this->templates = $pdf->ticket->types ?? null;

			// Set the right template.
			$this->set_template( $result->ticket_type );

			// Check if we need to rotate and/or scale.
			if ( 0 !== (int) $this->rotate || 100 !== (int) $this->scale ) {
				// Rotate the qrcode-block in the upper-left corner.
				$this->pdf->StartTransform();
				if ( 100 !== (int) $this->scale ) {
					$this->pdf->Scale( $this->scale, $this->scale, $this->x, $this->y );
				}
				if ( 0 !== (int) $this->rotate ) {
					$this->pdf->Rotate( $this->rotate, $this->x, $this->y );
				}
			}

			// Print the rectangle.
			if ( 0 === $this->no_border ) {
				$this->pdf->Rect( $this->x, $this->y, 120, 40 );
			}

			// Print the Qrcode.
			if ( 0 === (int) $result->tracking_needed ) {
				$qrcode = $result->qrcode;
			} else {
				$qrcode = $result->qrcode . ':' . $result->qrcode_id . ':' . PluginUtil::get_home_domain() .
						':' . PluginUtil::get_qrcode_signature( $result->qrcode, (int) $result->qrcode_id );
			}
			$this->pdf->write2DBarcode( $qrcode, 'QRCODE,Q', $this->x, $this->y, 40, 40, $style, 'N' );

			// Barcode text.
			$this->pdf->SetFont( self::FONTNAME, '', 9 );
			$this->pdf->SetTextColor( 64 );
			$this->pdf->SetXY( $this->x + 4, $this->y + 36 );
			$this->pdf->Cell( 30, 4, $result->qrcode, 0, 0, '', false, '', 1 );

			// If the layout is the default info.
			if ( 'Order-id,Name,Email' === $this->layout[ $result->ticket_type ] ) {
				$this->default_block( $result );
				continue;
			}

			// Collect all the input (order-level and ticket-level) and the order_id, name and email.
			$input       = array();
			$order_input = json_decode( $result->order_input );
			if ( null !== $order_input && false !== $order_input && isset( $order_input->fields ) ) {
				foreach ( $order_input->fields as $field ) {
					$input[ $field->name ] = $field->value;
				}
			}
			if ( ! is_null( $result->personalised_input ) ) {
				$ticket_input = json_decode( $result->personalised_input );
				if ( null !== $ticket_input && false !== $ticket_input && isset( $ticket_input->data ) ) {
					foreach ( $ticket_input->data as $key => $value ) {
						$input[ $key ] = $value;
					}
				}
			}
			$input['Order-id'] = $result->id;
			$input['Name']     = $result->name;
			$input['Email']    = $result->email;

			// Print the personalised block.
			$this->personalised_block( $result, $input );
		}
	}

	/**
	 * Print the default qrcode info.
	 *
	 * @param stdClass $result Ticket info.
	 *
	 * @since 2.1.0
	 */
	private function default_block( stdClass $result ): void {
		global $fevt_container;

		/**
		 * Filter the text in the qrcode block.
		 *
		 * @param string $event_name The name of the event.
		 * @param string $ticket_type The type of ticket.
		 * @param string $event_date The date of the event.
		 * @param int $order_id The id of the order.
		 * @param string $name The name of the person placing the order.
		 * @param string $email The emailaddress of the person placing the order.
		 *
		 * @since 1.0
		 */
		$attr = apply_filters(
			'fast_events_ticket_text',
			array(
				'event_name'  => $result->event_name,
				'ticket_type' => $result->ticket_type,
				'event_date'  => mysql2date( $result->event_date_format, $result->event_date ),
				'order_id'    => __( 'Order', 'fast-events' ) . " #$result->id",
				'name'        => $result->name,
				'email'       => $result->email,
			)
		);

		// Event name.
		$this->pdf->SetTextColor();
		$this->pdf->SetFont( self::FONTNAME, 'B', 11 );
		$this->pdf->SetXY( $this->x + 40, $this->y + 4 );
		$this->pdf->Cell( 80, 5, sanitize_text_field( $attr['event_name'] ), 0, 0, '', false, '', 1 );

		// Ticket type.
		$this->pdf->SetFont( self::FONTNAME, '', 10 );
		$this->pdf->SetXY( $this->x + 40, $this->y + 9 );
		if ( 1 === (int) $result->seats_needed ) {
			$seat = sanitize_text_field( $attr['ticket_type'] ) . $fevt_container->get( SeatsHelper::class )->get_seat( (int) $result->event_id, $result->qrcode );
		} else {
			$seat = sanitize_text_field( $attr['ticket_type'] );
		}
		$this->pdf->Cell( 80, 5, $seat, 0, 0, '', false, '', 1 );

		// Event date.
		$this->pdf->SetXY( $this->x + 40, $this->y + 14 );
		$this->pdf->Cell( 80, 5, sanitize_text_field( $attr['event_date'] ), 0, 0, '', false, '', 1 );

		// Order ID.
		$this->pdf->SetFont( self::FONTNAME, '', 9 );
		$this->pdf->SetTextColor( 64 );
		$this->pdf->SetXY( $this->x + 40, $this->y + 24 );
		$this->pdf->Cell( 80, 4, sanitize_text_field( $attr['order_id'] ), 0, 0, '', false, '', 1 );

		// Name.
		$this->pdf->SetXY( $this->x + 40, $this->y + 28 );
		$this->pdf->Cell( 80, 4, sanitize_text_field( $attr['name'] ), 0, 0, '', false, '', 1 );

		// Email.
		$this->pdf->SetXY( $this->x + 40, $this->y + 32 );
		$this->pdf->Cell( 80, 4, sanitize_text_field( $attr['email'] ), 0, 0, '', false, '', 1 );

		// Stop the rotation and/or scaling.
		if ( 0 !== (int) $this->rotate || 100 !== (int) $this->scale ) {
			$this->pdf->StopTransform();
		}
	}

	/**
	 * Print the personalised qrcode info.
	 *
	 * @param stdClass $result Ticket info.
	 * @param array    $input  Array of personalised input.
	 *
	 * @since 2.1.0
	 * @since 2.4.1 Don't print separator line if there are no layout fields.
	 */
	private function personalised_block( stdClass $result, array $input ): void {
		global $fevt_container;

		/**
		 * Filter the personalised data in the qrcode block.
		 *
		 * @param string $event_name The name of the event.
		 * @param string $ticket_type The type of ticket.
		 * @param string $event_date The date of the event.
		 * @param array $personalised Array of personalised data.
		 *
		 * @since 1.0
		 */
		$attr = apply_filters(
			'fast_events_personalised_ticket_text',
			array(
				'event_name'   => $result->event_name,
				'ticket_type'  => $result->ticket_type,
				'event_date'   => mysql2date( $result->event_date_format, $result->event_date ),
				'personalised' => $input,
			)
		);

		// Get positions.
		$fields = explode( ',', $this->layout[ $result->ticket_type ] );
		$max    = count( $fields );
		$pos    = self::$positions[ $max - 1 ];

		// Event name.
		$this->pdf->SetTextColor();
		$this->pdf->SetFont( self::FONTNAME, 'B', 11 );
		$this->pdf->SetXY( $this->x + 40, $this->y + $pos[0] );
		$this->pdf->Cell( 80, 5, sanitize_text_field( $attr['event_name'] ), 0, 0, '', false, '', 1 );

		// Ticket type.
		$this->pdf->SetFont( self::FONTNAME, '', 10 );
		$this->pdf->SetXY( $this->x + 40, $this->y + $pos[1] );
		if ( 1 === (int) $result->seats_needed ) {
			$seat = sanitize_text_field( $attr['ticket_type'] ) . $fevt_container->get( SeatsHelper::class )->get_seat( (int) $result->event_id, $result->qrcode );
		} else {
			$seat = sanitize_text_field( $attr['ticket_type'] );
		}
		$this->pdf->Cell( 80, 5, $seat, 0, 0, '', false, '', 1 );

		// Event date.
		$this->pdf->SetXY( $this->x + 40, $this->y + $pos[2] );
		$this->pdf->Cell( 80, 5, sanitize_text_field( $attr['event_date'] ), 0, 0, '', false, '', 1 );

		// Separator line.
		if ( ! empty( $this->layout[ $result->ticket_type ] ) ) {
			$this->pdf->SetFont( self::FONTNAME, '', 9 );
			$this->pdf->SetTextColor( 64 );
			$this->pdf->SetXY( $this->x + 40, $this->y + $pos[3] );
			$this->pdf->Line( $this->x + 40, $this->y + $pos[3], $this->x + 80, $this->y + $pos[3] );
		}

		// Print the personalised data.
		for ( $i = 0; $i < $max; $i++ ) {
			if ( isset( $input[ $fields[ $i ] ] ) ) {
				$this->pdf->SetTextColor( 64 );
				$this->pdf->SetFont( self::FONTNAME, '', 8 );
				$this->pdf->SetXY( $this->x + 40, $this->y + $pos[ $i + 4 ] );
				$name = match ( $fields[ $i ] ) {
					'Order-id' => __( 'Order-id', 'fast-events' ),
					'Name' => __( 'Name', 'fast-events' ),
					'Email' => __( 'Email', 'fast-events' ),
					default => $fields[ $i ],
				};
				$this->pdf->Cell( 15, 4, sanitize_text_field( $name ), 0, 0, '', false, '', 1 );
				$this->pdf->Cell( 2, 4, ':' );
				$this->pdf->SetTextColor();
				$this->pdf->SetFont( self::FONTNAME, '', 9 );
				$this->pdf->Cell( 63, 4, sanitize_text_field( $input[ $fields[ $i ] ] ), 0, 0, '', false, '', 1 );
			}
		}

		// Stop the rotation and/or scaling.
		if ( 0 !== (int) $this->rotate || 100 !== (int) $this->scale ) {
			$this->pdf->StopTransform();
		}
	}


	/**
	 * Send the Tickets.pdf to the client
	 *
	 * @since 1.0
	 */
	public function send_pdf(): void {
		$this->pdf->Output( __( 'Tickets', 'fast-events' ) . '.pdf' );
	}
}
