<?php
namespace App\Http\Controllers;
use App\Models as M;
use App\Services\FinanceService;
use App\Services\SequenceService;
use App\Support\CrudRegistry;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class SupplierPaymentController extends Controller {
    use Concerns\FxDoc;
    public function index(Request $r) { return app(CrudController::class)->index($r, 'supplier-payments'); }
    public function show(int $id) { return app(CrudController::class)->show('supplier-payments', $id); }
    public function create(Request $r) {
        $this->need('purchase.create');
        $p = new M\SupplierPayment(['payment_date' => date('Y-m-d'), 'payment_mode' => 'bank-transfer']);
        if ($r->filled('invoice_id')) { $inv = M\PurchaseInvoice::find($r->invoice_id); if ($inv) { $p->invoice_id = $inv->id; $p->supplier_id = $inv->supplier_id; $p->amount = $inv->balance_due; } }
        return view('docs.supplier-payment.form', ['record' => $p, 'cfg' => CrudRegistry::get('supplier-payments'), 'key' => 'supplier-payments',
            'docNo' => SequenceService::peek('supplier_payment'),
            'suppliers' => M\Supplier::where('is_active', true)->orderBy('name')->get(),
            'invoices' => M\PurchaseInvoice::where('balance_due', '>', 0)->whereNotIn('status', ['paid', 'cancelled', 'draft'])->orderByDesc('id')->limit(300)->get(),
            'banks' => M\BankAccount::where('is_active', true)->orderBy('bank_name')->get(), 'fx' => \App\Services\CurrencyService::active()]);
    }
    public function store(Request $r) {
        $this->need('purchase.create');
        $d = $r->validate(['supplier_id' => 'required|exists:suppliers,id', 'invoice_id' => 'nullable|exists:purchase_invoices,id', 'payment_date' => 'required|date',
            'amount' => 'required|numeric|min:0.01', 'payment_mode' => 'required|in:cash,bank-transfer,cheque,momo', 'bank_account_id' => 'nullable|exists:bank_accounts,id',
            'cheque_no' => 'nullable|max:40', 'reference' => 'nullable|max:80', 'paid_by' => 'nullable|max:100', 'remarks' => 'nullable|max:500'] + $this->fxRules());
        if ($d['invoice_id'] ?? null) {
            $inv = M\PurchaseInvoice::find($d['invoice_id']);
            abort_if($d['currency_code'] !== $inv->currency_code, 403, 'Settle in bill currency ('.$inv->currency_code.').');
            abort_if($d['amount'] > $inv->balance_due + 0.009, 403, 'Amount exceeds bill balance of '.money($inv->balance_due));
        }
        if (!empty($d['bank_account_id'])) {
            $ba = M\BankAccount::find($d['bank_account_id']);
            abort_if(strtoupper($ba->currency ?? 'GHS') !== $d['currency_code'], 403, 'Payment is '.$d['currency_code'].' but account '.$ba->account_no.' is '.$ba->currency.' — use a matching-currency account.');
        }
        $p = DB::transaction(function () use ($d) {
            $p = M\SupplierPayment::create($d + ['payment_no' => SequenceService::next('supplier_payment')]);
            if ($p->invoice_id) {
                $inv = M\PurchaseInvoice::find($p->invoice_id);
                $inv->increment('amount_paid', $p->amount);
                $inv->decrement('balance_due', $p->amount);
                $inv->update(['status' => $inv->fresh()->balance_due <= 0.009 ? 'paid' : 'partially-paid']);
            }
            $billRate = $p->invoice_id ? (float) M\PurchaseInvoice::where('id', $p->invoice_id)->value('exchange_rate') : (float) $p->exchange_rate;
            $payGhs = \App\Services\CurrencyService::toGhs($p->amount, $p->exchange_rate);
            $apGhs = \App\Services\CurrencyService::toGhs($p->amount, $billRate);
            $p->supplier()->decrement('current_balance', $apGhs);
            if ($p->bank_account_id) {
                FinanceService::bankTxn($p->bank_account_id, $p->payment_date->format('Y-m-d'), 'withdrawal', $p->amount, 'Payment '.$p->payment_no, 'supplier_payment', $p->id, $p->payment_no, $p->currency_code, (float) $p->exchange_rate);
                $bank = M\BankAccount::find($p->bank_account_id);
                $jlines = [
                    ['account' => '2000', 'debit' => $apGhs, 'narration' => 'AP settlement'],
                    ['account' => $bank->gl_account_id ?? '1010', 'credit' => $payGhs, 'narration' => 'Payment '.$p->payment_no],
                ];
                $diff = round($payGhs - $apGhs, 2); // FX on settlement
                if ($diff >= 0.005) $jlines[] = ['account' => '5650', 'debit' => $diff, 'narration' => 'FX loss — '.$p->payment_no];
                elseif ($diff <= -0.005) $jlines[] = ['account' => '4950', 'credit' => -$diff, 'narration' => 'FX gain — '.$p->payment_no];
                FinanceService::postJournal($p->payment_date->format('Y-m-d'), 'Supplier payment '.$p->payment_no.' ('.$p->currency_code.' @ '.$p->exchange_rate.')', $jlines, 'supplier_payment', $p->id, $p->payment_no);
            }
            return $p;
        });
        return redirect()->route('supplier-payments.show', $p)->with('success', 'Payment '.$p->payment_no.' posted.');
    }
}
