<?php
namespace App\classes;
use mysqli;

/**
 * BalanceHistory Class
 * 
 * Tracks all balance changes for agents, including store owners.
 * Store owners are agents in the agents table, so all balance changes
 * for store owners are automatically tracked through this class.
 * 
 * Usage:
 * - For order deductions: BalanceHistory::log($conn, $agentId, -$amount, 'order', $orderId, $phone)
 * - For payments/topups: BalanceHistory::log($conn, $agentId, $amount, 'payment', null, $reference)
 * - For refunds: BalanceHistory::log($conn, $agentId, $amount, 'refund', $orderId, 'reason')
 * - For manual adjustments: BalanceHistory::log($conn, $agentId, $amount, 'manual_adjustment', null, 'note')
 */
class BalanceHistory
{
    /**
     * Log a balance change for an agent (including store owners)
     * 
     * @param mysqli $conn Database connection
     * @param int $agentId Agent ID (store owners are also agents)
     * @param float $changeAmount Amount of change (positive for credit, negative for debit)
     * @param string $reason Reason for change (order, payment, refund, manual_adjustment)
     * @param int|null $refId Reference ID (e.g., order ID)
     * @param string|null $beneficiaryNumber Beneficiary number or reference note
     * @param float|null $balanceBefore Balance before the change (if provided, will be used; otherwise calculated)
     * @param float|null $balanceAfter Balance after the change (if provided, will be used; otherwise fetched from DB)
     * @return bool Success status
     */
    public static function log(mysqli $conn, int $agentId, float $changeAmount, string $reason, ?int $refId = null, ?string $beneficiaryNumber = null, ?float $balanceBefore = null, ?float $balanceAfter = null)
    {
        // Check if balance history logging is disabled (for production issues)
        if (defined('DISABLE_BALANCE_HISTORY') && DISABLE_BALANCE_HISTORY === true) {
            return true; // Return success without logging
        }
        
        // If balance_after is not provided, fetch it from database
        if ($balanceAfter === null) {
            $stmt = $conn->prepare("SELECT balance FROM agents WHERE id = ?");
            $stmt->bind_param("i", $agentId);
            $stmt->execute();
            $result = $stmt->get_result();
            $agent = $result->fetch_assoc();
            $stmt->close();

            if (!$agent) {
                error_log("BalanceHistory: Agent ID $agentId not found.");
                return false;
            }

            $balanceAfter = floatval($agent['balance']); // This is the balance *after* the current transaction has been applied
        }
        
        // If balance_before is not provided, calculate it from balance_after and change_amount
        if ($balanceBefore === null) {
            $balanceBefore = $balanceAfter - $changeAmount;
        }

        // Ensure reason is not empty
        if (empty($reason)) {
            $reason = 'txn';
        }
        
        // Map common reasons to valid ENUM values
        $reasonMap = [
            'topup' => 'manual_adjustment',
            'order' => 'order',
            'payment' => 'payment',
            'refund' => 'manual_adjustment',
            'adjustment' => 'manual_adjustment',
            'bonus' => 'manual_adjustment',
            'commission' => 'manual_adjustment',
            'txn' => 'manual_adjustment'
        ];
        
        $truncatedReason = $reasonMap[$reason] ?? 'manual_adjustment';
        
        // Also truncate beneficiary number if it's too long
        if ($beneficiaryNumber && strlen($beneficiaryNumber) > 10) {
            $beneficiaryNumber = substr($beneficiaryNumber, 0, 10);
        }
        

        try {
            // Check if balance_before column exists
            $checkColStmt = $conn->query("SHOW COLUMNS FROM balance_history LIKE 'balance_before'");
            $hasBalanceBefore = $checkColStmt && $checkColStmt->num_rows > 0;
            if ($checkColStmt) $checkColStmt->close();
            
            if ($hasBalanceBefore) {
                $insertStmt = $conn->prepare("INSERT INTO balance_history (agent_id, change_amount, balance_before, balance_after, reason, ref_id, beneficiary_number) VALUES (?, ?, ?, ?, ?, ?, ?)");
                if (!$insertStmt) {
                    error_log("BalanceHistory: Prepare failed: " . $conn->error);
                    return false;
                }
                $insertStmt->bind_param("idddsis", $agentId, $changeAmount, $balanceBefore, $balanceAfter, $truncatedReason, $refId, $beneficiaryNumber);
            } else {
                // Fallback for older schema without balance_before column
                $insertStmt = $conn->prepare("INSERT INTO balance_history (agent_id, change_amount, balance_after, reason, ref_id, beneficiary_number) VALUES (?, ?, ?, ?, ?, ?)");
                if (!$insertStmt) {
                    error_log("BalanceHistory: Prepare failed: " . $conn->error);
                    return false;
                }
                $insertStmt->bind_param("iddsis", $agentId, $changeAmount, $balanceAfter, $truncatedReason, $refId, $beneficiaryNumber);
            }
            $success = $insertStmt->execute();
            if (!$success) {
                error_log("BalanceHistory: Execute failed: " . $insertStmt->error . " | Reason: '$truncatedReason' | Beneficiary: '$beneficiaryNumber'");
            }
            $insertStmt->close();
            return $success;
        } catch (mysqli_sql_exception $e) {
            // If it's still a truncation error, try with minimal data
            if (strpos($e->getMessage(), 'Data truncated') !== false) {
                try {
                    // Try with only essential fields, no reason or beneficiary
                    $checkColStmt = $conn->query("SHOW COLUMNS FROM balance_history LIKE 'balance_before'");
                    $hasBalanceBefore = $checkColStmt && $checkColStmt->num_rows > 0;
                    if ($checkColStmt) $checkColStmt->close();
                    
                    if ($hasBalanceBefore) {
                        $minimalStmt = $conn->prepare("INSERT INTO balance_history (agent_id, change_amount, balance_before, balance_after) VALUES (?, ?, ?, ?)");
                        if ($minimalStmt) {
                            $minimalStmt->bind_param("iddd", $agentId, $changeAmount, $balanceBefore, $balanceAfter);
                            $minimalSuccess = $minimalStmt->execute();
                            $minimalStmt->close();
                            return $minimalSuccess;
                        }
                    } else {
                        $minimalStmt = $conn->prepare("INSERT INTO balance_history (agent_id, change_amount, balance_after) VALUES (?, ?, ?)");
                        if ($minimalStmt) {
                            $minimalStmt->bind_param("idd", $agentId, $changeAmount, $balanceAfter);
                            $minimalSuccess = $minimalStmt->execute();
                            $minimalStmt->close();
                            return $minimalSuccess;
                        }
                    }
                } catch (Exception $minimalException) {
                    // If even minimal insert fails, skip balance history logging entirely
                    // This ensures the main transaction (balance update) still succeeds
                    return true; // Return true to indicate "success" even though logging failed
                }
            }
            return false;
        }
    }
}
