<?php

declare(strict_types=1);

namespace App\Services;

use App\Shared\Finance\AccountBalanceSupport;
use App\Shared\Schema\FinanceSchemaSupport;
use App\Core\SchemaRuntime;
use App\Repositories\BankTransactionRepository;
use InvalidArgumentException;
use PDO;

final class BankTransactionService
{
    public function __construct(private PDO $pdo, private BankTransactionRepository $repo) {}
    public function ensureSchema(): void { SchemaRuntime::ensure($this->pdo, 'bank_accounts_schema', function (): void { FinanceSchemaSupport::ensureBankAccountsSchema($this->pdo); }, 'sql/migrate_v1_21_bank_accounts.sql'); SchemaRuntime::ensure($this->pdo, 'cashboxes_schema', function (): void { FinanceSchemaSupport::ensureCashboxesSchema($this->pdo); }, 'sql/migrate_v1_27_cashboxes.sql'); }
    public function loadForm(): array { $bankAccounts=$this->repo->activeBankAccounts(); $cashboxes=$this->repo->activeCashboxes(); $form=['bank_account_id'=>(int)($bankAccounts[0]['id'] ?? 0),'action_type'=>'deposit','cashbox_id'=>(int)($cashboxes[0]['id'] ?? 0),'trx_date'=>date('Y-m-d'),'trx_time'=>date('H:i'),'amount'=>'','ref_no'=>'','notes'=>'']; return compact('bankAccounts','cashboxes','form') + ['errors'=>[],'success'=>'']; }
    public function save(array $input, int $userId): void { $form=['bank_account_id'=>(int)($input['bank_account_id'] ?? 0),'action_type'=>trim((string)($input['action_type'] ?? 'deposit')),'cashbox_id'=>(int)($input['cashbox_id'] ?? 0),'trx_date'=>trim((string)($input['trx_date'] ?? '')),'trx_time'=>trim((string)($input['trx_time'] ?? '00:00')),'amount'=>trim((string)($input['amount'] ?? '')),'ref_no'=>trim((string)($input['ref_no'] ?? '')),'notes'=>trim((string)($input['notes'] ?? ''))]; if($form['bank_account_id']<=0) throw new InvalidArgumentException('اختر الحساب البنكي.'); if(!in_array($form['action_type'], ['deposit','withdraw','cash_to_bank','bank_to_cash'], true)) throw new InvalidArgumentException('نوع الحركة غير صحيح.'); if($form['trx_date']==='') throw new InvalidArgumentException('التاريخ مطلوب.'); if($form['amount']==='' || !is_numeric($form['amount']) || (float)$form['amount']<=0) throw new InvalidArgumentException('المبلغ غير صحيح.'); if(in_array($form['action_type'], ['cash_to_bank','bank_to_cash'], true) && $form['cashbox_id']<=0) throw new InvalidArgumentException('اختر الخزنة.'); $amount=(float)$form['amount']; $dt=$form['trx_date'].' '.($form['trx_time']?:'00:00').':00'; if(in_array($form['action_type'], ['withdraw','bank_to_cash'], true)){ $bankBal=AccountBalanceSupport::bankAccountBalance($this->pdo,(int)$form['bank_account_id'],$form['trx_date']); if($amount>$bankBal) throw new InvalidArgumentException('رصيد الحساب البنكي لا يكفي لهذه العملية. المتاح: '.number_format($bankBal,2).'.'); } if($form['action_type']==='cash_to_bank'){ $cashBal=AccountBalanceSupport::cashboxBalance($this->pdo,(int)$form['cashbox_id'],$form['trx_date']); if($amount>$cashBal) throw new InvalidArgumentException('رصيد الخزنة لا يكفي لهذه العملية. المتاح: '.number_format($cashBal,2).'.'); }
        $this->pdo->beginTransaction(); try { $sourceType=null; $trxType='in'; $sourceId=null; switch($form['action_type']){ case 'deposit': $sourceType='deposit'; $trxType='in'; break; case 'withdraw': $sourceType='withdraw'; $trxType='out'; break; case 'cash_to_bank': $sourceType='cash_to_bank'; $trxType='in'; $sourceId=(int)$form['cashbox_id']; AccountBalanceSupport::addCashboxTransaction($this->pdo,(int)$form['cashbox_id'],$dt,'out',$amount,'bank_transfer',null,'تحويل من خزنة إلى بنك'.($form['notes']!=='' ? ' - '.$form['notes'] : ''),$userId); break; case 'bank_to_cash': $sourceType='bank_to_cash'; $trxType='out'; $sourceId=(int)$form['cashbox_id']; break; } $newId=$this->repo->create(['bank_account_id'=>(int)$form['bank_account_id'],'trx_date'=>$dt,'trx_type'=>$trxType,'amount'=>$amount,'source_type'=>$sourceType,'source_id'=>$sourceId,'ref_no'=>$form['ref_no']!==''?$form['ref_no']:null,'notes'=>$form['notes']!==''?$form['notes']:null,'user_id'=>$userId]); if($form['action_type']==='bank_to_cash'){ AccountBalanceSupport::addCashboxTransaction($this->pdo,(int)$form['cashbox_id'],$dt,'in',$amount,'bank_transfer',$newId,'تحويل من بنك إلى خزنة'.($form['notes']!=='' ? ' - '.$form['notes'] : ''),$userId); } audit_log('BANK_TXN_'.strtoupper($form['action_type']), 'bank_transactions', $newId, ['bank_account_id'=>(int)$form['bank_account_id'],'amount'=>$amount,'action_type'=>$form['action_type']]); $this->pdo->commit(); } catch(\Throwable $e){ if($this->pdo->inTransaction()) $this->pdo->rollBack(); throw $e; } }
    public function loadStatement(int $bankId, string $from, string $to, string $q): array { if($from==='') $from=date('Y-m-01'); if($to==='') $to=date('Y-m-d'); $bankAccounts=$this->repo->activeBankAccounts(); $account=null; $rows=[]; $opening=0.0; $closing=0.0; $totals=['in'=>0.0,'out'=>0.0]; if($bankId>0){ $account=$this->repo->findAccount($bankId) ?: null; if($account){ $prevDate=date('Y-m-d', strtotime($from . ' -1 day')); $opening=AccountBalanceSupport::bankAccountBalance($this->pdo,$bankId,$prevDate); $rows=$this->repo->statementRows($bankId,$from,$to,$q); $closing=$opening; foreach($rows as $r){ if(($r['trx_type'] ?? '') === 'in'){ $totals['in'] += (float)$r['amount']; $closing += (float)$r['amount']; } else { $totals['out'] += (float)$r['amount']; $closing -= (float)$r['amount']; } } } } return compact('bankAccounts','bankId','account','from','to','q','rows','opening','closing','totals'); }
}
