#!/usr/bin/env raku
# Rakuish —— 双语言 REPL / 脚本运行器
#
# 用法：
#   raku bin/rakuish                 # 交互式 REPL（需要 tty）
#   raku bin/rakuish run foo.rakuish  # 跑脚本
#   raku bin/rakuish foo.rakuish      # 同上（run 可省）
#   raku bin/rakuish --help
#
# shebang 用法（脚本首行，注意 `-S` 让 env 把后续参数一起传进来）：
#   #!/usr/bin/env -S rakuish run
# 或者直接把 rakuish 装成 PATH 上的可执行文件后写：
#   #!/usr/bin/env rakuish
# 两种情况脚本路径都是 argv[1]，所以「裸文件参数 = 脚本」这条必须留。
#
# 依赖：Prompt（REPL 的行编辑器 / TAB 补全）。**脚本模式不加载它**——
# 跑 CI 的机器上没必要为了一次批处理装行编辑器。
#
# 模块搜索路径按脚本自身位置推算，所以从任意目录调用都能找到 lib/。

use lib $?FILE.IO.dirname.IO.parent.add('lib');

my constant FALLBACK_VERSION = '0.17.4';   # 与 META6.json 同步（t/51 守护）


sub meta-fallback(--> Str) {
    # zef 安装后 bin 旁边没有 META6.json —— 退回分发元数据
    my $v = try { $?DISTRIBUTION.meta<version> };
    return $v.Str if $v.defined && $v.Str.chars;
    FALLBACK_VERSION;
}

sub meta-version(--> Str) {
    # 源码树里直接读 META6.json
    my $f = $?FILE.IO.dirname.IO.parent.add('META6.json');
    if $f.e {
        my $t = try { $f.slurp };
        if $t.defined && $t ~~ /'"version"' \s* ':' \s* '"' (<-["]>+) '"'/ {
            return $0.Str;
        }
    }
    # zef 安装后 bin 旁边没有 META6.json —— 退回分发元数据
    my $v = try { $?DISTRIBUTION.meta<version> };
    return $v.Str if $v.defined && $v.Str.chars;
    FALLBACK_VERSION;
}

sub usage(--> Nil) {
    say 'rakuish ' ~ meta-version();
    say '';
    say '用法：';
    say '  rakuish                    启动交互式 REPL（自动 fork daemon）';
    say '  rakuish --daemon | -D      仅启动后台 shell 引擎（给 REPL 用）';
    say '  rakuish --json              Agent 批处理：stdin→stdout JSON 行流（自动 daemon）';
    say '  rakuish run <脚本> [参数...]  运行脚本';
    say '  rakuish <脚本> [参数...]      运行脚本（run 可省）';
    say '  rakuish --help | -h         显示本帮助';
    say '  rakuish --version | -V      显示版本';
    say '';
    say '脚本里可以直接写 Raku 语句、!shell 行、%magic 命令，';
    say '与 REPL 共用同一套语义；区别是不打印 Out[n]、不猜外部命令。';
}

# ── 参数解析 ────────────────────────────────────────────────────────
# 把脚本路径与脚本参数从 @*ARGS 里摘出去，剩下的留在 @*ARGS 给脚本用
# （脚本内 `@*ARGS` 拿到的就是真正的脚本参数，不含脚本名本身）。
my $script;
my @rest = @*ARGS;

if @rest.elems {
    my $first = @rest[0].Str;
    if $first eq '--json' {
        # Agent batch mode — stdin 逐行命令 → stdout 逐行 JSON 结果
        # Engine 模块里有 run-daemon-loop + json-batch-loop，不需要 Loop/Prompt
        use Rakuish::Shell::Engine;
        exit json-batch-loop();
    }
    elsif $first eq '--daemon' or $first eq '-D' {
        # 后台 shell 引擎模式 —— 跑 Engine.rakumod 的 run-daemon-loop
        # 独立进程，由 REPL 自动拉起（start-daemon-if-needed）
        use Rakuish::Shell::Engine;
        run-daemon-loop();
        exit 0;
    }
    elsif $first eq '--help' or $first eq '-h' {
        usage();
        exit 0;
    }
    elsif $first eq '--version' or $first eq '-V' {
        say 'rakuish ' ~ meta-version();
        exit 0;
    }
    elsif $first eq 'run' or $first eq 'script' {
        @rest.shift;
        unless @rest.elems {
            $*ERR.say: 'rakuish: run 后面要跟脚本路径';
            exit 2;
        }
        $script = @rest.shift;
    }
    else {
        $script = @rest.shift;
    }
}

if $script.defined and $script ne q{} {
    # 脚本模式：@*ARGS 只剩脚本参数，供脚本内使用。
    use Rakuish::Loop;
    @*ARGS = @rest;
    exit run-script($script);
}


# ── 启动常驻 shell daemon（Phase 2：加速 !cmd 到 ~10ms）───────────
# 只在交互式 REPL 启用。脚本模式是一次性执行，不需要常驻。
# rakuish --daemon / -D 是同一个二进制的 daemon mode 分支 —— 这里
# 用 bash 后台化拉起它。启动失败不阻止 REPL（自动回退单次进程）。
use Rakuish::Shell::Engine;
try { start-daemon-if-needed };
END { try { stop-daemon } };

# ── 交互式 REPL ─────────────────────────────────────────────────────
use Rakuish::Loop;
try require Prompt;
if $! {
    $*ERR.say: q{rakuish: 找不到 Prompt 模块（行编辑器 / TAB 补全依赖它）。};
    $*ERR.say: q{          请先 `zef install Prompt` 再启动。};
    exit 1;
}

# 颜色、历史路径等参数写进 ~/.rakuishrc（key = value，见 %help），
# 由 run-loop 按「默认值 < rc < 环境变量」统一解析，这里不用再传参。
my $rc = run-loop();
exit $rc;
