<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use App\Services\AccountingService;

/**
 * ReceivablePaymentController
 * * Modul Enterprise untuk menangani Pelunasan Piutang (Accounts Receivable).
 * Mendukung metode pembayaran Cash, Transfer Bank, dan Giro/Cek Mundur.
 * Dilengkapi dengan sistem Kliring Giro dan Penjurnalan Akuntansi Otomatis.
 * * Alur Kerja:
 * 1. Tarik daftar faktur penjualan yang belum lunas (Unpaid/Partial).
 * 2. Input pembayaran (Jika Giro -> Masuk daftar tunggu / Pending).
 * 3. Eksekusi Kliring Giro (Cairkan ke Bank atau Tolak kembali ke Piutang).
 */
class ReceivablePaymentController extends Controller
{
    /**
     * 1. GET UNPAID SALES (DAFTAR PIUTANG PELANGGAN)
     */
    public function getUnpaidReceivables(Request $request)
    {
        try {
            $user = auth()->user();
            
            // Subquery untuk menghitung total pembayaran yang sudah cair (Cash/Transfer/Cleared Giro)
            $paidSubquery = DB::table('debt_payments')
                ->select(DB::raw('COALESCE(SUM(amount), 0)'))
                ->whereColumn('sale_id', 'sales.id')
                ->where('payment_status', '!=', 'cancelled') // Pastikan pembayaran batal tidak terhitung
                ->where(function ($q) {
                    $q->where('payment_method', '!=', 'giro')
                      ->orWhere(function ($q2) {
                          $q2->where('payment_method', 'giro')
                             ->where('giro_status', 'cleared');
                      });
                });

            // Subquery untuk menghitung total Giro yang masih menggantung
            $pendingGiroSubquery = DB::table('debt_payments')
                ->select(DB::raw('COALESCE(SUM(amount), 0)'))
                ->whereColumn('sale_id', 'sales.id')
                ->where('payment_status', '!=', 'cancelled')
                ->where('payment_method', 'giro')
                ->where('giro_status', 'pending');
            
            $query = DB::table('sales')
                ->leftJoin('customers', 'sales.customer_id', '=', 'customers.id')
                ->leftJoin('users', 'sales.user_id', '=', 'users.id')
                ->leftJoin('salesmen', 'customers.salesman_id', '=', 'salesmen.id')
                ->leftJoin('users as sm_user', 'salesmen.user_id', '=', 'sm_user.id')
                ->select(
                    'sales.id', 
                    'sales.invoice_number', 
                    'sales.customer_name', 
                    'customers.address as customer_address', 
                    'sm_user.name as salesman_name',         
                    'users.name as created_by_name',         
                    'sales.grand_total', 
                    'sales.payment_status', 
                    'sales.created_at',
                    'sales.due_date'
                )
                ->selectSub($paidSubquery, 'total_paid')
                ->selectSub($pendingGiroSubquery, 'total_pending_giro')
                ->whereIn('sales.payment_status', ['pending', 'partial']);

            // PERBAIKAN ENTERPRISE: Isolasi Cabang
            if ($user->role !== 'owner') {
                $query->where('sales.branch_id', $user->branch_id);
            }

            $unpaidSales = $query->orderBy('sales.created_at', 'asc')->get();

            $data = [];
            foreach ($unpaidSales as $sale) {
                $outstanding = $sale->grand_total - $sale->total_paid;
                if ($outstanding > 0) {
                    $sale->outstanding_balance = $outstanding;
                    $data[] = $sale;
                }
            }

            return response()->json([
                'success' => true,
                'data' => $data
            ]);

        } catch (\Exception $e) {
            Log::error("Get Unpaid Receivables Error: " . $e->getMessage());
            return response()->json([
                'success' => false, 
                'message' => 'Gagal memuat daftar piutang: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * 2. PROSES PELUNASAN PIUTANG MANUAL (STORE PAYMENT)
     */
    public function storePayment(Request $request)
    {
        $request->validate([
            'sale_id' => 'required|exists:sales,id',
            'amount' => 'required|numeric|min:1',
            'payment_method' => 'required|in:cash,transfer,giro',
            'account_id' => 'required|exists:accounts,id', 
            'payment_date' => 'required|date',
            'giro_number' => 'required_if:payment_method,giro',
            'giro_due_date' => 'required_if:payment_method,giro|date',
        ]);

        DB::beginTransaction();

        try {
            $user = auth()->user();
            $sale = DB::table('sales')->where('id', $request->sale_id)->first();
            
            if (!$sale) {
                return response()->json(['success' => false, 'message' => 'Faktur penjualan tidak ditemukan.'], 404);
            }

            // PERBAIKAN ENTERPRISE: Keamanan Silang Cabang
            if ($user->role !== 'owner' && $sale->branch_id !== $user->branch_id) {
                return response()->json(['success' => false, 'message' => 'Akses ditolak: Faktur ini bukan milik cabang Anda.'], 403);
            }

            // PERBAIKAN ENTERPRISE: Validasi Rekening Bank (Branch Account Mapping)
            if ($user->role !== 'owner') {
                $isMapped = DB::table('branch_accounts')
                    ->where('branch_id', $sale->branch_id)
                    ->where('account_id', $request->account_id)
                    ->where('is_active', 1)
                    ->exists();

                if (!$isMapped) {
                    throw new \Exception("Akses ditolak (Security Lock): Akun penerimaan dana yang dipilih tidak terdaftar untuk cabang ini.");
                }
            }

            $totalPaidSoFar = DB::table('debt_payments')
                ->where('sale_id', $sale->id)
                ->where('payment_status', '!=', 'cancelled')
                ->where(function ($q) {
                    $q->where('payment_method', '!=', 'giro')
                      ->orWhere(function ($q2) {
                          $q2->where('giro_status', 'cleared');
                      });
                })
                ->sum('amount');

            $outstanding = $sale->grand_total - $totalPaidSoFar;
            
            $payAmount = (float) $request->amount;
            $excessAmount = 0;
            $allocatedToDebt = $payAmount;

            if ($payAmount > $outstanding && $outstanding > 0) {
                $allocatedToDebt = $outstanding;
                $excessAmount = $payAmount - $outstanding;
            } elseif ($outstanding <= 0) {
                $allocatedToDebt = 0;
                $excessAmount = $payAmount;
            }

            $paymentId = DB::table('debt_payments')->insertGetId([
                'sale_id' => $sale->id,
                'branch_id' => $sale->branch_id,
                'user_id' => $user->id,
                'amount' => $payAmount,
                'account_id' => $request->account_id,
                'payment_method' => $request->payment_method,
                'payment_type' => 'receivable', 
                'payment_status' => 'completed',
                'payment_date' => $request->payment_date,
                'giro_number' => $request->payment_method === 'giro' ? $request->giro_number : null,
                'giro_due_date' => $request->payment_method === 'giro' ? $request->giro_due_date : null,
                'giro_status' => $request->payment_method === 'giro' ? 'pending' : 'cleared',
                'note' => $excessAmount > 0 
                    ? ($request->note . " (Kelebihan Rp " . number_format($excessAmount, 0, ',', '.') . " masuk deposit)") 
                    : $request->note,
                'created_at' => Carbon::now(),
                'updated_at' => Carbon::now()
            ]);

            if ($excessAmount > 0 && $sale->customer_id) {
                DB::table('customers')
                    ->where('id', $sale->customer_id)
                    ->increment('deposit_balance', $excessAmount);
            }

            // =========================================================================
            // EKSEKUSI JURNAL VIA ACCOUNTING SERVICE DENGAN VALIDASI KETAT
            // =========================================================================
            $targetAccountId = $request->account_id;
            if ($request->payment_method === 'giro') {
                // PERBAIKAN: Gunakan AccountingService untuk menarik akun Giro
                $giroAccountId = AccountingService::getAccountId('giro_masuk');
                if (!$giroAccountId) throw new \Exception("Akun Giro Masuk belum dikonfigurasi di Pengaturan Akuntansi.");
                $targetAccountId = $giroAccountId;
            }

            $journalItems = [];

            // 1. (Debit) Kas/Bank/Giro Bertambah
            $journalItems[] = ['account_id' => $targetAccountId, 'debit' => $payAmount, 'credit' => 0];

            // 2. (Kredit) Piutang Berkurang
            if ($allocatedToDebt > 0) {
                $piutangAccountId = AccountingService::getAccountId('receivable_account');
                if (!$piutangAccountId) throw new \Exception("Akun Piutang Usaha belum di-mapping di Pengaturan Akuntansi.");
                
                $journalItems[] = ['account_id' => $piutangAccountId, 'debit' => 0, 'credit' => $allocatedToDebt];
            }

            // 3. (Kredit) Deposit Pelanggan (Jika Uang Lebih)
            if ($excessAmount > 0) {
                // PERBAIKAN: Gunakan AccountingService untuk menarik akun Uang Muka/Titipan Pelanggan
                $depositAccountId = AccountingService::getAccountId('deposit_pelanggan');
                if (!$depositAccountId) throw new \Exception("Akun Uang Muka/Titipan Pelanggan belum dikonfigurasi di Pengaturan Akuntansi.");
                
                $journalItems[] = ['account_id' => $depositAccountId, 'debit' => 0, 'credit' => $excessAmount];
            }

            AccountingService::log([
                'branch_id'   => $sale->branch_id,
                'entry_date'  => $request->payment_date,
                'description' => "Penerimaan AR: " . $sale->invoice_number . " (" . strtoupper($request->payment_method) . ")",
                'reference'   => 'PAY-AR-' . $paymentId,
                'source_type' => 'AR_PAYMENT',
                'user_id'     => $user->id,
                'items'       => $journalItems
            ]);
            // =========================================================================

            if ($request->payment_method !== 'giro') {
                $this->updateSalePaymentStatus($sale->id);
            }

            DB::commit();

            return response()->json([
                'success' => true, 
                'message' => $excessAmount > 0 
                    ? 'Pembayaran berhasil dicatat. Kelebihan saldo otomatis masuk ke Deposit Pelanggan.' 
                    : 'Pembayaran piutang berhasil dicatat dan dijurnal.'
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error("Store AR Payment Error: " . $e->getMessage());
            return response()->json([
                'success' => false, 
                'message' => 'Gagal mencatat pembayaran: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * FUNGSI INTERNAL: Update Status Faktur Penjualan (Paid / Partial)
     */
    private function updateSalePaymentStatus($saleId)
    {
        $sale = DB::table('sales')->where('id', $saleId)->first();
        
        $totalPaid = DB::table('debt_payments')
            ->where('sale_id', $saleId)
            ->where('payment_status', '!=', 'cancelled')
            ->where(function ($q) {
                $q->where('payment_method', '!=', 'giro')
                  ->orWhere(function ($q2) {
                      $q2->where('payment_method', 'giro')
                         ->where('giro_status', 'cleared');
                  });
            })
            ->sum('amount');

        $newStatus = 'pending';
        if (abs($totalPaid - $sale->grand_total) < 0.01 || $totalPaid > $sale->grand_total) {
            $newStatus = 'paid';
        } elseif ($totalPaid > 0) {
            $newStatus = 'partial';
        }

        DB::table('sales')->where('id', $saleId)->update([
            'payment_status' => $newStatus,
            'paid_amount' => $totalPaid,
            'updated_at' => Carbon::now()
        ]);
    }
    
    /**
     * 3. GET DAFTAR GIRO MASUK (PENDING CLEARANCE)
     */
    public function getPendingGiro(Request $request)
    {
        try {
            $user = auth()->user();
            
            $query = DB::table('debt_payments')
                ->join('sales', 'debt_payments.sale_id', '=', 'sales.id')
                ->select(
                    'debt_payments.*',
                    'sales.invoice_number',
                    'sales.customer_name'
                )
                ->where('debt_payments.payment_method', 'giro')
                ->where('debt_payments.payment_type', 'receivable')
                ->where('debt_payments.giro_status', 'pending');

            // PERBAIKAN ENTERPRISE: Isolasi Daftar Giro
            if ($user->role !== 'owner') {
                $query->where('debt_payments.branch_id', $user->branch_id);
            }

            $giros = $query->orderBy('debt_payments.giro_due_date', 'asc')->get();

            return response()->json([
                'success' => true,
                'data' => $giros
            ]);

        } catch (\Exception $e) {
            Log::error("Get Pending Giro AR Error: " . $e->getMessage());
            return response()->json(['success' => false, 'message' => 'Gagal memuat daftar Giro.'], 500);
        }
    }

    /**
     * 4. PROSES KLIRING GIRO (CAIR ATAU TOLAK) DENGAN JURNAL OTOMATIS
     */
    public function processGiro(Request $request, $id)
    {
        $request->validate([
            'action' => 'required|in:clear,reject',
            'clearance_date' => 'required|date',
            'bank_account_id' => 'required_if:action,clear|exists:accounts,id' 
        ]);

        DB::beginTransaction();

        try {
            $user = auth()->user();
            $payment = DB::table('debt_payments')->where('id', $id)->first();
            
            if (!$payment || $payment->payment_method !== 'giro' || $payment->giro_status !== 'pending') {
                return response()->json(['success' => false, 'message' => 'Giro tidak valid atau sudah diproses sebelumnya.'], 400);
            }

            // PERBAIKAN ENTERPRISE: Keamanan Kliring Lintas Cabang
            if ($user->role !== 'owner' && $payment->branch_id !== $user->branch_id) {
                return response()->json(['success' => false, 'message' => 'Akses ditolak: Giro ini bukan wewenang cabang Anda.'], 403);
            }

            // PERBAIKAN ENTERPRISE: Validasi Mapping Rekening Bank saat Pencairan
            if ($request->action === 'clear' && $user->role !== 'owner') {
                $isMapped = DB::table('branch_accounts')
                    ->where('branch_id', $payment->branch_id)
                    ->where('account_id', $request->bank_account_id)
                    ->where('is_active', 1)
                    ->exists();

                if (!$isMapped) {
                    throw new \Exception("Akses ditolak: Rekening Bank tujuan pencairan tidak terdaftar untuk cabang Anda.");
                }
            }

            $sale = DB::table('sales')->where('id', $payment->sale_id)->first();

            $piutangAccountId = AccountingService::getAccountId('receivable_account');
            if (!$piutangAccountId) throw new \Exception("Akun Piutang Usaha belum di-mapping di Pengaturan Akuntansi.");

            $giroAccountId = AccountingService::getAccountId('giro_masuk');
            if (!$giroAccountId) throw new \Exception("Akun Giro Masuk belum dikonfigurasi di Pengaturan Akuntansi.");

            if ($request->action === 'clear') {
                // --- SKENARIO 1: GIRO CAIR (CLEARED) ---
                DB::table('debt_payments')->where('id', $id)->update([
                    'giro_status' => 'cleared',
                    'updated_at' => Carbon::now()
                ]);

                AccountingService::log([
                    'branch_id'   => $payment->branch_id,
                    'entry_date'  => $request->clearance_date,
                    'description' => "Pencairan Giro Masuk: " . $payment->giro_number . " (Faktur: " . $sale->invoice_number . ")",
                    'reference'   => 'CLR-GIRO-' . $payment->id,
                    'source_type' => 'GIRO_CLEARANCE',
                    'user_id'     => $user->id,
                    'items'       => [
                        // DEBIT: Kas/Bank Tujuan
                        ['account_id' => $request->bank_account_id, 'debit' => $payment->amount, 'credit' => 0],
                        // KREDIT: Piutang Giro Masuk
                        ['account_id' => $giroAccountId, 'debit' => 0, 'credit' => $payment->amount]
                    ]
                ]);

                $this->updateSalePaymentStatus($sale->id);
                $message = "Giro berhasil dicairkan dan uang telah masuk ke rekening.";

            } else {
                // --- SKENARIO 2: GIRO DITOLAK / KOSONG (REJECTED) ---
                DB::table('debt_payments')->where('id', $id)->update([
                    'giro_status' => 'rejected',
                    'note' => $payment->note . " | DITOLAK pada " . $request->clearance_date,
                    'updated_at' => Carbon::now()
                ]);

                AccountingService::log([
                    'branch_id'   => $payment->branch_id,
                    'entry_date'  => $request->clearance_date,
                    'description' => "Penolakan Giro Kosong: " . $payment->giro_number . " (Faktur: " . $sale->invoice_number . ")",
                    'reference'   => 'REJ-GIRO-' . $payment->id,
                    'source_type' => 'GIRO_REJECTION',
                    'user_id'     => $user->id,
                    'items'       => [
                        // DEBIT: Piutang Pelanggan (Tagihan hidup lagi)
                        ['account_id' => $piutangAccountId, 'debit' => $payment->amount, 'credit' => 0],
                        // KREDIT: Piutang Giro Masuk (Giro dibuang)
                        ['account_id' => $giroAccountId, 'debit' => 0, 'credit' => $payment->amount]
                    ]
                ]);

                $message = "Giro telah ditolak. Saldo dikembalikan menjadi Piutang Pelanggan.";
            }

            DB::commit();

            return response()->json([
                'success' => true, 
                'message' => $message
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error("Process AR Giro Error: " . $e->getMessage());
            return response()->json([
                'success' => false, 
                'message' => 'Gagal memproses giro: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * 5. PEMBATALAN PEMBAYARAN (VOID PAYMENT)
     * * Menghapus fisik data pembayaran untuk menjaga penghitungan total akurat,
     * sekaligus mencetak jurnal pembalik agar audit trail keuangan tetap berjalan.
     */
    public function cancelPayment(Request $request, $id)
    {
        $request->validate([
            'cancel_reason' => 'required|string|min:5'
        ]);

        DB::beginTransaction();

        try {
            $user = auth()->user();
            $payment = DB::table('debt_payments')->where('id', $id)->first();
            
            if (!$payment) {
                return response()->json(['success' => false, 'message' => 'Data pembayaran tidak ditemukan.'], 404);
            }

            // PERBAIKAN ENTERPRISE: Keamanan Silang Cabang Void Payment
            if ($user->role !== 'owner' && $payment->branch_id !== $user->branch_id) {
                return response()->json(['success' => false, 'message' => 'Akses ditolak: Pembayaran ini bukan wewenang cabang Anda.'], 403);
            }

            $sale = DB::table('sales')->where('id', $payment->sale_id)->first();
            $userId = $user->id;

            $piutangAccountId = AccountingService::getAccountId('receivable_account');
            if (!$piutangAccountId) throw new \Exception("Akun Piutang Usaha belum di-mapping di Pengaturan Akuntansi.");

            $creditAccount = $payment->account_id;
            if ($payment->payment_method === 'giro') {
                $giroAccountId = AccountingService::getAccountId('giro_masuk');
                if (!$giroAccountId) throw new \Exception("Akun Giro Masuk belum dikonfigurasi.");
                $creditAccount = $giroAccountId;
            }

            // 1. Buat Jurnal Pembalik (Reversal Journal) SEBELUM data dihapus
            AccountingService::log([
                'branch_id'   => $payment->branch_id,
                'entry_date'  => date('Y-m-d'),
                'description' => "Jurnal Pembalik (Void Payment): " . ($payment->giro_number ?? "Cash") . " | Alasan: " . $request->cancel_reason,
                'reference'   => 'VOID-AR-' . $payment->id,
                'source_type' => 'AR_PAYMENT_VOID',
                'user_id'     => $userId,
                'items'       => [
                    // DEBIT: Piutang Pelanggan -> Tagihan hidup kembali
                    ['account_id' => $piutangAccountId, 'debit' => $payment->amount, 'credit' => 0],
                    // KREDIT: Kas/Bank atau Akun Giro Masuk (Sesuai metode awal)
                    ['account_id' => $creditAccount, 'debit' => 0, 'credit' => $payment->amount]
                ]
            ]);

            // 2. Jika ada uang yang masuk Deposit Pelanggan (Excess Amount), cabut kembali deposit tersebut
            $outstandingAtPaymentTime = $sale->grand_total - (DB::table('debt_payments')
                ->where('sale_id', $sale->id)
                ->where('id', '<', $payment->id)
                ->where('payment_status', '!=', 'cancelled')
                ->sum('amount'));

            if ($payment->amount > $outstandingAtPaymentTime && $outstandingAtPaymentTime >= 0) {
                $excessAmount = $payment->amount - $outstandingAtPaymentTime;
                if ($sale->customer_id && $excessAmount > 0) {
                    DB::table('customers')->where('id', $sale->customer_id)->decrement('deposit_balance', $excessAmount);
                }
            }

            // 3. Hapus data dari tabel pembayaran agar tidak terbaca oleh sum() sisa tagihan
            DB::table('debt_payments')->where('id', $id)->delete();

            // 4. Update Status Pembayaran Faktur (Hitung ulang sisa tagihan)
            $this->updateSalePaymentStatus($sale->id);

            DB::commit();
            return response()->json(['success' => true, 'message' => 'Pembayaran berhasil dibatalkan dan jurnal telah dibalikkan.']);

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error("Cancel AR Payment Error: " . $e->getMessage());
            return response()->json(['success' => false, 'message' => 'Gagal pembatalan: ' . $e->getMessage()], 500);
        }
    }

    /**
     * 5. GET RIWAYAT PEMBAYARAN (UNTUK FITUR VOID)
     */
    public function getPaymentHistory(Request $request)
    {
        try {
            $user = auth()->user();
            $query = DB::table('debt_payments')
                ->join('sales', 'debt_payments.sale_id', '=', 'sales.id')
                ->leftJoin('accounts', 'debt_payments.account_id', '=', 'accounts.id')
                ->select(
                    'debt_payments.*',
                    'sales.invoice_number',
                    'sales.customer_name',
                    'accounts.name as account_name'
                )
                ->where('debt_payments.payment_type', 'receivable');

            // PERBAIKAN ENTERPRISE: Isolasi Riwayat
            if ($user->role !== 'owner') {
                $query->where('debt_payments.branch_id', $user->branch_id);
            }

            $history = $query->orderBy('debt_payments.created_at', 'desc')->get();
            return response()->json(['success' => true, 'data' => $history]);

        } catch (\Exception $e) {
            Log::error("Get AR History Error: " . $e->getMessage());
            return response()->json(['success' => false, 'message' => 'Gagal memuat riwayat pembayaran.'], 500);
        }
    }
    
    /**
     * ========================================================================
     * MODUL VERIFIKASI SETORAN SALESMAN (MOBILE TO FINANCE)
     * ========================================================================
     */

    /**
     * 6. GET PENDING SETORAN (MENUNGGU VERIFIKASI FINANCE)
     */
    public function getPendingSetoran(Request $request)
    {
        try {
            $user = auth()->user();
            
            $query = DB::table('debt_payments')
                ->join('sales', 'debt_payments.sale_id', '=', 'sales.id')
                ->join('users as salesman', 'debt_payments.user_id', '=', 'salesman.id')
                ->select(
                    'debt_payments.*',
                    'sales.invoice_number',
                    'sales.customer_name',
                    'salesman.name as collector_name'
                )
                ->where('debt_payments.payment_type', 'receivable')
                ->where('debt_payments.payment_status', 'pending')
                ->where('debt_payments.payment_method', '!=', 'giro');

            // PERBAIKAN ENTERPRISE: Isolasi Setoran
            if ($user->role !== 'owner') {
                $query->where('debt_payments.branch_id', $user->branch_id);
            }

            $setoran = $query->orderBy('debt_payments.created_at', 'asc')->get();

            return response()->json([
                'success' => true,
                'data' => $setoran
            ]);

        } catch (\Exception $e) {
            Log::error("Get Pending Setoran Error: " . $e->getMessage());
            return response()->json(['success' => false, 'message' => 'Gagal memuat daftar setoran pending.'], 500);
        }
    }

    /**
     * 7. APPROVE SETORAN (TERIMA UANG FISIK/MUTASI)
     * Mengubah status menjadi completed, update status nota, dan cetak Jurnal Akuntansi.
     */
    public function approveSetoran(Request $request, $id)
    {
        $request->validate([
            'account_id' => 'required|exists:accounts,id' 
        ]);

        DB::beginTransaction();

        try {
            $user = auth()->user();
            $payment = DB::table('debt_payments')->where('id', $id)->first();
            
            if (!$payment || $payment->payment_status !== 'pending') {
                return response()->json(['success' => false, 'message' => 'Data setoran tidak valid atau sudah diproses.'], 400);
            }

            // PERBAIKAN ENTERPRISE: Keamanan Setoran Lintas Cabang
            if ($user->role !== 'owner' && $payment->branch_id !== $user->branch_id) {
                return response()->json(['success' => false, 'message' => 'Akses ditolak: Setoran ini bukan wewenang cabang Anda.'], 403);
            }

            // PERBAIKAN ENTERPRISE: Validasi Akun Penerimaan Kas/Bank Setoran
            if ($user->role !== 'owner') {
                $isMapped = DB::table('branch_accounts')
                    ->where('branch_id', $payment->branch_id)
                    ->where('account_id', $request->account_id)
                    ->where('is_active', 1)
                    ->exists();

                if (!$isMapped) {
                    throw new \Exception("Akses ditolak: Akun Kas/Bank yang Anda pilih tidak terdaftar untuk cabang ini.");
                }
            }

            $sale = DB::table('sales')->where('id', $payment->sale_id)->first();

            // 1. UPDATE DATA PEMBAYARAN
            DB::table('debt_payments')->where('id', $id)->update([
                'account_id' => $request->account_id, 
                'payment_status' => 'completed',
                'updated_at' => Carbon::now()
            ]);

            // 2. PENJURNALAN AKUNTANSI VIA ACCOUNTING SERVICE
            $piutangAccountId = AccountingService::getAccountId('receivable_account');
            if (!$piutangAccountId) throw new \Exception("Akun Piutang Usaha belum di-mapping di Pengaturan Akuntansi.");

            AccountingService::log([
                'branch_id'   => $payment->branch_id,
                'entry_date'  => Carbon::today()->toDateString(),
                'description' => "Setoran Tagihan Sales: " . $sale->invoice_number . " (" . strtoupper($payment->payment_method) . ")",
                'reference'   => 'SETOR-AR-' . $payment->id,
                'source_type' => 'AR_PAYMENT_VERIFIED',
                'user_id'     => $user->id,
                'items'       => [
                    // DEBIT: Kas/Bank Tujuan
                    ['account_id' => $request->account_id, 'debit' => $payment->amount, 'credit' => 0],
                    // KREDIT: Piutang Pelanggan
                    ['account_id' => $piutangAccountId, 'debit' => 0, 'credit' => $payment->amount]
                ]
            ]);

            // 3. UPDATE STATUS NOTA PENJUALAN
            $this->updateSalePaymentStatus($sale->id);

            DB::commit();

            return response()->json([
                'success' => true, 
                'message' => 'Setoran berhasil diverifikasi. Uang divalidasi masuk ke Kas/Bank dan Jurnal Akuntansi telah dicetak.'
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error("Approve Setoran Error: " . $e->getMessage());
            return response()->json(['success' => false, 'message' => 'Gagal memverifikasi setoran: ' . $e->getMessage()], 500);
        }
    }

    /**
     * 8. REJECT SETORAN (TOLAK SETORAN SALES)
     */
    public function rejectSetoran(Request $request, $id)
    {
        $request->validate([
            'reject_reason' => 'required|string|min:5'
        ]);

        try {
            $user = auth()->user();
            $payment = DB::table('debt_payments')->where('id', $id)->first();
            
            if (!$payment || $payment->payment_status !== 'pending') {
                return response()->json(['success' => false, 'message' => 'Data setoran tidak valid atau sudah diproses.'], 400);
            }

            // PERBAIKAN ENTERPRISE: Keamanan Penolakan Lintas Cabang
            if ($user->role !== 'owner' && $payment->branch_id !== $user->branch_id) {
                return response()->json(['success' => false, 'message' => 'Akses ditolak: Setoran ini bukan wewenang cabang Anda.'], 403);
            }

            DB::table('debt_payments')->where('id', $id)->update([
                'payment_status' => 'cancelled',
                'note' => $payment->note . " | DITOLAK FINANCE: " . $request->reject_reason,
                'updated_at' => Carbon::now()
            ]);

            return response()->json([
                'success' => true, 
                'message' => 'Setoran ditolak. Tagihan dikembalikan ke antrean Piutang untuk ditagih ulang.'
            ]);

        } catch (\Exception $e) {
            Log::error("Reject Setoran Error: " . $e->getMessage());
            return response()->json(['success' => false, 'message' => 'Gagal menolak setoran: ' . $e->getMessage()], 500);
        }
    }
}