<?php

namespace App\Services\Accounting;

use App\Enums\DocumentStatus;
use App\Models\Expense;
use App\Services\Audit\AuditLogger;
use App\Support\Decimal;
use DomainException;
use Illuminate\Support\Facades\DB;

final class ExpensePostingService
{
    public function __construct(private readonly AuthorizationGuard $authorization, private readonly DocumentApprovalGuard $guard, private readonly JournalPostingService $journals, private readonly AuditLogger $audit) {}

    public function post(Expense $expense): Expense
    {
        return DB::transaction(function () use ($expense): Expense {
            $expense=Expense::query()->lockForUpdate()->findOrFail($expense->id);
            $this->authorization->ensureCan('expenses.post',(int)$expense->company_id,(int)$expense->branch_id);
            $this->guard->ensureApproved($expense);
            if(Decimal::compare((string)$expense->total_amount,'0')<=0) throw new DomainException('Expense total must be greater than zero.');
            $expected=Decimal::add((string)$expense->amount_before_vat,(string)$expense->recoverable_vat,(string)$expense->nonrecoverable_vat);
            if(!Decimal::equals($expected,(string)$expense->total_amount)) throw new DomainException('Expense total does not reconcile with VAT amounts.');
            $expenseDebit=Decimal::add((string)$expense->amount_before_vat,(string)$expense->nonrecoverable_vat);
            $lines=[[
                'account_id'=>$expense->expense_account_id,'debit'=>$expenseDebit,'branch_id'=>$expense->branch_id,'department_id'=>$expense->department_id,'cost_center_id'=>$expense->cost_center_id,'description'=>$expense->description,
            ]];
            if(Decimal::compare((string)$expense->recoverable_vat,'0')>0){
                if(!$expense->input_vat_account_id) throw new DomainException('Input VAT account is required for recoverable VAT.');
                $lines[]=['account_id'=>$expense->input_vat_account_id,'debit'=>(string)$expense->recoverable_vat,'branch_id'=>$expense->branch_id,'department_id'=>$expense->department_id,'cost_center_id'=>$expense->cost_center_id,'description'=>'Recoverable input VAT'];
            }
            $lines[]=['account_id'=>$expense->payment_account_id,'credit'=>(string)$expense->total_amount,'party_id'=>$expense->party_id,'branch_id'=>$expense->branch_id,'department_id'=>$expense->department_id,'cost_center_id'=>$expense->cost_center_id,'description'=>'Expense payment'];
            $this->journals->post($expense,['company_id'=>$expense->company_id,'branch_id'=>$expense->branch_id,'posting_date'=>$expense->expense_date,'document_date'=>$expense->expense_date,'reference_number'=>$expense->expense_number,'source_module'=>'expenses','description'=>'Expense '.$expense->expense_number],$lines);
            $expense->forceFill(['status'=>DocumentStatus::POSTED,'posted_at'=>now()])->save();
            $this->audit->log('posted','expenses',$expense,[],['status'=>'posted']);
            return $expense->refresh();
        },3);
    }
}
