<?php

if (!function_exists('base_url')) {
    function base_url(string $path = ''): string {
        if (!defined('BASE_URL')) {
             trigger_error("Konstanta BASE_URL belum didefinisikan. Pastikan config.php sudah di-include.", E_USER_ERROR);
             return '';
        }
        $path = ltrim($path, '/');
        $baseUrl = rtrim(BASE_URL, '/') . '/';
        return $baseUrl . $path;
    }
}

if (!function_exists('sanitize_input')) {
    function sanitize_input(?string $data): string {
        if ($data === null) {
            return '';
        }
        $data = trim($data);
        $data = stripslashes($data);
        $data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
        return $data;
    }
}

if (!function_exists('redirect')) {
    function redirect(string $url): void {
        if (filter_var($url, FILTER_VALIDATE_URL) || (isset($url[0]) && $url[0] === '/') || (isset($url[0]) && $url[0] !== ' ' && strpos($url, '//') === false)) {
             header('Location: ' . $url);
        } else {
            trigger_error("Invalid redirect URL: " . htmlspecialchars($url), E_USER_WARNING);
        }
        exit;
    }
}

if (!function_exists('set_flash_message')) {
    function set_flash_message(string $name, string|array $message, string $type = 'info'): void {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
        $_SESSION['flash_' . $name] = [
            'message' => $message,
            'type' => $type
        ];
    }
}

if (!function_exists('display_flash_message')) {
    function display_flash_message(string $name): void {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
        if (isset($_SESSION['flash_' . $name])) {
            $flash = $_SESSION['flash_' . $name];
            $alert_class = 'bg-blue-100 border-blue-300 text-blue-700';
            if ($flash['type'] === 'success') {
                $alert_class = 'bg-green-100 border-green-300 text-green-700';
            } elseif ($flash['type'] === 'error') {
                $alert_class = 'bg-red-100 border-red-300 text-red-700';
            } elseif ($flash['type'] === 'warning') {
                 $alert_class = 'bg-yellow-100 border-yellow-300 text-yellow-700';
            }

            echo '<div class="mb-4 p-3 ' . $alert_class . ' border rounded-lg text-sm" role="alert">';
            if (is_array($flash['message'])) {
                 echo '<ul class="list-disc list-inside">';
                 foreach ($flash['message'] as $msg) {
                     echo '<li>' . htmlspecialchars($msg) . '</li>';
                 }
                 echo '</ul>';
            } else {
                 echo htmlspecialchars($flash['message']);
            }
            echo '</div>';

            unset($_SESSION['flash_' . $name]);
        }
    }
}

if (!function_exists('getStatusBadgeClass')) {
    function getStatusBadgeClass(string $status): string {
        switch (strtolower($status)) {
            case 'success':
                return 'bg-green-100 text-green-800 border border-green-200';
            case 'processing':
            case 'in progress':
                return 'bg-blue-100 text-blue-800 border border-blue-200';
            case 'pending':
                return 'bg-yellow-100 text-yellow-800 border border-yellow-200';
            case 'partial':
                return 'bg-orange-100 text-orange-800 border border-orange-200';
            case 'error':
            case 'canceled':
            case 'expired': // Tambahkan case untuk expired jika perlu
                return 'bg-red-100 text-red-800 border border-red-200';
            default:
                return 'bg-gray-100 text-gray-800 border border-gray-200';
        }
    }
}

/**
 * Mencatat mutasi saldo pengguna ke dalam tabel balance_logs.
 *
 * @param PDO $pdo Objek koneksi PDO.
 * @param int $userId ID pengguna.
 * @param string $type Tipe mutasi ('credit' atau 'debit').
 * @param string $category Kategori transaksi.
 * @param float $amount Jumlah yang dimutasikan.
 * @param float $balanceBefore Saldo sebelum mutasi.
 * @param float $balanceAfter Saldo setelah mutasi.
 * @param string|null $description Deskripsi transaksi.
 * @param string|null $referenceId ID referensi (misal: ID Pesanan, ID Deposit).
 * @param string $source Sumber aksi (default: 'web').
 * @return bool True jika berhasil mencatat, false jika gagal.
 */
function log_balance_mutation(
    PDO $pdo,
    int $userId,
    string $type,
    string $category,
    float $amount,
    float $balanceBefore,
    float $balanceAfter,
    ?string $description = null,
    ?string $referenceId = null,
    string $source = 'web'
): bool {
    $sql = "INSERT INTO balance_logs (user_id, type, category, amount, balance_before, balance_after, description, reference_id, source, created_at)
            VALUES (:user_id, :type, :category, :amount, :balance_before, :balance_after, :description, :reference_id, :source, NOW())";
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->bindParam(':user_id', $userId, PDO::PARAM_INT);
        $stmt->bindParam(':type', $type);
        $stmt->bindParam(':category', $category);
        $stmt->bindParam(':amount', $amount);
        $stmt->bindParam(':balance_before', $balanceBefore);
        $stmt->bindParam(':balance_after', $balanceAfter);
        $stmt->bindParam(':description', $description);
        $stmt->bindParam(':reference_id', $referenceId);
        $stmt->bindParam(':source', $source);
        return $stmt->execute();
    } catch (PDOException $e) {
        error_log("Failed to log balance mutation for user ID {$userId}: " . $e->getMessage());
        return false;
    }
}

if (!function_exists('format_local_date')) {
    function format_local_date(?string $dateString, string $format = 'dd MMM yyyy, HH:mm'): string {
        if (empty($dateString)) {
            return 'N/A';
        }
        try {
            $dateTime = new DateTime($dateString);
            if (class_exists('IntlDateFormatter')) {
                $formatter = new IntlDateFormatter(
                    'id_ID',
                    IntlDateFormatter::FULL,
                    IntlDateFormatter::FULL,
                    $dateTime->getTimezone()->getName(),
                    IntlDateFormatter::GREGORIAN,
                    $format
                );
                if ($formatter) {
                    return $formatter->format($dateTime);
                }
            }

            $phpDateFormat = 'd M Y, H:i';
            if ($format === 'dd MMM yyyy, HH:mm:ss') {
                $phpDateFormat = 'd M Y, H:i:s';
            } elseif ($format === 'dd MMM yyyy') {
                 $phpDateFormat = 'd M Y';
            }

            return date($phpDateFormat, $dateTime->getTimestamp());
        } catch (Exception $e) {
            error_log("Error formatting date '{$dateString}' in PHP: " . $e->getMessage());
            return $dateString;
        }
    }
}

/**
 * Mendapatkan informasi browser dan OS dari User Agent.
 * Ini adalah fungsi dasar, untuk deteksi yang lebih akurat, pertimbangkan pustaka seperti whichbrowser/parser.
 * @param string|null $userAgentString
 * @return array Dengan keys 'browser', 'platform', 'device_type'
 */
function parse_user_agent_basic(?string $userAgentString): array {
    $browser = "Unknown Browser";
    $platform = "Unknown OS";
    $device_type = "Unknown Device";

    if (empty($userAgentString)) {
        return ['browser' => $browser, 'platform' => $platform, 'device_type' => $device_type];
    }

    // Deteksi OS (Platform)
    if (preg_match('/linux/i', $userAgentString)) {
        $platform = 'Linux';
    } elseif (preg_match('/macintosh|mac os x|mac_powerpc/i', $userAgentString)) {
        $platform = 'Mac OS';
    } elseif (preg_match('/windows nt 10/i', $userAgentString)) {
        $platform = 'Windows 10';
    } elseif (preg_match('/windows nt 6.3/i', $userAgentString)) {
        $platform = 'Windows 8.1';
    } elseif (preg_match('/windows nt 6.2/i', $userAgentString)) {
        $platform = 'Windows 8';
    } elseif (preg_match('/windows nt 6.1|windows 7/i', $userAgentString)) {
        $platform = 'Windows 7';
    } elseif (preg_match('/windows nt 6.0/i', $userAgentString)) {
        $platform = 'Windows Vista';
    } elseif (preg_match('/windows nt 5.2/i', $userAgentString)) {
        $platform = 'Windows Server 2003/XP x64';
    } elseif (preg_match('/windows nt 5.1|windows xp/i', $userAgentString)) {
        $platform = 'Windows XP';
    } elseif (preg_match('/windows phone/i', $userAgentString)) {
        $platform = 'Windows Phone';
        $device_type = 'Mobile';
    } elseif (preg_match('/android/i', $userAgentString)) {
        $platform = 'Android';
        $device_type = 'Mobile';
    } elseif (preg_match('/iphone|ipad|ipod/i', $userAgentString)) {
        $platform = 'iOS';
        if (preg_match('/iphone/i', $userAgentString)) $device_type = 'Mobile';
        elseif (preg_match('/ipad/i', $userAgentString)) $device_type = 'Tablet';
        else $device_type = 'Mobile';
    }

    // Deteksi Browser
    if (preg_match('/msie/i', $userAgentString) && !preg_match('/opera/i', $userAgentString)) {
        $browser = 'Internet Explorer';
    } elseif (preg_match('/firefox/i', $userAgentString)) {
        $browser = 'Mozilla Firefox';
    } elseif (preg_match('/chrome/i', $userAgentString) && !preg_match('/edge/i', $userAgentString)) {
        $browser = 'Google Chrome';
    } elseif (preg_match('/safari/i', $userAgentString) && !preg_match('/chrome/i', $userAgentString)) {
        $browser = 'Apple Safari';
    } elseif (preg_match('/opera/i', $userAgentString)) {
        $browser = 'Opera';
    } elseif (preg_match('/edge/i', $userAgentString)) {
        $browser = 'Microsoft Edge';
    } elseif (preg_match('/trident/i', $userAgentString)) {
        $browser = 'Internet Explorer';
    }
    
    if ($device_type === "Unknown Device" && ($platform === "Linux" || strpos($platform, "Windows") !== false || $platform === "Mac OS")) {
        $device_type = "Desktop";
    }


    return ['browser' => $browser, 'platform' => $platform, 'device_type' => $device_type];
}


/**
 * Mencatat aktivitas login ke dalam tabel login_logs.
 *
 * @param PDO $pdo Objek koneksi PDO.
 * @param int|null $userId ID pengguna (null jika username tidak ditemukan atau login gagal karena username).
 * @param string $usernameAttempt Username yang digunakan saat mencoba login.
 * @param string $status Status login ('success', 'failed_password', 'failed_username').
 * @param string|null $locationInfo Informasi lokasi (opsional).
 * @return bool True jika berhasil mencatat, false jika gagal.
 */
function log_login_activity(
    PDO $pdo,
    ?int $userId,
    string $usernameAttempt,
    string $status,
    ?string $locationInfo = null
): bool {
    $ipAddress = get_client_ip(); 
    $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null;

    $agentInfo = parse_user_agent_basic($userAgent);
    $deviceType = $agentInfo['device_type'];
    $browserName = $agentInfo['browser'];
    $platformName = $agentInfo['platform'];

    $sql = "INSERT INTO login_logs (user_id, username_attempt, ip_address, user_agent, device_type, browser_name, platform_name, location_info, status, login_at)
            VALUES (:user_id, :username_attempt, :ip_address, :user_agent, :device_type, :browser_name, :platform_name, :location_info, :status, NOW())";
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->bindParam(':user_id', $userId, $userId === null ? PDO::PARAM_NULL : PDO::PARAM_INT);
        $stmt->bindParam(':username_attempt', $usernameAttempt);
        $stmt->bindParam(':ip_address', $ipAddress);
        $stmt->bindParam(':user_agent', $userAgent);
        $stmt->bindParam(':device_type', $deviceType);
        $stmt->bindParam(':browser_name', $browserName);
        $stmt->bindParam(':platform_name', $platformName);
        $stmt->bindParam(':location_info', $locationInfo); 
        $stmt->bindParam(':status', $status);
        return $stmt->execute();
    } catch (PDOException $e) {
        error_log("Failed to log login activity for username attempt {$usernameAttempt}: " . $e->getMessage());
        return false;
    }
}

if (!function_exists('get_client_ip')) {
    function get_client_ip() {
        $ipaddress = '';
        if (isset($_SERVER['HTTP_CLIENT_IP']))
            $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
        else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
            $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
        else if(isset($_SERVER['HTTP_X_FORWARDED']))
            $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
        else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
            $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
        else if(isset($_SERVER['HTTP_FORWARDED']))
            $ipaddress = $_SERVER['HTTP_FORWARDED'];
        else if(isset($_SERVER['REMOTE_ADDR']))
            $ipaddress = $_SERVER['REMOTE_ADDR'];
        else
            $ipaddress = 'UNKNOWN';
        if (strpos($ipaddress, ',') !== false) {
            $ipaddress = explode(',', $ipaddress)[0];
        }
        return trim($ipaddress);
    }
}

?>
