<?php
/**
 * سودانا — ReconciliationEngine v1
 * Bank ↔ System ↔ Ledger matching
 * PRINCIPLE: NO payout before reconciliation passes
 * BANK_SOURCE: bank wins on mismatch
 */
class ReconciliationEngine {

    /**
     * Daily reconciliation run
     * Returns pass/fail + mismatches
     */
    public static function run(string $date = null): array {
        $date    = $date ?: date('Y-m-d', strtotime('yesterday'));
        $traceId = uniqid('rec_', true);

        try {
            // 1. System: all paid invoices for the date
            $sysQ = db()->prepare(
                "SELECT reference_code, amount, payment_method, gateway_txn_id,
                        paid_at, user_id
                 FROM invoices
                 WHERE status='paid'
                   AND DATE(paid_at)=?"
            );
            $sysQ->execute([$date]);
            $systemTxns = $sysQ->fetchAll(PDO::FETCH_ASSOC);

            // 2. Ledger: sum for the date
            $ledQ = db()->prepare(
                "SELECT COALESCE(SUM(debit),0) as total_debit,
                        COALESCE(SUM(credit),0) as total_credit,
                        COUNT(*) as entry_count
                 FROM ledger
                 WHERE DATE(created_at)=?"
            );
            $ledQ->execute([$date]);
            $ledger = $ledQ->fetch(PDO::FETCH_ASSOC);

            $ledgerBalanced = abs((float)$ledger['total_debit'] - (float)$ledger['total_credit']) < 0.01;

            // 3. Compute system totals
            $systemTotal = array_sum(array_column($systemTxns, 'amount'));

            // 4. Bank statement (real API call via BankAdapter)
            require_once __DIR__ . '/BankAdapter.php';
            $bankData = BankAdapter::getStatement($date . ' 00:00:00', $date . ' 23:59:59');
            $bankTotal = (float)($bankData['total_received'] ?? 0);

            // 5. Detect mismatches
            $mismatches = [];

            // Ledger balance
            if (!$ledgerBalanced) {
                $mismatches[] = [
                    'type'   => 'LEDGER_IMBALANCE',
                    'debit'  => $ledger['total_debit'],
                    'credit' => $ledger['total_credit'],
                    'diff'   => round(abs($ledger['total_debit'] - $ledger['total_credit']), 2),
                ];
            }

            // Bank vs system (only if we got real bank data)
            if (!($bankData['sandbox'] ?? true) && abs($bankTotal - $systemTotal) > 1.0) {
                $mismatches[] = [
                    'type'      => 'BANK_SYSTEM_MISMATCH',
                    'bank'      => $bankTotal,
                    'system'    => $systemTotal,
                    'diff'      => round(abs($bankTotal - $systemTotal), 2),
                ];
            }

            $passed = empty($mismatches) && $ledgerBalanced;

            $result = [
                'date'          => $date,
                'passed'        => $passed,
                'status'        => $passed ? 'PASS' : 'FAIL',
                'system_total'  => $systemTotal,
                'system_txns'   => count($systemTxns),
                'ledger_debit'  => (float)$ledger['total_debit'],
                'ledger_credit' => (float)$ledger['total_credit'],
                'ledger_balanced'=> $ledgerBalanced,
                'mismatches'    => $mismatches,
                'mismatch_count'=> count($mismatches),
                'bank_mode'     => ($bankData['sandbox'] ?? true) ? 'sandbox' : 'live',
                'trace_id'      => $traceId,
                'run_at'        => date('Y-m-d H:i:s'),
            ];

            // Store result
            self::persist($result);

            // Alert admin if failed
            if (!$passed) {
                self::alertAdmin($result);
            }

            return $result;

        } catch (Throwable $e) {
            error_log("[ReconciliationEngine] " . $e->getMessage());
            return ['passed'=>false, 'status'=>'ERROR', 'error'=>$e->getMessage(), 'trace_id'=>$traceId];
        }
    }

    /**
     * Check if reconciliation passed for a date
     * Called by SettlementEngine before payout
     */
    public static function isPassed(string $date): bool {
        try {
            $q = db()->prepare(
                "SELECT COUNT(*) FROM audit_logs
                 WHERE action='reconciliation.passed' AND entity_type='date'
                   AND data LIKE ?"
            );
            $q->execute(["%\"date\":\"$date\"%"]);
            return (int)$q->fetchColumn() > 0;
        } catch (Throwable $e) {
            return false; // Fail safe: block payout if cannot verify
        }
    }

    private static function persist(array $result): void {
        $action = $result['passed'] ? 'reconciliation.passed' : 'reconciliation.failed';
        try {
            db()->prepare(
                "INSERT INTO audit_logs (action, entity_type, entity_id, data, created_at)
                 VALUES (?, 'date', 0, ?, NOW())"
            )->execute([$action, json_encode($result, JSON_UNESCAPED_UNICODE)]);
        } catch (Throwable $e) {
            error_log("[ReconciliationEngine::persist] " . $e->getMessage());
        }
    }

    private static function alertAdmin(array $result): void {
        try {
            $body = "تسوية {$result['date']}: {$result['mismatch_count']} مشكلة — " .
                    json_encode($result['mismatches']);
            db()->prepare(
                "INSERT INTO notifications (user_id,type,title,body,data,created_at)
                 VALUES (1,'reconciliation_fail','⚠️ فشلت التسوية',?,?,NOW())"
            )->execute([$body, json_encode($result, JSON_UNESCAPED_UNICODE)]);
        } catch (Throwable $e) {
            error_log("[ReconciliationEngine::alert] " . $e->getMessage());
        }
    }

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

    // ── batch(): معالجة دُفعة ─────────────────────────────────
    public static function batch(string $type, string $date = ''): array {
        if (!$date) $date = date('Y-m-d');
        return self::reconcile($date);
    }

    // ── daily(): التسوية اليومية ──────────────────────────────
    public static function daily(): array {
        return self::reconcile(date('Y-m-d'));
    }

    // ── settlement(): تسوية مع EBS/بنك ──────────────────────
    public static function settlement(float $amount, string $direction = 'to_bank'): array {
        // يُنفَّذ عند توفر Bank API
        return ['ok'=>false,'message'=>'Bank API not connected — EBS license required','amount'=>$amount];
    }

}
