<?php

namespace WPDesk\FakturyKSEF\Api\Services;

use WPDesk\FakturyKSEF\Api\APIClient;
use WPDesk\FakturyKSEF\Api\Exceptions\KSeFExceptionFactory;
use WPDesk\FakturyKSEF\Api\Requests\CloseSessionRequest;
use WPDesk\FakturyKSEF\Api\Requests\GetInvoiceStatusRequest;
use WPDesk\FakturyKSEF\Api\Requests\OpenSessionRequest;
use WPDesk\FakturyKSEF\Api\Requests\SendEncryptedInvoiceRequest;
use WPDesk\FakturyKSEF\Services\EncryptionService;

class DocumentService {

	private APIClient $client;

	private EncryptionService $encryption_service;

	private CertificateService $certificate_service;

	public function __construct(
		APIClient $client,
		EncryptionService $encryption_service,
		CertificateService $certificate_service
	) {
		$this->certificate_service = $certificate_service;
		$this->encryption_service  = $encryption_service;
		$this->client              = $client;
	}

	public function send_document( string $invoice_xml_content ): array {

		$symmetric_key = random_bytes( 32 );
		$iv            = random_bytes( 16 );

		try {
			$certificates    = $this->certificate_service->get_certificates();
			$ksef_public_key = $this->encryption_service->get_public_key_from_certificates( $certificates, CertificateService::PUBLIC_KEY_SYMMETRIC_ENCRYPTION );
		} catch ( \Exception $e ) {
			throw new \Exception( esc_html__( 'Failed to fetch certificates.', 'ksef-for-flexible-invoices' ) );
		}

		$encrypted_symmetric_key = $this->encryption_service->encrypt_key( $symmetric_key, $ksef_public_key );
		$encrypted_key_base64    = base64_encode( $encrypted_symmetric_key );//phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
		$iv_base64               = base64_encode( $iv );//phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode

		$session_ref_number = null;
		try {
			$session = $this->client->execute( new OpenSessionRequest( $encrypted_key_base64, $iv_base64 ) );

			if ( ! isset( $session['referenceNumber'] ) ) {
				throw new \Exception( esc_html__( 'Failed to open session. Try again later.', 'ksef-for-flexible-invoices' ) );
			}

			$session_ref_number = $session['referenceNumber'];

			$encrypted_invoice_content = $this->encryption_service->encrypt_invoice( $invoice_xml_content, $symmetric_key, $iv );

			$invoice_hash_base64              = base64_encode( hash( 'sha256', $invoice_xml_content, true ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
			$invoice_size                     = strlen( $invoice_xml_content );
			$encrypted_invoice_hash_base64    = base64_encode( hash( 'sha256', $encrypted_invoice_content, true ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
			$encrypted_invoice_size           = strlen( $encrypted_invoice_content );
			$encrypted_invoice_content_base64 = base64_encode( $encrypted_invoice_content ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode

			$result = $this->client->execute(
				new SendEncryptedInvoiceRequest( $session_ref_number, $invoice_hash_base64, $invoice_size, $encrypted_invoice_hash_base64, $encrypted_invoice_size, $encrypted_invoice_content_base64 )
			);

			return [
				'session_ref'  => $session_ref_number,
				'document_ref' => $result['referenceNumber'],
			];
		} catch ( \Throwable $e ) {
			throw KSeFExceptionFactory::create( $e );
		} finally {
			if ( $session_ref_number ) {
				$this->client->execute( new CloseSessionRequest( $session_ref_number ) );
			}
		}
	}

	public function get_invoice_status( string $session_ref_number, string $invoice_ref_number ): array {
		try {
			return $this->client->execute( new GetInvoiceStatusRequest( $session_ref_number, $invoice_ref_number ) );
		} catch ( \Throwable $e ) {
			throw KSeFExceptionFactory::create( $e );
		}
	}
}
