<?php

namespace App\Services\Accounting;

use App\Enums\JournalStatus;
use App\Models\Branch;
use App\Models\JournalEntry;
use App\Services\Audit\AuditLogger;
use App\Support\Decimal;
use DomainException;
use Illuminate\Support\Facades\DB;

final class ReversalService
{
    public function __construct(private readonly AuthorizationGuard $authorization,private readonly AccountingPeriodGuard $periodGuard,private readonly JournalNumberService $numbers,private readonly AuditLogger $audit){}
    public function reverse(JournalEntry $original,string $date,string $reason):JournalEntry{return DB::transaction(function()use($original,$date,$reason){$original=JournalEntry::with('lines')->lockForUpdate()->findOrFail($original->id);$this->authorization->ensureCan('journals.reverse',(int)$original->company_id,(int)$original->branch_id);if($original->status!==JournalStatus::POSTED)throw new DomainException('Only posted journals can be reversed.');if(JournalEntry::where('reversal_of_id',$original->id)->exists())throw new DomainException('This journal already has a reversal.');$period=$this->periodGuard->openPeriodFor((int)$original->company_id,$date);$branch=Branch::findOrFail($original->branch_id);$rev=JournalEntry::create(['company_id'=>$original->company_id,'branch_id'=>$original->branch_id,'accounting_period_id'=>$period->id,'journal_number'=>$this->numbers->next($branch,$date),'posting_date'=>$date,'document_date'=>$date,'reference_number'=>'REV-'.$original->journal_number,'source_module'=>'journal_reversal','description'=>'Reversal of '.$original->journal_number.': '.$reason,'currency_code'=>$original->currency_code,'exchange_rate'=>$original->exchange_rate,'debit_total'=>$original->credit_total,'credit_total'=>$original->debit_total,'status'=>JournalStatus::POSTED,'created_by'=>auth()->id(),'posted_by'=>auth()->id(),'posted_at'=>now(),'reversal_of_id'=>$original->id]);foreach($original->lines as $i=>$line){$rev->lines()->create(['line_number'=>$i+1,'account_id'=>$line->account_id,'party_id'=>$line->party_id,'party_ledger'=>$line->party_ledger,'branch_id'=>$line->branch_id,'department_id'=>$line->department_id,'cost_center_id'=>$line->cost_center_id,'description'=>'Reversal: '.$line->description,'debit'=>(string)$line->credit,'credit'=>(string)$line->debit,'currency_code'=>$line->currency_code,'exchange_rate'=>$line->exchange_rate]);}$this->audit->log('reversed','journals',$original,[],['reversal_journal'=>$rev->journal_number],$reason);return$rev->load('lines');},3);}
}
