<?php
/**
 * سودانا — FinancialAgent v1
 * SECTION 7: Financial Agent
 * Verifies ledger, detects mismatch, validates invoice flows
 * Called via: EventBus::emit('financial.audit', [...])
 */
class FinancialAgent {

    /**
     * Main entry — called by AIOrchestrator
     */
    public static function run(array $payload = []): array {
        $result = [
            'timestamp'     => date('Y-m-d H:i:s'),
            'ledger_check'  => self::verifyLedger(),
            'invoice_check' => self::verifyInvoices(),
            'wallet_check'  => self::verifyWallets(),
            'issues'        => [],
        ];

        // Collect issues
        if (!$result['ledger_check']['balanced']) {
            $result['issues'][] = [
                'type'     => 'LEDGER_MISMATCH',
                'severity' => 'CRITICAL',
                'detail'   => $result['ledger_check'],
            ];
        }
        foreach ($result['invoice_check']['stuck'] as $inv) {
            $result['issues'][] = [
                'type'     => 'INVOICE_STUCK',
                'severity' => 'HIGH',
                'detail'   => $inv,
            ];
        }

        // Log findings
        self::persistAudit($result);

        // Notify admin if critical
        if (!empty($result['issues'])) {
            self::alertAdmin($result['issues']);
        }

        return $result;
    }

    /**
     * SECTION 6 RULE: SUM(debit) MUST EQUAL SUM(credit)
     */
    public static function verifyLedger(): array {
        try {
            $row = db()->query(
                "SELECT COALESCE(SUM(debit),0) AS total_debit,
                        COALESCE(SUM(credit),0) AS total_credit
                 FROM ledger"
            )->fetch(PDO::FETCH_ASSOC);

            $debit  = (float)$row['total_debit'];
            $credit = (float)$row['total_credit'];
            $diff   = round(abs($debit - $credit), 2);

            return [
                'total_debit'  => $debit,
                'total_credit' => $credit,
                'difference'   => $diff,
                'balanced'     => $diff < 0.01,
                'status'       => $diff < 0.01 ? 'OK' : 'MISMATCH',
            ];
        } catch (Throwable $e) {
            return ['status' => 'ERROR', 'error' => $e->getMessage(), 'balanced' => false];
        }
    }

    /**
     * Find invoices stuck in pending > 24 hours
     */
    public static function verifyInvoices(): array {
        try {
            $stuck = db()->query(
                "SELECT id, user_id, service, amount, reference_code, status, created_at
                 FROM invoices
                 WHERE status IN ('pending','proof_uploaded','under_review')
                   AND created_at < DATE_SUB(NOW(), INTERVAL 24 HOUR)
                 LIMIT 20"
            )->fetchAll(PDO::FETCH_ASSOC);

            $duplicates = db()->query(
                "SELECT reference_code, COUNT(*) as cnt
                 FROM invoices
                 GROUP BY reference_code
                 HAVING cnt > 1"
            )->fetchAll(PDO::FETCH_ASSOC);

            return [
                'stuck_count'      => count($stuck),
                'stuck'            => $stuck,
                'duplicate_refs'   => count($duplicates),
                'status'           => count($stuck) === 0 ? 'OK' : 'HAS_STUCK',
            ];
        } catch (Throwable $e) {
            return ['status' => 'ERROR', 'error' => $e->getMessage(), 'stuck' => []];
        }
    }

    /**
     * Verify wallet balances match ledger entries
     */
    public static function verifyWallets(): array {
        try {
            // Sum all wallet balances
            $walletSum = (float)db()->query(
                "SELECT COALESCE(SUM(balance_sdg), 0) FROM wallet"
            )->fetchColumn();

            // Sum net credits - debits for user wallet account (account code 1002)
            $ledgerNet = db()->query(
                "SELECT COALESCE(SUM(credit - debit), 0)
                 FROM ledger l
                 JOIN accounts a ON a.id = l.account_id
                 WHERE a.code = '1002'"
            )->fetchColumn();
            $ledgerNet = (float)$ledgerNet;

            $diff = round(abs($walletSum - $ledgerNet), 2);
            return [
                'wallet_sum'  => $walletSum,
                'ledger_net'  => $ledgerNet,
                'difference'  => $diff,
                'status'      => $diff < 0.01 ? 'OK' : 'MISMATCH',
            ];
        } catch (Throwable $e) {
            return ['status' => 'ERROR', 'error' => $e->getMessage()];
        }
    }

    /**
     * Process payment confirmation — SECTION 5 flow
     * Called after admin approves payment proof
     * @param int $invoiceId
     * @param int $adminId
     */
    public static function confirmPayment(int $invoiceId, int $adminId): array {
        try {
            // Idempotency: check not already paid
            $inv = db()->prepare(
                "SELECT * FROM invoices WHERE id = ? AND status NOT IN ('paid','refunded')"
            );
            $inv->execute([$invoiceId]);
            $invoice = $inv->fetch(PDO::FETCH_ASSOC);

            if (!$invoice) {
                return ['success' => false, 'error' => 'Invoice already processed or not found'];
            }

            $userId  = (int)$invoice['user_id'];
            $amount  = (float)$invoice['amount'];

            // Begin double-entry: Debit Cash(1001) Credit UserLiability(2001)
            // Then: Debit UserLiability(2001) Credit UserWallet(1002)
            db()->beginTransaction();

            // Entry 1: Cash received
            $acct1001 = self::getAccount('1001');
            $acct2001 = self::getAccount('2001');
            $acct1002 = self::getAccount('1002');
            $acct4001 = self::getAccount('4001');

            self::ledgerEntry($acct1001, $amount, 0, 'invoice', $invoiceId, 'استلام دفعة');
            self::ledgerEntry($acct2001, 0, $amount, 'invoice', $invoiceId, 'التزام للمستخدم');

            // Entry 2: Wallet top-up
            self::ledgerEntry($acct2001, $amount, 0, 'invoice', $invoiceId, 'تحميل المحفظة');
            self::ledgerEntry($acct1002, 0, $amount, 'invoice', $invoiceId, 'رصيد المحفظة');

            // Entry 3: Commission revenue (10% of amount → Commission Revenue acct4001)
            // DEBIT UserWallet(1002) — cost from user perspective
            // CREDIT CommissionRevenue(4001) — Sudanna earns
            $commissionRate   = (float)PricingEngine::getSetting('pay_commission_rate', 0.10);
            $commissionAmount = round($amount * $commissionRate, 2);
            if ($commissionAmount > 0) {
                self::ledgerEntry($acct1002, $commissionAmount, 0, 'invoice', $invoiceId, 'عمولة سودانا');
                self::ledgerEntry($acct4001, 0, $commissionAmount, 'invoice', $invoiceId, 'إيراد عمولة');
            }

            // Update wallet balance
            db()->prepare(
                "INSERT INTO wallet (user_id, balance_sdg, total_deposited, created_at)
                 VALUES (?, ?, ?, NOW())
                 ON DUPLICATE KEY UPDATE
                 balance_sdg = balance_sdg + VALUES(balance_sdg),
                 total_deposited = total_deposited + VALUES(balance_sdg),
                 updated_at = NOW()"
            )->execute([$userId, $amount, $amount]);

            // Mark invoice paid
            db()->prepare(
                "UPDATE invoices SET status='paid', paid_at=NOW() WHERE id=?"
            )->execute([$invoiceId]);

            // Mark proof approved
            db()->prepare(
                "UPDATE payment_proofs SET status='approved', reviewed_by=?, reviewed_at=NOW()
                 WHERE invoice_id=?"
            )->execute([$adminId, $invoiceId]);

            // Insert wallet transaction
            $walletId = db()->query("SELECT id FROM wallet WHERE user_id=$userId")->fetchColumn();
            $balance  = db()->query("SELECT balance_sdg FROM wallet WHERE user_id=$userId")->fetchColumn();
            db()->prepare(
                "INSERT INTO wallet_transactions
                 (wallet_id, user_id, type, amount_sdg, balance_after, ref_type, ref_id, description, created_at)
                 VALUES (?,?,'credit',?,?,'invoice',?,?,NOW())"
            )->execute([$walletId, $userId, $amount, $balance, $invoiceId, "شحن محفظة — فاتورة #$invoiceId"]);

            db()->commit();

            // ── FIX 1: Generate receipt (UNIQUE per invoice) ──────────────
            $receiptNo = self::generateReceiptNo($invoiceId);
            $userEmail = db()->query("SELECT email FROM users WHERE id=$userId")->fetchColumn();
            $userName  = db()->query("SELECT name  FROM users WHERE id=$userId")->fetchColumn();

            // Verify ledger balance before writing receipt
            $lv = self::verifyLedger();
            $ledgerOk = $lv['balanced'] ?? false;

            try {
                db()->prepare(
                    "INSERT IGNORE INTO payment_receipts
                     (invoice_id, user_id, receipt_no, amount, service, payment_method,
                      reference_code, txn_id, issued_at, ledger_balanced)
                     VALUES (?,?,?,?,?,?,?,?,NOW(),?)"
                )->execute([
                    $invoiceId, $userId, $receiptNo, $amount,
                    $invoice['service'] ?? 'general',
                    $invoice['payment_method'] ?? 'offline',
                    $invoice['reference_code'] ?? '',
                    $invoice['gateway_txn_id'] ?? null,
                    $ledgerOk ? 1 : 0,
                ]);
            } catch (\Throwable $re) {
                error_log("[FinancialAgent::receipt] " . $re->getMessage());
            }

            // ── FIX 2: Send payment confirmation email (finance@sudanna.ai) ─
            if ($userEmail) {
                $emailSent = self::sendPaymentEmail($userEmail, $userName ?: 'عميل', [
                    'receipt_no'     => $receiptNo,
                    'invoice_id'     => $invoiceId,
                    'amount'         => $amount,
                    'reference_code' => $invoice['reference_code'] ?? '',
                    'paid_at'        => date('Y-m-d H:i:s'),
                    'service'        => $invoice['service'] ?? 'خدمة سودانا',
                    'method'         => $invoice['payment_method'] ?? 'offline',
                    'ledger_balanced'=> $ledgerOk,
                ]);
                if ($emailSent) {
                    db()->prepare(
                        "UPDATE payment_receipts SET emailed_at=NOW(), email_recipient=? WHERE invoice_id=?"
                    )->execute([$userEmail, $invoiceId]);
                }
            }

            // Fire confirmation event
            EventBus::emit('payment.confirmed', [
                'user_id'    => $userId,
                'invoice_id' => $invoiceId,
                'amount'     => $amount,
                'reference'  => $invoice['reference_code'],
            ]);

            return [
                'success'    => true,
                'invoice_id' => $invoiceId,
                'user_id'    => $userId,
                'amount'     => $amount,
                'ledger_entries' => 4,
                'wallet_updated' => true,
            ];
        } catch (Throwable $e) {
            db()->rollBack();
            error_log("[FinancialAgent] confirmPayment: " . $e->getMessage());
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    /**
     * SECTION 10: Refund — reverse ledger entries
     */
    public static function processRefund(int $invoiceId, int $adminId): array {
        try {
            $inv = db()->prepare(
                "SELECT * FROM invoices WHERE id = ? AND status = 'paid'"
            );
            $inv->execute([$invoiceId]);
            $invoice = $inv->fetch(PDO::FETCH_ASSOC);

            if (!$invoice) {
                return ['success' => false, 'error' => 'Invoice not paid or not found'];
            }

            $userId = (int)$invoice['user_id'];
            $amount = (float)$invoice['amount'];

            db()->beginTransaction();

            // Reverse entries (mirror of confirmPayment)
            $acct1001 = self::getAccount('1001');
            $acct2001 = self::getAccount('2001');
            $acct1002 = self::getAccount('1002');

            self::ledgerEntry($acct1002, $amount, 0, 'invoice_refund', $invoiceId, 'استرداد من المحفظة');
            self::ledgerEntry($acct2001, 0, $amount, 'invoice_refund', $invoiceId, 'التزام استرداد');
            self::ledgerEntry($acct2001, $amount, 0, 'invoice_refund', $invoiceId, 'دفع الاسترداد');
            self::ledgerEntry($acct1001, 0, $amount, 'invoice_refund', $invoiceId, 'إعادة النقدية');

            // Deduct wallet
            db()->prepare(
                "UPDATE wallet SET balance_sdg = balance_sdg - ?, updated_at=NOW()
                 WHERE user_id=? AND balance_sdg >= ?"
            )->execute([$amount, $userId, $amount]);

            // Mark invoice refunded
            db()->prepare(
                "UPDATE invoices SET status='refunded' WHERE id=?"
            )->execute([$invoiceId]);

            db()->commit();

            // Fire reversal event
            EventBus::emit('payment.reversed', [
                'user_id'    => $userId,
                'invoice_id' => $invoiceId,
                'amount'     => $amount,
            ]);

            return ['success' => true, 'invoice_id' => $invoiceId, 'refunded' => $amount];
        } catch (Throwable $e) {
            db()->rollBack();
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    // ── Private helpers ────────────────────────────────────────────

    private static function getAccount(string $code): int {
        return (int)db()->query(
            "SELECT id FROM accounts WHERE code='$code' LIMIT 1"
        )->fetchColumn();
    }

    private static function ledgerEntry(
        int $accountId, float $debit, float $credit,
        string $refType, int $refId, string $desc
    ): void {
        db()->prepare(
            "INSERT INTO ledger (account_id, debit, credit, reference_type, reference_id, description, created_at)
             VALUES (?,?,?,?,?,?,NOW())"
        )->execute([$accountId, $debit, $credit, $refType, $refId, $desc]);
    }

    private static function persistAudit(array $result): void {
        try {
            db()->prepare(
                "INSERT INTO audit_logs (action, entity_type, entity_id, data, created_at)
                 VALUES ('financial.audit','system',0,?,NOW())"
            )->execute([json_encode($result, JSON_UNESCAPED_UNICODE)]);
        } catch (Throwable $e) {
            error_log("[FinancialAgent::audit] " . $e->getMessage());
        }
    }

    private static function alertAdmin(array $issues): void {
        try {
            $body = 'تنبيه مالي: ' . count($issues) . ' مشكلة تحتاج مراجعة';
            db()->prepare(
                "INSERT INTO notifications (user_id, type, title, body, data, created_at)
                 VALUES (1, 'financial_alert', '⚠️ تنبيه مالي', ?, ?, NOW())"
            )->execute([$body, json_encode($issues, JSON_UNESCAPED_UNICODE)]);
        } catch (Throwable $e) {
            error_log("[FinancialAgent::alert] " . $e->getMessage());
        }
    }

    // ── Receipt helpers ─────────────────────────────────────────────

    private static function generateReceiptNo(int $invoiceId): string {
        $count = (int)db()->query("SELECT COUNT(*) FROM payment_receipts")->fetchColumn();
        return 'RCP-' . date('Ymd') . '-' . str_pad($count + 1, 6, '0', STR_PAD_LEFT);
    }

    private static function sendPaymentEmail(string $to, string $name, array $data): bool {
        $receiptNo  = htmlspecialchars($data['receipt_no']);
        $invoiceId  = (int)$data['invoice_id'];
        $amount     = number_format($data['amount'], 2);
        $refCode    = htmlspecialchars($data['reference_code']);
        $paidAt     = htmlspecialchars($data['paid_at']);
        $service    = htmlspecialchars($data['service']);
        $method     = $data['method'] === 'gateway' ? 'دفع إلكتروني' : 'تحويل بنكي';
        $balanced   = $data['ledger_balanced'] ? '✅ متوازن' : '⚠️ مراجعة مطلوبة';
        $siteUrl    = defined('SITE_URL') ? SITE_URL : 'https://sudanna.ai/s26';

        $subject = "إيصال دفع #{$receiptNo} — سودانا";
        $html = <<<HTML
<!DOCTYPE html>
<html dir="rtl" lang="ar">
<head><meta charset="utf-8">
<style>
body{font-family:Arial,sans-serif;background:#f4f7f0;margin:0;padding:20px}
.box{background:#fff;max-width:520px;margin:0 auto;border-radius:12px;padding:32px;border-top:4px solid #073328}
.logo{font-size:1.4rem;font-weight:900;color:#073328;margin-bottom:4px}
.tag{background:#e8f5e9;color:#073328;padding:4px 10px;border-radius:20px;font-size:.8rem}
.row{display:flex;justify-content:space-between;padding:10px 0;border-bottom:1px solid #f0f0f0}
.lbl{color:#666;font-size:.9rem}
.val{font-weight:600;color:#222}
.amt{font-size:1.5rem;color:#073328;font-weight:900}
.footer{margin-top:24px;font-size:.78rem;color:#999;text-align:center}
</style>
</head>
<body>
<div class="box">
  <div class="logo">🇸🇩 سودانا</div>
  <div class="tag">إيصال دفع رسمي</div>
  <hr style="margin:16px 0;border:none;border-top:1px solid #eee">
  <p>مرحباً {$name}،</p>
  <p>تم استلام دفعتك بنجاح. فيما يلي تفاصيل الإيصال:</p>
  <div class="row"><span class="lbl">رقم الإيصال</span><span class="val">{$receiptNo}</span></div>
  <div class="row"><span class="lbl">رقم الفاتورة</span><span class="val">#{$invoiceId}</span></div>
  <div class="row"><span class="lbl">الرمز المرجعي</span><span class="val">{$refCode}</span></div>
  <div class="row"><span class="lbl">الخدمة</span><span class="val">{$service}</span></div>
  <div class="row"><span class="lbl">طريقة الدفع</span><span class="val">{$method}</span></div>
  <div class="row"><span class="lbl">وقت الدفع</span><span class="val">{$paidAt}</span></div>
  <div class="row"><span class="lbl">التوازن المحاسبي</span><span class="val">{$balanced}</span></div>
  <div style="text-align:center;margin:20px 0">
    <div class="lbl">المبلغ المستلم</div>
    <div class="amt">{$amount} جنيه سوداني</div>
  </div>
  <p style="text-align:center">
    <a href="{$siteUrl}/api/payment/status.php?ref={$refCode}"
       style="background:#073328;color:#fff;padding:10px 24px;border-radius:8px;text-decoration:none">
      عرض الإيصال الرقمي
    </a>
  </p>
  <div class="footer">
    هذا البريد أُرسل من <strong>finance@sudanna.ai</strong><br>
    سودانا للخدمات الذكية — لا ترد على هذا البريد
  </div>
</div>
</body>
</html>
HTML;
        // Use finance@sudanna.ai as sender — override config
        $headers  = "MIME-Version: 1.0\r\n";
        $headers .= "Content-Type: text/html; charset=utf-8\r\n";
        $headers .= "From: سودانا المالية <finance@sudanna.ai>\r\n";
        $headers .= "Reply-To: finance@sudanna.ai\r\n";
        $encodedSubject = '=?utf-8?B?' . base64_encode($subject) . '?=';
        $sent = @mail($to, $encodedSubject, $html, $headers);
        if (!$sent) error_log("[FinancialAgent::email] Failed to send to $to");
        return $sent;
    }


    // ── journal(): تسجيل قيد محاسبي ──────────────────────────
    public static function journal(string $type, string $txnRef, int $userId, float $amount, float $fee, int $providerId = 0): void {
        require_once __DIR__ . '/AccountingEngine.php';
        try {
            switch ($type) {
                case 'transfer':
                    AccountingEngine::recordTransfer($txnRef, $userId, $providerId, $amount, $fee);
                    break;
                case 'bill':
                    AccountingEngine::recordBillPayment($txnRef, $userId, $amount, $fee, 'Bill');
                    break;
                case 'service':
                    $platformFee = $amount * 0.10;
                    AccountingEngine::recordServicePayment($txnRef, $userId, $providerId, $amount, $platformFee, $amount-$platformFee, 'other');
                    break;
                case 'subscription':
                    AccountingEngine::recordSubscription($txnRef, $userId, $amount, 'plus');
                    break;
            }
        } catch (\Throwable $e) {
            error_log("[FinancialAgent::journal] ".$e->getMessage());
        }
    }

    // ── reconcile(): تسوية يومية ──────────────────────────────
    public static function reconcile(string $date = ''): array {
        require_once __DIR__ . '/AccountingEngine.php';
        return AccountingEngine::runDailyReconciliation($date ?: date('Y-m-d'));
    }

    // ── chart_of_accounts(): جلب شجرة الحسابات ───────────────
    public static function chart_of_accounts(): array {
        try {
            $st = db()->prepare("SELECT * FROM chart_of_accounts ORDER BY code");
            $st->execute([]);
            return $st->fetchAll();
        } catch (\Throwable $e) { return []; }
    }

}
