<?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 CustomerPaymentController extends Controller {
    use Concerns\FxDoc;
    public function index(Request $r) { return app(CrudController::class)->index($r, 'customer-payments'); }
    public function show(int $id) { return app(CrudController::class)->show('customer-payments', $id); }
    public function create(Request $r) {
        $this->need('sales.create');
        $p = new M\CustomerPayment(['payment_date' => date('Y-m-d'), 'payment_mode' => 'bank-transfer']);
        if ($r->filled('invoice_id')) { $inv = M\SalesInvoice::find($r->invoice_id); if ($inv) { $p->invoice_id = $inv->id; $p->customer_id = $inv->customer_id; $p->amount = $inv->balance_due; } }
        return view('docs.customer-payment.form', ['record' => $p, 'cfg' => CrudRegistry::get('customer-payments'), 'key' => 'customer-payments',
            'docNo' => SequenceService::peek('customer_payment'),
            'customers' => M\Customer::where('is_active', true)->orderBy('name')->get(),
            'invoices' => M\SalesInvoice::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('sales.create');
        $d = $r->validate(['customer_id' => 'required|exists:customers,id', 'invoice_id' => 'nullable|exists:sales_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', 'received_by' => 'nullable|max:100', 'remarks' => 'nullable|max:500'] + $this->fxRules());
        if ($d['invoice_id'] ?? null) {
            $inv = M\SalesInvoice::find($d['invoice_id']);
            abort_if($d['currency_code'] !== $inv->currency_code, 403, 'Settle in invoice currency ('.$inv->currency_code.').');
            abort_if($d['amount'] > $inv->balance_due + 0.009, 403, 'Amount exceeds invoice 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, 'Receipt 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\CustomerPayment::create($d + ['receipt_no' => SequenceService::next('customer_payment')]);
            if ($p->invoice_id) {
                $inv = M\SalesInvoice::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']);
            }
            $invRate = $p->invoice_id ? (float) M\SalesInvoice::where('id', $p->invoice_id)->value('exchange_rate') : (float) $p->exchange_rate;
            $bankGhs = \App\Services\CurrencyService::toGhs($p->amount, $p->exchange_rate);
            $arGhs = \App\Services\CurrencyService::toGhs($p->amount, $invRate);
            $p->customer()->decrement('current_balance', $arGhs);
            if ($p->bank_account_id) {
                FinanceService::bankTxn($p->bank_account_id, $p->payment_date->format('Y-m-d'), 'deposit', $p->amount, 'Receipt '.$p->receipt_no, 'sales_receipt', $p->id, $p->receipt_no, $p->currency_code, (float) $p->exchange_rate);
                $bank = M\BankAccount::find($p->bank_account_id);
                $jlines = [
                    ['account' => $bank->gl_account_id ?? '1010', 'debit' => $bankGhs, 'narration' => 'Receipt '.$p->receipt_no],
                    ['account' => '1100', 'credit' => $arGhs, 'narration' => 'AR settlement'],
                ];
                $diff = round($bankGhs - $arGhs, 2); // FX on settlement
                if ($diff >= 0.005) $jlines[] = ['account' => '4950', 'credit' => $diff, 'narration' => 'FX gain — '.$p->receipt_no];
                elseif ($diff <= -0.005) $jlines[] = ['account' => '5650', 'debit' => -$diff, 'narration' => 'FX loss — '.$p->receipt_no];
                FinanceService::postJournal($p->payment_date->format('Y-m-d'), 'Customer receipt '.$p->receipt_no.' ('.$p->currency_code.' @ '.$p->exchange_rate.')', $jlines, 'sales_receipt', $p->id, $p->receipt_no);
            }
            return $p;
        });
        return redirect()->route('customer-payments.show', $p)->with('success', 'Receipt '.$p->receipt_no.' posted.');
    }
    public function print(Request $r, int $id) {
        $this->need('sales.view');
        $doc = M\CustomerPayment::with('customer', 'invoice')->findOrFail($id);
        if ($r->get('pdf')) return \App\Services\PdfService::download('docs.customer-payment.print', ['p' => $doc], 'RCPT-'.($doc->receipt_no ?? $id).'.pdf');
        return view('docs.customer-payment.print', ['p' => $doc]);
    }
}
