import path from "path";
import fs from "fs";
import { WorkDir } from "./config.js";

export const SECURITY_CONFIG_PATH = path.join(WorkDir, "config", "security.json");

const DEFAULT_ALLOW_LIST = [
    "cat",
    "curl",
    "date",
    "echo",
    "grep",
    "jq",
    "ls",
    "pwd",
    "yq",
    "whoami"
]

let cachedAllowList: string[] | null = null;
let cachedMtimeMs: number | null = null;

function ensureSecurityConfig() {
    if (!fs.existsSync(SECURITY_CONFIG_PATH)) {
        fs.writeFileSync(
            SECURITY_CONFIG_PATH,
            JSON.stringify(DEFAULT_ALLOW_LIST, null, 2) + "\n",
            "utf8",
        );
    }
}

function normalizeList(commands: unknown[]): string[] {
    const seen = new Set<string>();
    for (const entry of commands) {
        if (typeof entry !== "string") continue;
        const normalized = entry.trim().toLowerCase();
        if (!normalized) continue;
        seen.add(normalized);
    }

    return Array.from(seen);
}

function parseSecurityPayload(payload: unknown): string[] {
    if (Array.isArray(payload)) {
        return normalizeList(payload);
    }

    if (payload && typeof payload === "object") {
        const maybeObject = payload as Record<string, unknown>;
        if (Array.isArray(maybeObject.allowedCommands)) {
            return normalizeList(maybeObject.allowedCommands);
        }

        const dynamicList = Object.entries(maybeObject)
            .filter(([, value]) => Boolean(value))
            .map(([key]) => key);

        return normalizeList(dynamicList);
    }

    return [];
}

function readAllowList(): string[] {
    ensureSecurityConfig();

    try {
        const configContent = fs.readFileSync(SECURITY_CONFIG_PATH, "utf8");
        const parsed = JSON.parse(configContent);
        return parseSecurityPayload(parsed);
    } catch (error) {
        console.warn(`Failed to read security config at ${SECURITY_CONFIG_PATH}: ${error instanceof Error ? error.message : error}`);
        return DEFAULT_ALLOW_LIST;
    }
}

export function getSecurityAllowList(): string[] {
    ensureSecurityConfig();
    try {
        const stats = fs.statSync(SECURITY_CONFIG_PATH);
        if (cachedAllowList && cachedMtimeMs === stats.mtimeMs) {
            return cachedAllowList;
        }

        const allowList = readAllowList();
        cachedAllowList = allowList;
        cachedMtimeMs = stats.mtimeMs;
        return allowList;
    } catch {
        cachedAllowList = null;
        cachedMtimeMs = null;
        return readAllowList();
    }
}

export function resetSecurityAllowListCache() {
    cachedAllowList = null;
    cachedMtimeMs = null;
}
