<?php

class CreditNoteController extends Controller
{
    public function index(Request $request): void
    {
        $this->view('credit-notes/index', [
            'title' => lang('adv_finance.credit_notes'),
            'breadcrumbs' => [['label' => lang('adv_finance.title'), 'url' => '/advanced-finance/installments'], ['label' => lang('adv_finance.credit_notes')]],
        ], 'app');
    }

    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'] ?? '';

        $where = '1=1';
        $params = [];
        if ($search) {
            $where .= ' AND (cn.credit_note_number LIKE ? OR m.full_name_en LIKE ? OR m.membership_number LIKE ?)';
            $like = "%{$search}%";
            $params = [$like,$like,$like];
        }

        $total = (int)$db->fetchColumn("SELECT COUNT(*) FROM credit_notes cn JOIN members m ON cn.member_id=m.id");
        $filtered = (int)$db->fetchColumn("SELECT COUNT(*) FROM credit_notes cn JOIN members m ON cn.member_id=m.id WHERE {$where}", $params);
        $rows = $db->fetchAll(
            "SELECT cn.*, m.full_name_en AS member_name, m.membership_number
             FROM credit_notes cn JOIN members m ON cn.member_id=m.id
             WHERE {$where} ORDER BY cn.id DESC LIMIT {$length} OFFSET {$start}",
            $params
        );

        $data = [];
        foreach ($rows as $r) {
            $data[] = [
                'id' => $r['id'],
                'credit_note_number' => $r['credit_note_number'],
                'member_name' => $r['member_name'],
                'credit_date' => format_date($r['credit_date']),
                'total_amount' => format_money($r['total_amount']),
                'applied_amount' => format_money($r['applied_amount']),
                'remaining_amount' => format_money($r['remaining_amount']),
                'status' => $r['status'],
                'status_badge' => status_badge($r['status']),
            ];
        }
        $this->json(['draw' => $draw, 'recordsTotal' => $total, 'recordsFiltered' => $filtered, 'data' => $data]);
    }

    public function create(Request $request): void
    {
        $currencies = $this->db()->fetchAll("SELECT * FROM sys_currencies WHERE is_active = 1");
        $this->view('credit-notes/create', [
            'title' => lang('adv_finance.create_credit_note'),
            'breadcrumbs' => [['label' => lang('adv_finance.credit_notes'), 'url' => '/advanced-finance/credit-notes'], ['label' => lang('common.create')]],
            'currencies' => $currencies,
        ], 'app');
    }

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

        $validator = new Validator($request->all(), [
            'member_id'         => 'required|integer|exists:members,id',
            'original_invoice_id' => 'nullable|integer',
            'total_amount'      => 'required|decimal|min:0.01',
            'reason'            => 'required|string|max:2000',
            'notes'             => 'nullable|string|max:2000',
        ]);

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

        $currency = $db->fetchOne("SELECT id FROM sys_currencies WHERE is_default = 1 LIMIT 1");

        $cnNumber = SequenceGenerator::next('credit_note_number');
        $id = $db->insert('credit_notes', [
            'credit_note_number' => $cnNumber,
            'member_id'          => $d['member_id'],
            'original_invoice_id'=> $d['original_invoice_id'] ?: null,
            'credit_date'        => date('Y-m-d'),
            'total_amount'       => $d['total_amount'],
            'applied_amount'     => 0,
            'remaining_amount'   => $d['total_amount'],
            'currency_id'        => $currency['id'] ?? 1,
            'reason'             => $d['reason'],
            'status'             => 'draft',
            'notes'              => $d['notes'] ?? null,
            'created_by'         => Auth::id(),
        ]);

        // Add a single item for the full amount
        $db->insert('credit_note_items', [
            'credit_note_id'  => $id,
            'description_en'  => $d['reason'],
            'amount'          => $d['total_amount'],
            'original_invoice_item_id' => null,
        ]);

        $this->audit('create', 'credit_notes', $id, 'Created credit note ' . $cnNumber);
        $this->json(['success' => true, 'message' => lang('adv_finance.saved'), 'redirect' => '/advanced-finance/credit-notes/' . $id]);
    }

    public function show(Request $request): void
    {
        $id = (int)$request->routeParam('id');
        $db = $this->db();
        $cn = $db->fetchOne(
            "SELECT cn.*, m.full_name_en AS member_name, m.membership_number,
                    i.invoice_number AS original_invoice_number
             FROM credit_notes cn
             JOIN members m ON cn.member_id = m.id
             LEFT JOIN invoices i ON cn.original_invoice_id = i.id
             WHERE cn.id = ?",
            [$id]
        );
        if (!$cn) { $this->abort(404, 'Not found'); return; }

        $items = $db->fetchAll("SELECT * FROM credit_note_items WHERE credit_note_id = ?", [$id]);
        $outstandingInvoices = $db->fetchAll(
            "SELECT id, invoice_number, balance_due FROM invoices WHERE member_id = ? AND status IN ('issued','partially_paid','overdue') AND balance_due > 0 AND is_deleted = 0",
            [$cn['member_id']]
        );

        $this->view('credit-notes/show', [
            'title' => $cn['credit_note_number'],
            'breadcrumbs' => [['label' => lang('adv_finance.credit_notes'), 'url' => '/advanced-finance/credit-notes'], ['label' => $cn['credit_note_number']]],
            'cn' => $cn,
            'items' => $items,
            'outstandingInvoices' => $outstandingInvoices,
        ], 'app');
    }

    public function issue(Request $request): void
    {
        if (!CSRF::validate($request->csrfToken())) { $this->json(['success' => false, 'message' => 'Invalid CSRF'], 403); return; }
        $id = (int)$request->routeParam('id');
        $db = $this->db();
        $cn = $db->fetchOne("SELECT * FROM credit_notes WHERE id = ? AND status = 'draft'", [$id]);
        if (!$cn) { $this->json(['success' => false, 'message' => 'Cannot issue — not in draft'], 422); return; }

        $db->update('credit_notes', ['status' => 'issued', 'approved_by' => Auth::id(), 'approved_at' => date('Y-m-d H:i:s')], 'id = ?', [$id]);
        $this->audit('update', 'credit_notes', $id, 'Issued credit note');
        $this->json(['success' => true, 'message' => lang('adv_finance.status_updated'), 'redirect' => '/advanced-finance/credit-notes/' . $id]);
    }

    public function apply(Request $request): void
    {
        if (!CSRF::validate($request->csrfToken())) { $this->json(['success' => false, 'message' => 'Invalid CSRF'], 403); return; }
        $id = (int)$request->routeParam('id');
        $invoiceId = (int)$request->post('invoice_id', 0);
        $applyAmount = (float)$request->post('apply_amount', 0);

        $db = $this->db();
        $cn = $db->fetchOne("SELECT * FROM credit_notes WHERE id = ? AND status IN ('issued','partially_applied')", [$id]);
        if (!$cn) { $this->json(['success' => false, 'message' => 'Credit note not available for application'], 422); return; }

        if ($applyAmount <= 0 || $applyAmount > $cn['remaining_amount']) {
            $this->json(['success' => false, 'message' => 'Invalid amount. Remaining: ' . format_money($cn['remaining_amount'])], 422);
            return;
        }

        $invoice = $db->fetchOne("SELECT * FROM invoices WHERE id = ? AND is_deleted = 0", [$invoiceId]);
        if (!$invoice || $invoice['balance_due'] <= 0) {
            $this->json(['success' => false, 'message' => 'Invoice not found or fully paid'], 422);
            return;
        }

        $actualApply = min($applyAmount, (float)$invoice['balance_due']);

        try {
            $db->beginTransaction();

            // Update invoice
            $db->update('invoices', [
                'paid_amount' => $invoice['paid_amount'] + $actualApply,
                'updated_at' => date('Y-m-d H:i:s'),
            ], 'id = ?', [$invoiceId]);

            // Update credit note
            $newApplied = $cn['applied_amount'] + $actualApply;
            $newRemaining = $cn['total_amount'] - $newApplied;
            $newStatus = $newRemaining <= 0.001 ? 'fully_applied' : 'partially_applied';

            $db->update('credit_notes', [
                'applied_amount'   => $newApplied,
                'remaining_amount' => max(0, $newRemaining),
                'status'           => $newStatus,
                'updated_at'       => date('Y-m-d H:i:s'),
            ], 'id = ?', [$id]);

            // Update member balance
            $db->execute("CALL sp_recalculate_member_balance(?)", [$cn['member_id']]);

            $db->commit();
            $this->audit('update', 'credit_notes', $id, "Applied " . format_money($actualApply) . " to invoice #{$invoice['invoice_number']}");
            $this->json(['success' => true, 'message' => lang('adv_finance.applied_success'), 'redirect' => '/advanced-finance/credit-notes/' . $id]);
        } catch (\Exception $e) {
            $db->rollBack();
            Logger::error('Credit note application failed: ' . $e->getMessage());
            $this->json(['success' => false, 'message' => 'Application failed'], 500);
        }
    }
}