<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Core\ValueObject;

use BookiFlex\Core\Exception\MoneyCalculationException;
use Brick\Math\Exception\MathException;
use Brick\Money\Exception\MoneyMismatchException;
use Brick\Money\Money;

defined( 'ABSPATH' ) || exit;

final class Summary
{
    public function __construct(
        private readonly Money $subtotal,
        private readonly Money $totalTaxes,
        private readonly Money $totalCharges,
        private readonly Money $totalDiscounts,
        private readonly Money $total,
    ) {
    }

    public function subtotal(): Money
    {
        return $this->subtotal;
    }

    public function totalTaxes(): Money
    {
        return $this->totalTaxes;
    }

    public function totalCharges(): Money
    {
        return $this->totalCharges;
    }

    public function totalDiscounts(): Money
    {
        return $this->totalDiscounts;
    }

    public function total(): Money
    {
        return $this->total;
    }

    /**
     * @param Summary[] $summaries
     * @param string $currency
     * @return Summary
     * @throws MoneyCalculationException
     */
    public static function summarize(array $summaries, string $currency): Summary
    {
        $subtotal       = Money::zero($currency);
        $totalTaxes     = Money::zero($currency);
        $totalCharges   = Money::zero($currency);
        $totalDiscounts = Money::zero($currency);
        $total          = Money::zero($currency);

        try {
            foreach ($summaries as $summary) {
                $subtotal       = $subtotal->plus($summary->subtotal());
                $totalTaxes     = $totalTaxes->plus($summary->totalTaxes());
                $totalCharges   = $totalCharges->plus($summary->totalCharges());
                $totalDiscounts = $totalDiscounts->plus($summary->totalDiscounts());
                $total          = $total->plus($summary->total());
            }
        } catch (MoneyMismatchException|MathException $e) {
            throw new MoneyCalculationException(
                sprintf(
					'Failed to calculate money: %s',
                    $e->getMessage()
                ),
                0,
                $e,
                ['error' => $e->getMessage()]
            );
        }

        return new self($subtotal, $totalTaxes, $totalCharges, $totalDiscounts, $total);
    }
}
