<?php
/**
 * Order to stored invoice.
 *
 * @package Harbor_EU_EInvoicing_For_WooCommerce
 */

defined( 'ABSPATH' ) || exit;

class HEIN_Invoice_Service {

	/**
	 * The only path from an order to a stored invoice: the admin button, auto-generation and bulk
	 * regeneration all come through here and none re-implements it
	 *
	 * @throws HEIN_Invoice_Exception On an unknown format, a failed precondition or a failed write.
	 */
	public static function generate( WC_Order $order, string $format ): array {
		$all = HEIN_Generator_Registry::all();

		try {
			if ( ! isset( $all[ $format ] ) ) {
				throw new HEIN_Invoice_Exception(
					esc_html__( 'That invoice format is not available.', 'harbor-eu-einvoicing-for-woocommerce' ),
					'unknown_format'
				);
			}

			do_action( 'hein_before_generate', $order, $format );

			$invoice = HEIN_Invoice_Data::from_order( $order );

			if ( ! $all[ $format ]['class']::supports( $invoice ) ) {
				throw new HEIN_Invoice_Exception(
					esc_html__( 'This order cannot be invoiced in that format.', 'harbor-eu-einvoicing-for-woocommerce' ),
					'unsupported_format'
				);
			}

			$rendered = HEIN_Generator_Registry::get( $format )->render( $invoice );
			$row      = HEIN_Invoice_Store::save( $order->get_id(), $invoice, $format, $rendered );

			do_action( 'hein_invoice_generated', $order->get_id(), $format, $row, $invoice );

			return $row;
		} catch ( HEIN_Invoice_Exception $e ) {
			do_action( 'hein_invoice_generation_failed', $order->get_id(), $format, $e->error_code(), $e->getMessage() );

			throw $e;
		}
	}

	/**
	 * One format's failure never aborts the rest
	 */
	public static function generate_all( WC_Order $order, array $formats ): array {
		$result = [
			'ok'     => [],
			'errors' => [],
		];

		foreach ( $formats as $format ) {
			try {
				$result['ok'][ $format ] = self::generate( $order, (string) $format );
			} catch ( HEIN_Invoice_Exception $e ) {
				$result['errors'][ $format ] = [
					'code'    => $e->error_code(),
					'message' => $e->getMessage(),
				];
			}
		}

		return $result;
	}
}
