import { readFile, stat } from "node:fs/promises";
import { join } from "node:path";
const APP_FACADE_PACKAGE = "@terajs/app";
const LEGACY_APP_FACADE_PACKAGE = "terajs";
/**
 * Inspects a project folder and reports common Terajs setup issues.
 */
export async function inspectTerajsProject(root) {
    const checks = [];
    const packagePath = join(root, "package.json");
    const packageExists = await fileExists(packagePath);
    checks.push({
        id: "package-json",
        label: "package.json exists",
        ok: packageExists,
        level: "error",
        details: packageExists ? packagePath : "Create package.json in the project root."
    });
    let manifest = null;
    if (packageExists) {
        manifest = await readPackageManifest(packagePath);
        const facadeVersion = dependencyValue(manifest, APP_FACADE_PACKAGE)
            ?? dependencyValue(manifest, LEGACY_APP_FACADE_PACKAGE);
        const hasFacade = facadeVersion !== undefined;
        if (hasFacade) {
            checks.push({
                id: "dep:app-facade",
                label: "default app package declared",
                ok: true,
                level: "error",
                details: `${dependencyValue(manifest, APP_FACADE_PACKAGE) !== undefined ? APP_FACADE_PACKAGE : LEGACY_APP_FACADE_PACKAGE}@${facadeVersion}`
            });
        }
        else {
            checks.push(checkDependency(manifest, "@terajs/runtime", "error"));
            checks.push(checkDependency(manifest, "@terajs/renderer-web", "error"));
            checks.push(checkDependency(manifest, "@terajs/vite-plugin", "error"));
            checks.push({
                id: "dep:app-facade",
                label: "default app package declared",
                ok: false,
                level: "warn",
                details: `Recommended: add ${APP_FACADE_PACKAGE} as the default app package for simplified setup.`
            });
        }
        checks.push(checkScript(manifest, "dev", "warn"));
        checks.push(checkScript(manifest, "build", "warn"));
    }
    const viteConfig = await findFirstExisting(root, [
        "vite.config.ts",
        "vite.config.js",
        "vite.config.mjs",
        "vite.config.cjs"
    ]);
    checks.push({
        id: "vite-config",
        label: "Vite config present",
        ok: viteConfig !== null,
        level: "error",
        details: viteConfig ?? "Add vite.config.ts or vite.config.js in the project root."
    });
    const terajsConfig = await findFirstExisting(root, [
        "terajs.config.cjs",
        "terajs.config.js"
    ]);
    checks.push({
        id: "terajs-config",
        label: "Terajs config present",
        ok: terajsConfig !== null,
        level: "warn",
        details: terajsConfig ?? "Add terajs.config.cjs to configure auto imports and route dirs."
    });
    const routeIndex = await findFirstExisting(root, [
        "src/routes/index.tera",
        "src/pages/index.tera"
    ]);
    checks.push({
        id: "route-entry",
        label: "Route entry file present",
        ok: routeIndex !== null,
        level: "warn",
        details: routeIndex ?? "Add src/routes/index.tera or src/pages/index.tera."
    });
    const hasBlockingIssue = checks.some((check) => !check.ok && check.level === "error");
    return {
        root,
        checks,
        ok: !hasBlockingIssue
    };
}
export function formatDoctorReport(report) {
    const lines = [
        `Terajs Doctor report for ${report.root}`,
        ""
    ];
    for (const check of report.checks) {
        const state = check.ok ? "OK" : check.level === "error" ? "FAIL" : "WARN";
        lines.push(`[${state}] ${check.label}`);
        lines.push(`  ${check.details}`);
    }
    lines.push("");
    lines.push(report.ok
        ? "Doctor summary: setup is ready for development."
        : "Doctor summary: fix FAIL items before continuing.");
    return lines.join("\n");
}
function checkDependency(manifest, depName, level) {
    const value = dependencyValue(manifest, depName);
    return {
        id: `dep:${depName}`,
        label: `${depName} dependency declared`,
        ok: typeof value === "string" && value.length > 0,
        level,
        details: value ? `${depName}@${value}` : `Add ${depName} to dependencies or devDependencies.`
    };
}
function dependencyValue(manifest, depName) {
    return manifest.dependencies?.[depName] ?? manifest.devDependencies?.[depName];
}
function checkScript(manifest, scriptName, level) {
    const value = manifest.scripts?.[scriptName];
    return {
        id: `script:${scriptName}`,
        label: `npm script '${scriptName}' exists`,
        ok: typeof value === "string" && value.length > 0,
        level,
        details: value ? `${scriptName}: ${value}` : `Add a '${scriptName}' script in package.json.`
    };
}
async function readPackageManifest(packagePath) {
    try {
        const raw = await readFile(packagePath, "utf8");
        return JSON.parse(raw);
    }
    catch {
        return {};
    }
}
async function findFirstExisting(root, relativePaths) {
    for (const relPath of relativePaths) {
        const fullPath = join(root, relPath);
        if (await fileExists(fullPath)) {
            return relPath;
        }
    }
    return null;
}
async function fileExists(path) {
    try {
        await stat(path);
        return true;
    }
    catch {
        return false;
    }
}
