package tech.easyflow.agent.config;

import com.easyagents.agent.runtime.tool.operate.ControlledShellTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

/**
 * 在应用启动后报告受控 Shell 固定白名单命令的实际可用性。
 */
@Component
public class AgentShellCommandAvailabilityReporter {

    private static final Logger LOG = LoggerFactory.getLogger(AgentShellCommandAvailabilityReporter.class);

    /**
     * 检查当前进程 PATH，并报告已安装与缺失的白名单命令。
     *
     * @param event 应用就绪事件
     */
    @EventListener(ApplicationReadyEvent.class)
    public void report(ApplicationReadyEvent event) {
        List<String> available = new ArrayList<>();
        List<String> missing = new ArrayList<>();
        for (String command : ControlledShellTool.DEFAULT_ALLOWED_COMMANDS.stream().sorted().toList()) {
            (isAvailable(command) ? available : missing).add(command);
        }
        LOG.info("Agent controlled Shell allowlist check completed, available={}", available);
        if (!missing.isEmpty()) {
            LOG.warn("Agent controlled Shell commands are unavailable in this runtime: {}", missing);
        }
    }

    /**
     * 判断一个不含路径分隔符的固定命令是否存在于当前 PATH。
     *
     * @param command 固定白名单命令
     * @return 存在可执行普通文件时为 true
     */
    private boolean isAvailable(String command) {
        String pathValue = System.getenv("PATH");
        if (pathValue == null || pathValue.isBlank()) {
            return false;
        }
        for (String directory : pathValue.split(java.io.File.pathSeparator)) {
            if (directory == null || directory.isBlank()) {
                continue;
            }
            try {
                Path executable = Path.of(directory).resolve(command);
                if (Files.isRegularFile(executable) && Files.isExecutable(executable)) {
                    return true;
                }
            } catch (InvalidPathException ignored) {
                // PATH 中的无效目录仅视为不可用，避免把宿主路径写入普通日志。
            }
        }
        return false;
    }
}
