import { Application, Router } from "jsr:@oak/oak";
import { parseArgs } from "jsr:@std/cli/parse-args";
import { Runtime } from "./runtime.ts";
import * as compiler from "../compiler/mod.ts";

const port = 8000;

const flags = parseArgs(Deno.args, {
    boolean: ["flame-graph", "code-coverage"],
});

if (flags._.length !== 1) {
    throw new Error("please specify a filename");
}

//

const filepath = flags._[0] as string;
const text = await Deno.readTextFile(filepath);

const runtime = new Runtime(13370);

async function runProgramWithDebug(program: number[]) {
    const connection = await runtime.connect();
    connection.send({
        type: "run-debug",
        program,
    });
    const res = await connection.receive<{
        ok: boolean;
    }>();
    connection.close();
    if (!res.ok) {
        throw new Error("could not run code");
    }
}

const { program, fnNames } = await compiler.compileWithDebug(filepath);
await runProgramWithDebug(program);

//

const router = new Router();

router.get("/api/source", (ctx) => {
    ctx.response.body = { ok: true, filepath, text };
    ctx.response.status = 200;
    ctx.respond = true;
});

router.get("/api/status", async (ctx) => {
    const connection = await runtime.connect();
    connection.send({ type: "status" });
    const res = await connection.receive<{
        ok: boolean;
        status: { running: boolean };
    }>();
    connection.close();
    if (!res.ok) {
        ctx.response.body = { ok: false };
        ctx.response.status = 500;
        ctx.respond = true;
        return;
    }
    ctx.response.body = { ok: true, status: res.status };
    ctx.response.status = 200;
    ctx.respond = true;
});

router.get("/api/flame-graph", async (ctx) => {
    const connection = await runtime.connect();
    connection.send({ type: "flame-graph" });
    const res = await connection.receive<{
        ok: boolean;
        flameGraph: string;
    }>();
    connection.close();
    if (!res.ok) {
        ctx.response.body = { ok: false };
        ctx.response.status = 500;
        ctx.respond = true;
        return;
    }
    ctx.response.body = { ok: true, flameGraph: res.flameGraph };
    ctx.response.status = 200;
    ctx.respond = true;
});

router.get("/api/flame-graph-fn-names", (ctx) => {
    ctx.response.body = { ok: true, fnNames };
    ctx.response.status = 200;
    ctx.respond = true;
});

router.get("/api/code-coverage", async (ctx) => {
    const connection = await runtime.connect();
    connection.send({ type: "code-coverage" });
    const res = await connection.receive<{
        ok: boolean;
        codeCoverage: string;
    }>();
    connection.close();
    if (!res.ok) {
        ctx.response.body = { ok: false };
        ctx.response.status = 500;
        ctx.respond = true;
        return;
    }
    ctx.response.body = { ok: true, codeCoverage: res.codeCoverage };
    ctx.response.status = 200;
    ctx.respond = true;
});

//

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());
app.use(async (ctx, next) => {
    try {
        await ctx.send({ root: "./public", index: "index.html" });
    } catch {
        next();
    }
});
const listener = app.listen({ port });
console.log(`Devtools at http://localhost:${port}/`);
await listener;
