<?php
declare(strict_types=1);

use App\Core\Registries\MenuRegistry;
use App\Core\Registries\PermissionRegistry;
use App\Core\EventBus;
use App\Modules\Accounting\Services\AccountingIntegrationService;
use App\Modules\Accounting\Services\StatementIntegrationService;
use App\Modules\Accounting\Services\DailyCashMovementService;

// ────────────────────────────────────────────────────────────
// Accounting Module — Permissions (28 total)
// ────────────────────────────────────────────────────────────

PermissionRegistry::register('accounting', [
    // Dashboard & Reports
    'accounting.reports.view'              => ['ar' => 'لوحة تحكم المحاسبة',            'en' => 'Accounting Dashboard'],
    'accounting.reports.trial_balance'     => ['ar' => 'ميزان المراجعة',                'en' => 'Trial Balance'],
    'accounting.reports.general_ledger'    => ['ar' => 'دفتر الأستاذ العام',            'en' => 'General Ledger'],
    'accounting.reports.income_statement'  => ['ar' => 'قائمة الدخل',                   'en' => 'Income Statement'],
    'accounting.reports.balance_sheet'     => ['ar' => 'الميزانية العمومية',             'en' => 'Balance Sheet'],
    'accounting.reports.consolidated'      => ['ar' => 'ميزانية موحدة',                 'en' => 'Consolidated Balance Sheet'],
    'accounting.reports.ar'                => ['ar' => 'تقرير المدينين',                'en' => 'Accounts Receivable Report'],
    'accounting.reports.ap'                => ['ar' => 'تقرير الدائنين',                'en' => 'Accounts Payable Report'],
    'accounting.reports.member_statement'  => ['ar' => 'كشف حساب عضو',                 'en' => 'Member Statement'],
    'accounting.reports.treasury'          => ['ar' => 'تقرير الخزينة والمدفوعات',      'en' => 'Treasury & Payments Report'],
    'accounting.reports.revenue_analysis'  => ['ar' => 'تحليل الإيرادات',               'en' => 'Revenue Analysis'],

    // Fiscal Year
    'accounting.fiscal_year.view'          => ['ar' => 'عرض السنوات المالية',            'en' => 'View Fiscal Years'],
    'accounting.fiscal_year.manage'        => ['ar' => 'إدارة السنوات المالية',           'en' => 'Manage Fiscal Years'],
    'accounting.fiscal_year.close'         => ['ar' => 'إقفال السنة المالية',            'en' => 'Close Fiscal Year'],

    // Chart of Accounts
    'accounting.coa.view'                  => ['ar' => 'عرض دليل الحسابات',              'en' => 'View Chart of Accounts'],
    'accounting.coa.manage'                => ['ar' => 'إدارة دليل الحسابات',             'en' => 'Manage Chart of Accounts'],

    // Journal Types
    'accounting.journal_type.view'         => ['ar' => 'عرض أنواع اليومية',              'en' => 'View Journal Types'],
    'accounting.journal_type.manage'       => ['ar' => 'إدارة أنواع اليومية',             'en' => 'Manage Journal Types'],

    // Cost Centers
    'accounting.cost_center.view'          => ['ar' => 'عرض مراكز التكلفة',              'en' => 'View Cost Centers'],
    'accounting.cost_center.manage'        => ['ar' => 'إدارة مراكز التكلفة',             'en' => 'Manage Cost Centers'],

    // Budgets
    'accounting.budget.view'               => ['ar' => 'عرض الموازنات التقديرية',         'en' => 'View Budgets'],
    'accounting.budget.manage'             => ['ar' => 'إدارة الموازنات التقديرية',        'en' => 'Manage Budgets'],

    // Bank Accounts
    'accounting.bank_account.view'         => ['ar' => 'عرض الحسابات البنكية',           'en' => 'View Bank Accounts'],
    'accounting.bank_account.manage'       => ['ar' => 'إدارة الحسابات البنكية',          'en' => 'Manage Bank Accounts'],

    // Negotiable Instruments
    'accounting.instruments.view'          => ['ar' => 'عرض الأوراق التجارية',           'en' => 'View Negotiable Instruments'],
    'accounting.instruments.manage'        => ['ar' => 'إدارة الأوراق التجارية',          'en' => 'Manage Negotiable Instruments'],

    // Journal Entries
    'accounting.journal.view'              => ['ar' => 'عرض قيود اليومية',               'en' => 'View Journal Entries'],
    'accounting.journal.create'            => ['ar' => 'إنشاء قيد يومية',                'en' => 'Create Journal Entry'],
    'accounting.journal.post'              => ['ar' => 'ترحيل قيود اليومية',             'en' => 'Post Journal Entries'],
    'accounting.journal.reverse'           => ['ar' => 'عكس قيود اليومية',               'en' => 'Reverse Journal Entries'],

    // Accounting Dimensions
    'accounting.dimensions.view'           => ['ar' => 'عرض الأبعاد المحاسبية',          'en' => 'View Accounting Dimensions'],
    'accounting.dimensions.manage'         => ['ar' => 'إدارة الأبعاد المحاسبية',         'en' => 'Manage Accounting Dimensions'],

    // Bank Reconciliation
    'accounting.bank_recon.view'           => ['ar' => 'عرض المطابقات البنكية',          'en' => 'View Bank Reconciliations'],
    'accounting.bank_recon.manage'         => ['ar' => 'إدارة المطابقات البنكية',         'en' => 'Manage Bank Reconciliations'],

    // Daily Transactions
    'accounting.daily_tx.view'             => ['ar' => 'عرض الحركات اليومية',            'en' => 'View Daily Transactions'],
    'accounting.daily_tx.manage'           => ['ar' => 'إدارة الحركات اليومية',           'en' => 'Manage Daily Transactions'],

    // Opening Entries & History
    'accounting.opening_entry.view'        => ['ar' => 'عرض القيود الافتتاحية',          'en' => 'View Opening Entries'],
    'accounting.opening_entry.manage'      => ['ar' => 'إدارة القيود الافتتاحية',         'en' => 'Manage Opening Entries'],

    // Period Closing
    'accounting.period.view'               => ['ar' => 'عرض إقفال الفترات',              'en' => 'View Period Closings'],
    'accounting.period.close'              => ['ar' => 'إقفال فترة',                     'en' => 'Close Period'],
    'accounting.period.reopen'             => ['ar' => 'إعادة فتح فترة مغلقة',           'en' => 'Reopen Closed Period'],

    // Account Statements
    'accounting.statements.view'           => ['ar' => 'كشوف حسابات العملاء والموردين',   'en' => 'Account Statements'],
    'accounting.cash.view'                 => ['ar' => 'حركة النقدية اليومية',            'en' => 'Daily Cash Movements'],

    // Bank Loans
    'accounting.loans.view'                => ['ar' => 'عرض القروض البنكية',              'en' => 'View Bank Loans'],
    'accounting.loans.manage'              => ['ar' => 'إدارة القروض البنكية',             'en' => 'Manage Bank Loans'],

    // Cross-Entity Settlements
    'accounting.settlements.view'          => ['ar' => 'عرض التسويات',                   'en' => 'View Settlements'],
    'accounting.settlements.manage'        => ['ar' => 'إنشاء تسويات',                   'en' => 'Create Settlements'],
    'accounting.settlements.approve'       => ['ar' => 'اعتماد التسويات',                 'en' => 'Approve Settlements'],

    // Documentary Credits
    'accounting.lc.view'                   => ['ar' => 'عرض الاعتمادات المستندية',        'en' => 'View Documentary Credits'],
    'accounting.lc.manage'                 => ['ar' => 'إدارة الاعتمادات المستندية',       'en' => 'Manage Documentary Credits'],

    // Letters of Guarantee
    'accounting.guarantee.view'            => ['ar' => 'عرض خطابات الضمان',              'en' => 'View Letters of Guarantee'],
    'accounting.guarantee.manage'          => ['ar' => 'إدارة خطابات الضمان',             'en' => 'Manage Letters of Guarantee'],
]);

// ────────────────────────────────────────────────────────────
// Accounting Module — Sidebar Menu
// ────────────────────────────────────────────────────────────

MenuRegistry::register('accounting', [
    'label_ar'   => 'المحاسبة والدفتر العام',
    'label_en'   => 'Accounting & GL',
    'icon'       => 'calculator',
    'route'      => '/accounting',
    'permission' => 'accounting.reports.view',
    'parent'     => null,
    'order'      => 400,
    'children'   => [
        ['label_ar' => 'لوحة التحكم',           'label_en' => 'Dashboard',              'route' => '/accounting',                                    'permission' => 'accounting.reports.view',            'order' => 1],
        ['label_ar' => 'دليل الحسابات',          'label_en' => 'Chart of Accounts',      'route' => '/accounting/chart-of-accounts',                  'permission' => 'accounting.coa.view',                'order' => 2],
        ['label_ar' => 'قيود اليومية',           'label_en' => 'Journal Entries',        'route' => '/accounting/journal-entries',                     'permission' => 'accounting.journal.view',            'order' => 3],
        ['label_ar' => 'أنواع اليومية',          'label_en' => 'Journal Types',          'route' => '/accounting/journal-types',                      'permission' => 'accounting.journal_type.view',       'order' => 4],
        ['label_ar' => 'السنوات المالية',         'label_en' => 'Fiscal Years',           'route' => '/accounting/fiscal-years',                       'permission' => 'accounting.fiscal_year.view',        'order' => 5],
        ['label_ar' => 'مراكز التكلفة',          'label_en' => 'Cost Centers',           'route' => '/accounting/cost-centers',                       'permission' => 'accounting.cost_center.view',        'order' => 5],
        ['label_ar' => 'الموازنات التقديرية',     'label_en' => 'Budgets',                'route' => '/accounting/budgets',                            'permission' => 'accounting.budget.view',             'order' => 6],
        ['label_ar' => 'الحسابات البنكية',       'label_en' => 'Bank Accounts',          'route' => '/accounting/bank-accounts',                      'permission' => 'accounting.bank_account.view',       'order' => 7],
        ['label_ar' => 'الأوراق التجارية',       'label_en' => 'Instruments',            'route' => '/accounting/instruments',                        'permission' => 'accounting.instruments.view',        'order' => 8],
        ['label_ar' => 'الأبعاد المحاسبية',      'label_en' => 'Dimensions',             'route' => '/accounting/dimensions',                         'permission' => 'accounting.dimensions.view',         'order' => 9],
        ['label_ar' => 'المطابقة البنكية',       'label_en' => 'Bank Reconciliation',    'route' => '/accounting/bank-reconciliation',                'permission' => 'accounting.bank_recon.view',         'order' => 10],
        ['label_ar' => 'الحركات اليومية',         'label_en' => 'Daily Transactions',     'route' => '/accounting/daily-transactions',                 'permission' => 'accounting.daily_tx.view',           'order' => 11],
        ['label_ar' => 'القيود الافتتاحية',       'label_en' => 'Opening Entries',        'route' => '/accounting/opening-entries',                    'permission' => 'accounting.opening_entry.view',      'order' => 12],
        ['label_ar' => 'إقفال الفترات',          'label_en' => 'Period Closing',         'route' => '/accounting/period-closing',                     'permission' => 'accounting.period.view',             'order' => 12],
        ['label_ar' => 'ميزان المراجعة',         'label_en' => 'Trial Balance',          'route' => '/accounting/reports/trial-balance',              'permission' => 'accounting.reports.trial_balance',   'order' => 9],
        ['label_ar' => 'دفتر الأستاذ',           'label_en' => 'General Ledger',         'route' => '/accounting/reports/general-ledger',             'permission' => 'accounting.reports.general_ledger',  'order' => 10],
        ['label_ar' => 'قائمة الدخل',            'label_en' => 'Income Statement',       'route' => '/accounting/reports/income-statement',           'permission' => 'accounting.reports.income_statement','order' => 11],
        ['label_ar' => 'الميزانية العمومية',      'label_en' => 'Balance Sheet',          'route' => '/accounting/reports/balance-sheet',              'permission' => 'accounting.reports.balance_sheet',   'order' => 12],
        ['label_ar' => 'ميزانية موحدة',          'label_en' => 'Consolidated BS',        'route' => '/accounting/reports/consolidated-balance-sheet', 'permission' => 'accounting.reports.consolidated',    'order' => 13],
        ['label_ar' => 'المدينون (AR)',           'label_en' => 'Accounts Receivable',    'route' => '/accounting/reports/accounts-receivable',        'permission' => 'accounting.reports.ar',              'order' => 14],
        ['label_ar' => 'الدائنون (AP)',           'label_en' => 'Accounts Payable',       'route' => '/accounting/reports/accounts-payable',           'permission' => 'accounting.reports.ap',              'order' => 15],
        ['label_ar' => 'كشف حساب عضو',           'label_en' => 'Member Statement',       'route' => '/accounting/reports/member-statement',           'permission' => 'accounting.reports.member_statement','order' => 16],
        ['label_ar' => 'الخزينة والمدفوعات',     'label_en' => 'Treasury & Payments',    'route' => '/accounting/reports/treasury',                    'permission' => 'accounting.reports.treasury',        'order' => 17],
        ['label_ar' => 'تحليل الإيرادات',        'label_en' => 'Revenue Analysis',       'route' => '/accounting/reports/revenue-analysis',            'permission' => 'accounting.reports.revenue_analysis','order' => 18],
        ['label_ar' => 'كشف حساب عميل',          'label_en' => 'Customer Statement',     'route' => '/accounting/statements/customer',                 'permission' => 'accounting.statements.view',         'order' => 19],
        ['label_ar' => 'كشف حساب مورد',          'label_en' => 'Supplier Statement',     'route' => '/accounting/statements/supplier',                 'permission' => 'accounting.statements.view',         'order' => 20],
        ['label_ar' => 'حركة النقدية اليومية',    'label_en' => 'Daily Cash',             'route' => '/accounting/statements/daily-cash',               'permission' => 'accounting.cash.view',               'order' => 21],
        ['label_ar' => 'القروض البنكية',          'label_en' => 'Bank Loans',             'route' => '/accounting/loans',                               'permission' => 'accounting.loans.view',              'order' => 22],
        ['label_ar' => 'التسويات',               'label_en' => 'Settlements',            'route' => '/accounting/settlements',                          'permission' => 'accounting.settlements.view',        'order' => 23],
        ['label_ar' => 'الاعتمادات المستندية',    'label_en' => 'Documentary Credits',    'route' => '/accounting/documentary-credits',                  'permission' => 'accounting.lc.view',                 'order' => 24],
        ['label_ar' => 'خطابات الضمان',          'label_en' => 'Guarantees',             'route' => '/accounting/guarantees',                           'permission' => 'accounting.guarantee.view',          'order' => 25],
    ],
]);

// ────────────────────────────────────────────────────────────
// Accounting Module — Auto-Create Fiscal Year
// ────────────────────────────────────────────────────────────
// Without an open fiscal year, ALL auto-posted journal entries silently fail.
// This ensures a fiscal year always exists for the current calendar year.
(function (): void {
    try {
        $db = \App\Core\App::getInstance()->db();
        $year = (int) date('Y');
        $startDate = $year . '-01-01';
        $endDate = $year . '-12-31';
        $existing = $db->selectOne(
            "SELECT id FROM fiscal_years WHERE start_date <= ? AND end_date >= ? AND is_archived = 0",
            [$startDate, $endDate]
        );
        if (!$existing) {
            $db->insert('fiscal_years', [
                'name_ar'     => 'السنة المالية ' . $year,
                'name_en'     => 'Fiscal Year ' . $year,
                'start_date'  => $startDate,
                'end_date'    => $endDate,
                'status'      => 'open',
                'is_current'  => 1,
                'is_archived' => 0,
                'created_at'  => date('Y-m-d H:i:s'),
                'updated_at'  => date('Y-m-d H:i:s'),
            ]);
        }
    } catch (\Throwable $e) {
        // Silently ignore — table might not exist yet during initial migration
    }
})();

// ────────────────────────────────────────────────────────────
// Accounting Module — Event Listeners (Auto-Posting)
// ────────────────────────────────────────────────────────────

// ── Payments ─────────────────────────────────────────────────
// When a payment is completed, auto-post journal entry: Dr. Cash/Bank, Cr. Revenue
EventBus::listen('payment.completed', function (array $data): void {
    try {
        AccountingIntegrationService::onPaymentCompleted($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (payment.completed): ' . $e->getMessage());
    }
}, 50); // Priority 50 — runs after Payments module's own listener (100)

// When a payment is voided, reverse the journal entry
EventBus::listen('payment.voided', function (array $data): void {
    try {
        AccountingIntegrationService::onPaymentVoided($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-reverse failed (payment.voided): ' . $e->getMessage());
    }
}, 50);

// ── Sales ────────────────────────────────────────────────────
// When a sale is completed, auto-post COGS entry
EventBus::listen('sale.completed', function (array $data): void {
    try {
        AccountingIntegrationService::onSaleCompleted($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (sale.completed): ' . $e->getMessage());
    }
}, 50);

// When a sale is voided, reverse COGS entry
EventBus::listen('sale.voided', function (array $data): void {
    try {
        AccountingIntegrationService::onSaleVoided($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-reverse failed (sale.voided): ' . $e->getMessage());
    }
}, 50);

// ── HR Payroll ───────────────────────────────────────────────
// When payroll is paid, auto-post salary journal
EventBus::listen('hr.payroll.paid', function (array $data): void {
    try {
        AccountingIntegrationService::onPayrollPaid($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (hr.payroll.paid): ' . $e->getMessage());
    }
}, 50);

// ── Subscriptions ────────────────────────────────────────────
// When a subscription is paid, update AR
EventBus::listen('subscription.paid', function (array $data): void {
    try {
        AccountingIntegrationService::onSubscriptionPaid($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (subscription.paid): ' . $e->getMessage());
    }
}, 50);

// ── Fines ────────────────────────────────────────────────────
// When a fine is imposed, create AR entry and journal
EventBus::listen('fine.imposed', function (array $data): void {
    try {
        AccountingIntegrationService::onFineImposed($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (fine.imposed): ' . $e->getMessage());
    }
}, 50);

// When a fine is collected, update AR
EventBus::listen('fine.paid', function (array $data): void {
    try {
        AccountingIntegrationService::onFineCollected($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (fine.paid): ' . $e->getMessage());
    }
}, 50);

// ── Installments ─────────────────────────────────────────────
// When an installment plan is created, create AR entry
EventBus::listen('installment.plan_created', function (array $data): void {
    try {
        AccountingIntegrationService::onInstallmentPlanCreated($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (installment.plan_created): ' . $e->getMessage());
    }
}, 50);

// When an installment is paid, update AR
EventBus::listen('installment.paid', function (array $data): void {
    try {
        AccountingIntegrationService::onInstallmentPaid($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (installment.paid): ' . $e->getMessage());
    }
}, 50);

// ── Refunds ─────────────────────────────────────────────────
// When a sale is refunded, post reversal GL entry
EventBus::listen('sale.refunded', function (array $data): void {
    try {
        AccountingIntegrationService::onSaleRefunded($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (sale.refunded): ' . $e->getMessage());
    }
}, 50);

// ── Procurement ─────────────────────────────────────────────
// When a vendor invoice is approved, post AP accrual
EventBus::listen('procurement.invoice_approved', function (array $data): void {
    try {
        AccountingIntegrationService::onVendorInvoiceApproved($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (procurement.invoice_approved): ' . $e->getMessage());
    }
}, 50);

// When a vendor payment is completed, post AP reduction
EventBus::listen('procurement.payment_completed', function (array $data): void {
    try {
        AccountingIntegrationService::onVendorPaymentCompleted($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (procurement.payment_completed): ' . $e->getMessage());
    }
}, 50);

// When a vendor payment is voided, reverse the journal entry
EventBus::listen('procurement.payment_voided', function (array $data): void {
    try {
        AccountingIntegrationService::onVendorPaymentVoided($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-reverse failed (procurement.payment_voided): ' . $e->getMessage());
    }
}, 50);

// When a return-to-vendor is completed, post AP debit / inventory credit
EventBus::listen('procurement.rtv_completed', function (array $data): void {
    try {
        AccountingIntegrationService::onReturnToVendorCompleted($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (procurement.rtv_completed): ' . $e->getMessage());
    }
}, 50);

// ── Rentals ─────────────────────────────────────────────────
// When a rental deposit is collected, record deposit liability
EventBus::listen('rental.deposit_collected', function (array $data): void {
    try {
        AccountingIntegrationService::onRentalDepositCollected($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (rental.deposit_collected): ' . $e->getMessage());
    }
}, 50);

// When a rental deposit is refunded, reverse deposit liability
EventBus::listen('rental.deposit_refunded', function (array $data): void {
    try {
        AccountingIntegrationService::onRentalDepositRefunded($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (rental.deposit_refunded): ' . $e->getMessage());
    }
}, 50);

// ── Facility Entry ──────────────────────────────────────────
// When a facility entry payment is recorded (pool/gym access)
EventBus::listen('facility.entry_recorded', function (array $data): void {
    try {
        AccountingIntegrationService::onFacilityEntry($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (facility.entry_recorded): ' . $e->getMessage());
    }
}, 50);

// ── Carnet Guest Entry ──────────────────────────────────────
// When a carnet guest entry is recorded (invitation book usage)
EventBus::listen('carnet.guest_entry_recorded', function (array $data): void {
    try {
        AccountingIntegrationService::onGuestEntry($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (carnet.guest_entry_recorded): ' . $e->getMessage());
    }
}, 50);

// ── Tournament Fees ─────────────────────────────────────────
// When a tournament registration fee is collected
EventBus::listen('tournament.fee_collected', function (array $data): void {
    try {
        AccountingIntegrationService::onTournamentFee($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (tournament.fee_collected): ' . $e->getMessage());
    }
}, 50);

// ── Membership Transfers & Waivers ─────────────────────────
// When a transfer/separation is completed, post AR write-off if fee was pre-collected
EventBus::listen('transfer.completed', function (array $data): void {
    try {
        AccountingIntegrationService::onTransferCompleted($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (transfer.completed): ' . $e->getMessage());
    }
}, 50);

// When a waiver is completed, post AR write-off
EventBus::listen('waiver.completed', function (array $data): void {
    try {
        AccountingIntegrationService::onWaiverCompleted($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (waiver.completed): ' . $e->getMessage());
    }
}, 50);

// When a member is dropped (5-year unpaid / installment default), write off AR
EventBus::listen('member.dropped', function (array $data): void {
    try {
        AccountingIntegrationService::onMemberDropped($data);
    } catch (\Throwable $e) {
        \App\Core\Logger::error('Accounting auto-post failed (member.dropped): ' . $e->getMessage());
    }
}, 50);

// ── Statement Integration ───────────────────────────────────
// Auto-records customer/supplier transactions for account statements and credit limits
StatementIntegrationService::registerListeners();

// ── Daily Cash Movement Tracking ────────────────────────────
// Auto-records daily cash inflows/outflows for treasury dashboard
DailyCashMovementService::registerListeners();
