<?php
// 应用公共文件
use app\service\DictionaryService;
use app\service\file\FilesystemService;
use Hashids\Hashids;
use think\Collection;
use think\facade\Event;
use think\Model;


/**
 * @return FilesystemService
 */
function filesystem(): FilesystemService
{
    return app()->filesystem;
}

/**
 * 写入日志
 * @param array|string $event
 * @param string $message
 * @param mixed|null $data
 * @return void
 */
function security_log_record(array|string $event, string $message, mixed $data = null): void
{
    if (is_string($event)) {
        $event = explode('.', $event);
    }
    if ($data instanceof Model) {
        $data = $data->toArray();
    }
    if ($data instanceof Collection) {
        $data = $data->toArray();
    }

    Event::trigger('sys:securityLogRecord', [$event, $message, $data]);
}


/**
 * 获取字典内容
 * @param string $name
 * @param $default
 * @return mixed
 */
function dict_get(string $name, $default = null): mixed
{
    return dict()->get($name, $default);
}

/**
 * 获取字典服务
 * @return DictionaryService
 */
function dict(): DictionaryService
{
    return app()->dict;
}

/**
 * 将扁平数组列表转换为树形结构
 * @param array $items 原始数组
 * @param string $idKey ID字段名
 * @param string $parentKey 父ID字段名
 * @param string $childrenKey 子节点字段名
 * @return array 树形结构
 */
function list_build_tree(array $items, string $idKey = 'id', string $parentKey = 'pid', string $childrenKey = 'children'): array
{
    // 创建ID映射和结果树
    $tree = [];
    $map = [];

    // 创建ID到数组元素的引用映射
    foreach ($items as &$item) {
        $map[$item[$idKey]] = &$item;
        $item[$childrenKey] = []; // 初始化children
    }

    // 构建树结构
    foreach ($items as &$item) {
        $parentId = $item[$parentKey];

        if (isset($map[$parentId])) {
            // 当前项有父节点，添加到父节点的children
            $map[$parentId][$childrenKey][] = &$item;
        } else {
            // 当前项是根节点，添加到树
            $tree[] = &$item;
        }
    }

    // 清理引用
    unset($item);

    return $tree;
}


/**
 * @param int $minHashLength
 * @return Hashids
 */
function hashids(int $minHashLength = 6): Hashids
{
    $salt = (string)config('app.default_salt', '');
    return new Hashids($salt, $minHashLength);
}

function snowflake_id(int $machineId = null): int
{
    // 时间戳 42字节
    $time = floor(microtime(true) * 1000);
    // 当前时间 与 开始时间 差值
    $time -= 1641862815726;
    $base = decbin(1099511627775 + $time);
    if ($machineId) {
        $machineId = str_pad(decbin($machineId), 10, '0', STR_PAD_LEFT);
    }
    $random = str_pad(decbin(mt_rand(0, 4095)), 12, '0', STR_PAD_LEFT);
    return bindec($base . $machineId . $random);
}

function guid($namespace = ''): string
{

    $uid = uniqid("", true);
    $data = $namespace;
    $data .= $_SERVER['REQUEST_TIME'] ?? '';
    $data .= $_SERVER['HTTP_USER_AGENT'] ?? '';
    $data .= $_SERVER['LOCAL_ADDR'] ?? '';
    $data .= $_SERVER['LOCAL_PORT'] ?? '';
    $data .= $_SERVER['REMOTE_ADDR'] ?? '';
    $data .= $_SERVER['REMOTE_PORT'] ?? '';
    $hash = strtoupper(hash('ripemd128', $uid . md5($data)));
    return
        substr($hash, 0, 8) .
        '-' .
        substr($hash, 8, 4) .
        '-' .
        substr($hash, 12, 4) .
        '-' .
        substr($hash, 16, 4) .
        '-' .
        substr($hash, 20, 12);
}

function unique_str(): string
{
    return md5(uniqid());
}

function get_agent_browser($userAgent = ''): string
{
    if (str_contains($userAgent, 'MicroMessenger')) {
        return 'Wechat';
    } elseif (str_contains($userAgent, 'QQBrowser')) {
        return 'QQ';
    } elseif (str_contains($userAgent, 'MSIE') || str_contains($userAgent, 'Trident/7.0;') || str_contains($userAgent, 'rv:11.0')) {
        return 'Explorer';
    } elseif (str_contains($userAgent, 'Firefox')) {
        return 'Firefox';
    } elseif (str_contains($userAgent, 'Edg')) {
        return 'Edge';
    } elseif (str_contains($userAgent, 'Chrome')) {
        return 'Chrome';
    } elseif (str_contains($userAgent, 'Safari')) {
        return 'Safari';
    } elseif (str_contains($userAgent, 'Opera Mini') || str_contains($userAgent, 'Opera')) {
        return 'Opera';
    } else {
        return 'Unknown';
    }
}

function get_agent_device($agent = ''): string
{
    if (stristr($agent, 'iPad')) {
        $fb_fs = "iPad";
    } else if (preg_match('/Android (([0-9_.]{1,3})+)/i', $agent, $version)) {
        $fb_fs = "手机(Android " . $version[1] . ")";
    } else if (stristr($agent, 'Linux')) {
        $fb_fs = "电脑(Linux)";
    } else if (preg_match('/iPhone OS (([0-9_.]{1,3})+)/i', $agent, $version)) {
        $fb_fs = "手机(iPhone " . $version[1] . ")";
    } else if (preg_match('/Mac OS X (([0-9_.]{1,5})+)/i', $agent, $version)) {
        $fb_fs = "电脑(OS X " . $version[1] . ")";
    } else if (preg_match('/unix/i', $agent)) {
        $fb_fs = "Unix";
    } else if (preg_match('/windows/i', $agent)) {
        $fb_fs = "电脑(Windows)";
    } else {
        $fb_fs = "Unknown";
    }
    return $fb_fs;
}

function get_agent_os($userAgent): string
{
    if (preg_match('/windows/i', $userAgent)) {
        return 'Windows';
    } elseif (preg_match('/iPhone/i', $userAgent)) {
        return 'iOS';
    } elseif (preg_match('/HarmonyOS/i', $userAgent)) {
        return 'Android';
    } elseif (preg_match('/Android/i', $userAgent)) {
        return 'Android';
    } elseif (preg_match('/mac/i', $userAgent)) {
        return 'Mac';
    } else {
        return 'Unknown';
    }
}

function agent_is_crawler($userAgent): bool
{
    $crawlers = [
        'googlebot', 'bingbot', 'slurp', 'baidu', 'duckduckbot',
        'yandexbot', 'sogou', 'exabot', 'ia_archiver', 'facebot',
        'facebookexternalhit'
    ];

    foreach ($crawlers as $crawler) {
        if (str_contains($userAgent, $crawler)) {
            return true;
        }
    }
    return false;
}
