<?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\CashboxRepository;
use InvalidArgumentException;
use PDO;

final class CashboxService
{
    public function __construct(private PDO $pdo, private CashboxRepository $repo) {}

    public function ensureSchema(): void
    {
        SchemaRuntime::ensure($this->pdo, 'cashboxes_schema', function (): void { FinanceSchemaSupport::ensureCashboxesSchema($this->pdo); }, 'sql/migrate_v1_27_cashboxes.sql');
    }

    public function balancesFor(array $cashboxes, ?string $date = null): array
    {
        $balances = []; $date = $date ?: date('Y-m-d');
        foreach ($cashboxes as $cb) $balances[(int)$cb['id']] = AccountBalanceSupport::cashboxBalance($this->pdo, (int)$cb['id'], $date);
        return $balances;
    }

    public function loadForm(int $id): array
    {
        $cashbox = ['id'=>0,'name'=>'','opening_balance'=>'0.00','is_active'=>1];
        if ($id > 0) {
            $row = $this->repo->findById($id);
            if ($row) $cashbox = $row;
        }
        return ['cashbox'=>$cashbox,'errors'=>[],'is_edit'=>$id>0];
    }

    public function save(int $id, array $input): void
    {
        $data = [
            'name' => trim((string)($input['name'] ?? '')),
            'opening_balance' => trim((string)($input['opening_balance'] ?? '0')),
            'is_active' => (int)($input['is_active'] ?? 1),
        ];
        if ($data['name'] === '') throw new InvalidArgumentException('اسم الخزنة مطلوب.');
        if (!is_numeric($data['opening_balance'])) throw new InvalidArgumentException('رصيد افتتاحي غير صحيح.');
        $data['opening_balance'] = (float)$data['opening_balance'];
        if ($id > 0) $this->repo->update($id, $data); else $this->repo->create($data);
    }

    public function loadLedger(int $cashboxId, string $from, string $to): array
    {
        $cashboxes = $this->repo->activeAllBasic();
        if ($from === '') $from = date('Y-m-01');
        if ($to === '') $to = date('Y-m-d');
        if ($cashboxId <= 0) $cashboxId = (int)($cashboxes[0]['id'] ?? 1);
        $openBal = AccountBalanceSupport::cashboxBalance($this->pdo, $cashboxId, date('Y-m-d', strtotime($from.' -1 day')));
        $rows = $this->repo->ledgerRows($cashboxId, $from, $to);
        $running = $openBal; $tx = []; $inTotal = 0.0; $outTotal = 0.0;
        foreach ($rows as $r) {
            $amt = (float)$r['amount'];
            if ($r['trx_type'] === 'in') { $inTotal += $amt; $running += $amt; }
            else { $outTotal += $amt; $running -= $amt; }
            $r['running'] = $running; $tx[] = $r;
        }
        return compact('cashboxes','cashboxId','from','to','openBal','tx','inTotal','outTotal') + ['endBal'=>$running];
    }

    public function loadTxnForm(): array
    {
        $cashboxes = $this->repo->activeForSelect();
        $form = ['cashbox_id'=>(int)($cashboxes[0]['id'] ?? 1),'trx_date'=>date('Y-m-d'),'trx_time'=>date('H:i'),'trx_type'=>'in','amount'=>'','notes'=>''];
        return compact('cashboxes','form') + ['errors'=>[], 'success'=>''];
    }

    public function submitTxn(array $input, int $userId): void
    {
        $form = [
            'cashbox_id' => (int)($input['cashbox_id'] ?? 0),
            'trx_date' => trim((string)($input['trx_date'] ?? '')),
            'trx_time' => trim((string)($input['trx_time'] ?? '00:00')),
            'trx_type' => trim((string)($input['trx_type'] ?? 'in')),
            'amount' => trim((string)($input['amount'] ?? '')),
            'notes' => trim((string)($input['notes'] ?? '')),
        ];
        if ($form['cashbox_id'] <= 0) throw new InvalidArgumentException('اختر خزنة.');
        if ($form['trx_date'] === '') throw new InvalidArgumentException('التاريخ مطلوب.');
        if (!in_array($form['trx_type'], ['in','out'], true)) throw new InvalidArgumentException('نوع الحركة غير صحيح.');
        if ($form['amount'] === '' || !is_numeric($form['amount']) || (float)$form['amount'] <= 0) throw new InvalidArgumentException('المبلغ غير صحيح.');
        $amount = (float)$form['amount'];
        if ($form['trx_type'] === 'out') {
            $cashAvail = AccountBalanceSupport::cashboxBalance($this->pdo, (int)$form['cashbox_id'], $form['trx_date']);
            if ($amount > $cashAvail) throw new InvalidArgumentException('رصيد الخزنة لا يكفي لهذه الحركة. المتاح: ' . number_format($cashAvail, 2) . '.');
        }
        $dt = $form['trx_date'].' '.($form['trx_time'] ?: '00:00').':00';
        AccountBalanceSupport::addCashboxTransaction($this->pdo, $form['cashbox_id'], $dt, $form['trx_type'], $amount, 'manual', null, $form['notes'], $userId);
    }
}
