<?php
/**
 * data/ 内の相対パスを実ファイルパスへ解決
 */
function fl_normalize_relative(string $relative, string $base): string
{
    $relative = trim(str_replace('\\', '/', $relative), '/');
    $mountName = basename($base);

    if ($relative === '' || $relative === $mountName) {
        return '';
    }

    if (strpos($relative, $mountName . '/') === 0) {
        return substr($relative, strlen($mountName) + 1);
    }

    return $relative;
}

function fl_path_is_under_base(string $full, string $base): bool
{
    $fullPath = realpath($full);
    $basePath = realpath($base);

    if ($fullPath === false || $basePath === false) {
        return false;
    }

    $norm = static function (string $p): string {
        return strtolower(str_replace('\\', '/', $p));
    };

    $f = $norm($fullPath);
    $b = $norm($basePath);

    if ($f === $b) {
        return true;
    }

    return strpos($f, $b . '/') === 0;
}

function fl_resolve_path_case_insensitive(string $sub, string $base)
{
    $current = realpath($base);
    if ($current === false) {
        return false;
    }

    if ($sub === '') {
        return $current;
    }

    $parts = explode('/', str_replace('\\', '/', $sub));

    foreach ($parts as $part) {
        if ($part === '' || $part === '.') {
            continue;
        }

        if (!is_dir($current)) {
            return false;
        }

        $match = null;
        $items = @scandir($current);

        if ($items === false) {
            return false;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }
            if (strcasecmp($item, $part) === 0) {
                $match = $current . DIRECTORY_SEPARATOR . $item;
                break;
            }
        }

        if ($match === null) {
            return false;
        }

        $current = realpath($match) ?: $match;
    }

    if (!fl_path_is_under_base($current, $base)) {
        return false;
    }

    return $current;
}

function fl_resolve_path(string $relative, string $base)
{
    $sub = fl_normalize_relative($relative, $base);

    if ($sub === '') {
        return realpath($base) ?: false;
    }

    $full = realpath($base . '/' . $sub);

    if ($full !== false && fl_path_is_under_base($full, $base)) {
        return $full;
    }

    return fl_resolve_path_case_insensitive($sub, $base);
}

function fl_relative_for_client(string $absolute, string $base): string
{
    $full = str_replace('\\', '/', realpath($absolute) ?: $absolute);
    $root = str_replace('\\', '/', realpath($base) ?: $base);

    if (strpos($full, $root . '/') === 0) {
        return substr($full, strlen($root) + 1);
    }

    return basename($full);
}
