<?php
/**
 * Zano Payment Gateway QR Code Generator
 *
 * @package ZanoPaymentGateway
 */

defined( 'ABSPATH' ) || exit;

/**
 * QR code generator class
 */
class AnyCoin_QR_Generator {

	/**
	 * Generate and output QR code.
	 */
	public function generate_and_output() {
		$nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : '';
		if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $nonce, 'anycoin_qr' ) ) {
			wp_die( 'Security check failed' );
		}

		if ( ! isset( $_GET['data'] ) ) {
			wp_die( 'Missing data parameter' );
		}

		$data       = sanitize_text_field( wp_unslash( $_GET['data'] ) );
		$logo_asset = isset( $_GET['logo'] ) ? sanitize_text_field( wp_unslash( $_GET['logo'] ) ) : '';
		if ( $logo_asset !== 'zano' && $logo_asset !== 'fusd' ) {
			$logo_asset = '';
		}

		header( 'Content-Type: image/png' );

		if ( ! function_exists( 'imagecreatetruecolor' ) ) {
			$this->output_fallback_image();
			return;
		}

		if ( ! empty( $logo_asset ) ) {
			$this->generate_qr_with_logo( $data, $logo_asset );
		} else {
			$this->render_qr_png( $data, 5, 2 );
		}
		exit;
	}

	/**
	 * Render QR as PNG to output using chillerlan/php-qrcode.
	 *
	 * @param string $data   QR content.
	 * @param int    $size   Scale size.
	 * @param int    $margin Margin size.
	 */
	private function render_qr_png( $data, $size = 5, $margin = 2 ) {
		if ( class_exists( 'chillerlan\\QRCode\\QRCode' ) ) {
			$options = new \chillerlan\QRCode\QROptions(
				[
					'eccLevel'       => \chillerlan\QRCode\QRCode::ECC_L,
					'outputType'     => \chillerlan\QRCode\QRCode::OUTPUT_IMAGE_PNG,
					'scale'          => max( 1, (int) $size ),
					'margin'         => max( 0, (int) $margin ),
					'returnResource' => true,
				]
			);

			$qrcode   = new \chillerlan\QRCode\QRCode( $options );
			$rendered = $qrcode->render( $data );

			if ( $rendered instanceof \GdImage || ( is_resource( $rendered ) && get_resource_type( $rendered ) === 'gd' ) ) {
				imagepng( $rendered );
				imagedestroy( $rendered );
				return;
			}
			if ( is_string( $rendered ) ) {
				echo $rendered; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				return;
			}
		}
		$this->output_fallback_image();
	}

	/**
	 * Output fallback image when QR library is not available.
	 */
	private function output_fallback_image() {
		$img       = imagecreate( 300, 100 );
		$bg        = imagecolorallocate( $img, 255, 255, 255 );
		$textcolor = imagecolorallocate( $img, 0, 0, 0 );
		imagestring( $img, 5, 10, 40, 'QR Library not available', $textcolor );
		imagepng( $img );
		imagedestroy( $img );
		exit;
	}

	/**
	 * Generate QR code with logo embedded in center.
	 *
	 * @param string $data       QR content.
	 * @param string $logo_asset Logo asset key (zano|fusd).
	 */
	private function generate_qr_with_logo( $data, $logo_asset ) {

		$qr_image = false;
		if ( class_exists( 'chillerlan\\QRCode\\QRCode' ) ) {
			$options  = new \chillerlan\QRCode\QROptions(
				[
					'eccLevel'       => \chillerlan\QRCode\QRCode::ECC_H,
					'outputType'     => \chillerlan\QRCode\QRCode::OUTPUT_IMAGE_PNG,
					'scale'          => 8,
					'margin'         => 2,
					'returnResource' => true,
				]
			);
			$qrcode   = new \chillerlan\QRCode\QRCode( $options );
			$rendered = $qrcode->render( $data );
			if ( $rendered instanceof \GdImage || ( is_resource( $rendered ) && get_resource_type( $rendered ) === 'gd' ) ) {
				$qr_image = $rendered;
			} elseif ( is_string( $rendered ) ) {
				$qr_image = imagecreatefromstring( $rendered );
			}
		}

		if ( ! $qr_image ) {
			$this->render_qr_png( $data, 5, 2 );
			return;
		}

		$qr_width  = imagesx( $qr_image );
		$qr_height = imagesy( $qr_image );

		$logo_path = $this->get_logo_path( $logo_asset );

		if ( empty( $logo_path ) || ! file_exists( $logo_path ) ) {
			imagepng( $qr_image );
			imagedestroy( $qr_image );
			return;
		}

		$logo_image = $this->load_logo_image( $logo_path );

		if ( ! $logo_image ) {
			imagepng( $qr_image );
			imagedestroy( $qr_image );
			return;
		}

		$this->apply_logo_to_qr( $qr_image, $logo_image, $qr_width, $qr_height );

		imagepng( $qr_image );

		imagedestroy( $qr_image );
		imagedestroy( $logo_image );
	}

	/**
	 * Get logo path based on asset.
	 *
	 * @param string $logo_asset Logo asset key.
	 * @return string Logo path.
	 */
	private function get_logo_path( $logo_asset ) {
		$logo_path = '';
		if ( $logo_asset === 'zano' ) {
			$logo_path = ANYCOIN_PAYMENT_PLUGIN_DIR . 'assets/images/zano-icon.png';
		} elseif ( $logo_asset === 'fusd' ) {
			$logo_path = ANYCOIN_PAYMENT_PLUGIN_DIR . 'assets/images/fusd-icon.png';
		}
		return $logo_path;
	}

	/**
	 * Load logo image.
	 *
	 * @param string $logo_path Logo file path.
	 * @return resource|GdImage|null Image resource or null.
	 */
	private function load_logo_image( $logo_path ) {
		$logo_image = null;
		$logo_ext   = strtolower( pathinfo( $logo_path, PATHINFO_EXTENSION ) );

		switch ( $logo_ext ) {
			case 'png':
				$logo_image = imagecreatefrompng( $logo_path );
				break;
			case 'jpg':
			case 'jpeg':
				$logo_image = imagecreatefromjpeg( $logo_path );
				break;
			case 'ico':
				$png_logo = str_replace( '.ico', '.png', $logo_path );
				if ( file_exists( $png_logo ) ) {
					$logo_image = imagecreatefrompng( $png_logo );
				}
				break;
		}

		return $logo_image;
	}

	/**
	 * Apply logo to QR code.
	 *
	 * @param resource|GdImage $qr_image   QR image.
	 * @param resource|GdImage $logo_image Logo image.
	 * @param int              $qr_width   QR width.
	 * @param int              $qr_height  QR height.
	 */
	private function apply_logo_to_qr( $qr_image, $logo_image, $qr_width, $qr_height ) {
		// Calculate integer geometry.
		$logo_size_px = max( 1, (int) round( min( $qr_width, $qr_height ) * 0.2 ) );
		$logo_x       = (int) round( ( $qr_width - $logo_size_px ) / 2 );
		$logo_y       = (int) round( ( $qr_height - $logo_size_px ) / 2 );

		$white_bg_size = max( 1, (int) round( $logo_size_px * 1.2 ) );

		$white = imagecolorallocate( $qr_image, 255, 255, 255 );
		imagefilledellipse( $qr_image, (int) floor( $qr_width / 2 ), (int) floor( $qr_height / 2 ), $white_bg_size, $white_bg_size, $white );

		imagecopyresampled(
			$qr_image,
			$logo_image,
			$logo_x,
			$logo_y,
			0,
			0,
			$logo_size_px,
			$logo_size_px,
			imagesx( $logo_image ),
			imagesy( $logo_image )
		);
	}
}
