// deno-lint-ignore-file no-explicit-any
import * as dntShim from "../../../_dnt.shims.js";
import { writeFileSync } from "node:fs";
import path from "node:path";
import process from "node:process";
import { isSuperset, parseFromFile, removeType, } from "../../types.js";
import { requireLogin } from "../../core/auth.js";
import { resolveWorkspace } from "../../core/context.js";
import { colors, Command, log, Table } from "../../../deps.js";
import * as wmill from "../../../gen/services.gen.js";
import { compileResourceTypeToTsType } from "../../utils/resource_types.js";
import { capitalize, toCamel } from "../../utils/utils.js";
export async function pushResourceType(workspace, remotePath, resource, localResource) {
    remotePath = removeType(remotePath, "resource-type");
    try {
        resource = await wmill.getResourceType({
            workspace: workspace,
            path: remotePath,
        });
    }
    catch {
        // resource type doesn't exist
    }
    if (resource) {
        if (isSuperset(localResource, resource)) {
            return;
        }
        await wmill.updateResourceType({
            workspace: workspace,
            path: remotePath,
            requestBody: {
                ...localResource,
            },
        });
    }
    else {
        log.info(colors.yellow.bold("Creating new resource type..."));
        await wmill.createResourceType({
            workspace: workspace,
            requestBody: {
                name: remotePath,
                ...localResource,
            },
        });
    }
}
async function push(opts, filePath, name) {
    const fstat = await dntShim.Deno.stat(filePath);
    if (!fstat.isFile) {
        throw new Error("file path must refer to a file.");
    }
    const workspace = await resolveWorkspace(opts);
    await requireLogin(opts);
    log.info(colors.bold.yellow("Pushing resource..."));
    await pushResourceType(workspace.workspaceId, name, undefined, parseFromFile(filePath));
    log.info(colors.bold.underline.green("Resource pushed"));
}
async function list(opts) {
    const workspace = await resolveWorkspace(opts);
    await requireLogin(opts);
    const res = await wmill.listResourceType({
        workspace: workspace.workspaceId,
    });
    if (opts.schema) {
        new Table()
            .header(["Workspace", "Name", "Schema"])
            .padding(2)
            .border(true)
            .body(res.map((x) => [
            x.workspace_id ?? "Global",
            x.name,
            JSON.stringify(x.schema, null, 2),
        ]))
            .render();
    }
    else {
        new Table()
            .header(["Workspace", "Name"])
            .padding(2)
            .border(true)
            .body(res.map((x) => [x.workspace_id ?? "Global", x.name]))
            .render();
    }
}
export async function generateRTNamespace(opts) {
    const workspace = await resolveWorkspace(opts);
    await requireLogin(opts);
    const rts = await wmill.listResourceType({
        workspace: workspace.workspaceId,
    });
    let namespaceContent = "declare namespace RT {\n";
    namespaceContent += rts
        .map((resourceType) => {
        return `  type ${toCamel(capitalize(resourceType.name))} = ${compileResourceTypeToTsType(resourceType.schema).replaceAll("\n", "\n  ")}`;
    })
        .join("\n\n");
    namespaceContent += "\n}";
    writeFileSync(path.join(process.cwd(), "rt.d.ts"), namespaceContent);
    log.info(colors.green("Created rt.d.ts with resource types namespace (RT) for TypeScript."));
}
const command = new Command()
    .description("resource type related commands")
    .action(() => log.info("2 actions available, list and push."))
    .command("list", "list all resource types")
    .option("--schema", "Show schema in the output")
    .action(list)
    .command("push", "push a local resource spec. This overrides any remote versions.")
    .arguments("<file_path:string> <name:string>")
    .action(push)
    .command("generate-namespace", "Create a TypeScript definition file with the RT namespace generated from the resource types")
    .action(generateRTNamespace);
export default command;
