<?php
class PaymentController extends Controller
{
    public function index(Request $request): void
    {
        $db = $this->db();
        $methods = $db->fetchAll("SELECT id, name_en FROM payment_methods WHERE is_active=1 ORDER BY sort_order");

        $this->view('payments/index', [
            'title' => lang('finance.payments'),
            'breadcrumbs' => [
                ['label' => lang('finance.title'), 'url' => '/finance/invoices'],
                ['label' => lang('finance.payments')],
            ],
            'methods' => $methods,
        ]);
    }

    public function datatable(Request $request): void
    {
        $db = $this->db();
        $draw   = (int)$request->get('draw', 1);
        $start  = (int)$request->get('start', 0);
        $length = (int)$request->get('length', 25);
        $search = $request->get('search')['value'] ?? '';

        $filterMethod = $request->get('filter_method', '');
        $filterStatus = $request->get('filter_status', '');
        $filterFrom   = $request->get('filter_from', '');
        $filterTo     = $request->get('filter_to', '');

        $where = "p.is_deleted=0";
        $params = [];

        if ($filterMethod) { $where .= " AND p.payment_method_id=?"; $params[] = (int)$filterMethod; }
        if ($filterStatus) { $where .= " AND p.status=?"; $params[] = $filterStatus; }
        if ($filterFrom)   { $where .= " AND p.payment_date >= ?"; $params[] = $filterFrom; }
        if ($filterTo)     { $where .= " AND p.payment_date <= ?"; $params[] = $filterTo; }
        if ($search) {
            $where .= " AND (p.payment_number LIKE ? OR m.full_name_en LIKE ? OR m.membership_number LIKE ?)";
            $s = "%{$search}%";
            $params = array_merge($params, [$s, $s, $s]);
        }

        $totalRecords = (int)$db->fetchColumn("SELECT COUNT(*) FROM payments p WHERE p.is_deleted=0");
        $filteredCount = (int)$db->fetchColumn(
            "SELECT COUNT(*) FROM payments p LEFT JOIN members m ON p.member_id=m.id WHERE {$where}", $params
        );

        $orderDir = strtoupper($request->get('order')[0]['dir'] ?? 'DESC') === 'ASC' ? 'ASC' : 'DESC';

        $rows = $db->fetchAll(
            "SELECT p.id, p.payment_number, p.amount, p.payment_date, p.status,
                    m.full_name_en AS member_name, m.membership_number,
                    pm.name_en AS method_name
             FROM payments p
             LEFT JOIN members m ON p.member_id=m.id
             LEFT JOIN payment_methods pm ON p.payment_method_id=pm.id
             WHERE {$where}
             ORDER BY p.id {$orderDir}
             LIMIT {$length} OFFSET {$start}",
            $params
        );

        $data = [];
        foreach ($rows as $row) {
            $actions = '<a href="/finance/payments/'.$row['id'].'" class="btn btn-sm btn-outline-primary"><i class="fas fa-eye"></i></a>';
            $data[] = [
                'id'             => $row['id'],
                'payment_number' => e($row['payment_number']),
                'member_name'    => e($row['member_name'] ?? '') . ' <small class="text-muted">'.e($row['membership_number'] ?? '').'</small>',
                'amount'         => money($row['amount']),
                'method_name'    => e($row['method_name'] ?? ''),
                'payment_date'   => format_date($row['payment_date']),
                'status'         => status_badge($row['status']),
                'actions'        => $actions,
            ];
        }

        $this->json([
            'draw'            => $draw,
            'recordsTotal'    => $totalRecords,
            'recordsFiltered' => $filteredCount,
            'data'            => $data,
        ]);
    }

    public function create(Request $request): void
    {
        $db = $this->db();
        $methods = $db->fetchAll("SELECT id, name_en, method_type, requires_reference FROM payment_methods WHERE is_active=1 ORDER BY sort_order");
        $registers = $db->fetchAll("SELECT cr.id, cr.name_en, crs.id AS session_id FROM cash_registers cr LEFT JOIN cash_register_sessions crs ON cr.id=crs.register_id AND crs.status='open' WHERE cr.is_active=1");

        // Pre-populate member if passed
        $memberId = (int)$request->get('member_id', 0);
        $member = null;
        if ($memberId) {
            $member = $db->fetchOne("SELECT id, membership_number, full_name_en, outstanding_balance FROM members WHERE id=? AND is_deleted=0", [$memberId]);
        }

        $invoiceId = (int)$request->get('invoice_id', 0);
        $invoice = null;
        if ($invoiceId) {
            $invoice = $db->fetchOne("SELECT id, invoice_number, balance_due, member_id FROM invoices WHERE id=? AND is_deleted=0", [$invoiceId]);
        }

        $this->view('payments/create', [
            'title' => lang('finance.record_payment'),
            'breadcrumbs' => [
                ['label' => lang('finance.title'), 'url' => '/finance/invoices'],
                ['label' => lang('finance.payments'), 'url' => '/finance/payments'],
                ['label' => lang('finance.record_payment')],
            ],
            'methods'   => $methods,
            'registers' => $registers,
            'member'    => $member,
            'invoice'   => $invoice,
        ]);
    }

    public function store(Request $request): void
    {
        if (!CSRF::validate($request->csrfToken())) {
            $this->json(['success' => false, 'message' => 'Invalid security token'], 403);
            return;
        }

        $validator = new Validator($request->all(), [
            'member_id'         => 'required|integer|exists:members,id',
            'payment_method_id' => 'required|integer|exists:payment_methods,id',
            'amount'            => 'required|decimal|min:0.01',
            'payment_date'      => 'required|date',
            'reference_number'  => 'nullable|string|max:100',
            'invoice_id'        => 'nullable|integer',
        ]);

        if ($validator->fails()) {
            $this->json(['success' => false, 'errors' => $validator->errors()], 422);
            return;
        }

        $db = $this->db();
        $db->beginTransaction();

        try {
            $memberId   = (int)$request->post('member_id');
            $methodId   = (int)$request->post('payment_method_id');
            $amount     = round((float)$request->post('amount'), 4);
            $payDate    = $request->post('payment_date');
            $refNum     = $request->post('reference_number', '');
            $invoiceId  = (int)$request->post('invoice_id', 0) ?: null;
            $sessionId  = (int)$request->post('cash_register_session_id', 0) ?: null;

            $db->execute("CALL sp_record_payment(?, ?, ?, ?, ?, ?, ?, ?, @pay_id, @pay_num, @pay_result)", [
                $memberId, $methodId, $amount, $payDate, $refNum, $invoiceId, Auth::id(), $sessionId
            ]);

            $result = $db->fetchOne("SELECT @pay_id AS payment_id, @pay_num AS payment_number, @pay_result AS msg");
            $paymentId = (int)$result['payment_id'];
            $paymentNumber = $result['payment_number'];

            if (!$paymentId) {
                throw new \RuntimeException($result['msg'] ?? 'Payment failed');
            }

            // Generate receipt
            $db->execute("CALL sp_generate_receipt(?, ?, @rcpt_id, @rcpt_num)", [$paymentId, Auth::id()]);
            $rcpt = $db->fetchOne("SELECT @rcpt_id AS receipt_id, @rcpt_num AS receipt_number");

            $db->commit();

            AuditLog::log('create', 'finance', 'payment', $paymentId, "Recorded payment {$paymentNumber} for " . money_format($amount));

            $this->json([
                'success'   => true,
                'message'   => lang('finance.payment_recorded') . ($rcpt['receipt_number'] ? ' | ' . lang('finance.receipt') . ': ' . $rcpt['receipt_number'] : ''),
                'redirect'  => '/finance/payments/' . $paymentId,
                'receipt_id' => $rcpt['receipt_id'] ?? null,
            ]);

        } catch (\Exception $e) {
            $db->rollBack();
            Logger::error('Payment recording failed: ' . $e->getMessage());
            $this->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function show(Request $request): void
    {
        $id = (int)$request->routeParam('id');
        $db = $this->db();

        $payment = $db->fetchOne(
            "SELECT p.*, m.full_name_en AS member_name, m.membership_number,
                    pm.name_en AS method_name, pm.method_type,
                    c.symbol AS currency_symbol
             FROM payments p
             LEFT JOIN members m ON p.member_id=m.id
             LEFT JOIN payment_methods pm ON p.payment_method_id=pm.id
             LEFT JOIN sys_currencies c ON p.currency_id=c.id
             WHERE p.id=? AND p.is_deleted=0", [$id]
        );

        if (!$payment) {
            $this->abort(404, 'Payment not found');
            return;
        }

        $allocations = $db->fetchAll(
            "SELECT pa.allocated_amount, i.invoice_number, i.total_amount, i.balance_due
             FROM payment_allocations pa
             JOIN invoices i ON pa.invoice_id=i.id
             WHERE pa.payment_id=? AND pa.is_reversed=0", [$id]
        );

        $receipt = $db->fetchOne("SELECT id, receipt_number FROM receipts WHERE payment_id=? AND status='issued'", [$id]);

        $this->view('payments/show', [
            'title' => lang('finance.payment') . ' #' . $payment['payment_number'],
            'breadcrumbs' => [
                ['label' => lang('finance.title'), 'url' => '/finance/invoices'],
                ['label' => lang('finance.payments'), 'url' => '/finance/payments'],
                ['label' => '#' . $payment['payment_number']],
            ],
            'payment'     => $payment,
            'allocations' => $allocations,
            'receipt'     => $receipt,
        ]);
    }
}