<?php

declare(strict_types=1);

namespace Maestro\Core\Modules\Invoices\Services;

use Maestro\Core\Modules\Invoices\Enums\InvoiceType;
use Maestro\Core\Modules\Invoices\Models\Invoice;

final class InvoiceTotalsService
{
    public static function recalculate(Invoice $invoice): void
    {
        $lines = $invoice->relationLoaded('lines')
            ? $invoice->lines
            : $invoice->lines()->with('vatRate')->orderBy('sort_order')->orderBy('id')->get();

        $sign = $invoice->type === InvoiceType::CreditNote ? -1 : 1;

        $sumEx = 0.0;
        $sumVat = 0.0;
        $sumInc = 0.0;

        $sort = 0;
        foreach ($lines as $line) {
            $sort++;
            $line->sort_order = $sort;

            $qty = (float) $line->quantity;
            $unit = (float) $line->unit_price_ex_vat;
            $ex = self::roundMoney($qty * $unit);
            $vatModel = $line->relationLoaded('vatRate') ? $line->vatRate : $line->vatRate()->first();
            $rate = (float) ($vatModel?->rate_percent ?? 0);
            $vat = self::roundMoney($ex * ($rate / 100.0));
            $inc = self::roundMoney($ex + $vat);

            $line->line_total_ex_vat = $ex;
            $line->line_vat_amount = $vat;
            $line->line_total_inc_vat = $inc;
            $line->save();

            $sumEx += $ex;
            $sumVat += $vat;
            $sumInc += $inc;
        }

        $invoice->subtotal_ex_vat = self::roundMoney($sign * $sumEx);
        $invoice->total_vat = self::roundMoney($sign * $sumVat);
        $invoice->total_inc_vat = self::roundMoney($sign * $sumInc);
        $invoice->save();
    }

    private static function roundMoney(float $v): float
    {
        return round($v, 2);
    }
}
