function toPascal(name: string): string {
  return name.charAt(0).toUpperCase() + name.slice(1);
}

const templates = {
  command: {
    render: (name: string) => {
      const inputType = `${toPascal(name)}Input`;
      return `import type { Transaction } from "../generated/kysely-tailordb";
import { ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export interface ${inputType} {
  // TODO: define input fields
}

export async function run(db: Transaction, input: ${inputType}, ctx: CommandContext) {
  // TODO: implement
  return ok({});
}
`;
    },
  },
  commandTest: {
    render: (name: string) => {
      const pascal = toPascal(name);
      return `import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import { run, ${pascal}Input } from "./${name}";
import type { CommandContext } from "@tailor-platform/erp-kit/module";

describe("${name} - test scenario", () => {
  const ctx: CommandContext = {
    actorId: "test-actor",
    permissions: ["TODO:${name}"],
  };

  it("should be implemented", async () => {
    const { db } = createMockDb<Transaction>();
    const result = await run(db, {} as ${pascal}Input, ctx);
    expect(result.ok).toBe(true);
  });
});
`;
    },
  },
  query: {
    render: (name: string) => {
      const inputType = `${toPascal(name)}Input`;
      return `import type { DB } from "../generated/kysely-tailordb";
import type { ReadonlyDB } from "@tailor-platform/erp-kit/module";

export interface ${inputType} {
  // TODO: define input fields
}

export async function run(db: ReadonlyDB<DB>, input: ${inputType}) {
  // TODO: implement
  return {};
}
`;
    },
  },
  queryTest: {
    render: (name: string) => {
      const pascal = toPascal(name);
      const inputType = `${pascal}Input`;
      return `import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { DB } from "../generated/kysely-tailordb";
import { run, type ${inputType} } from "./${name}";

describe("${name}", () => {
  it("should be implemented", async () => {
    const { db } = createMockDb<DB>();
    const result = await run(db, {} as ${inputType});
    expect(result).toBeDefined();
  });
});
`;
    },
  },
  db: {
    render: (name: string) => {
      return `import { db, unsafeAllowAllGqlPermission, unsafeAllowAllTypePermission } from "@tailor-platform/sdk";

export const ${name} = db
  .type("${toPascal(name)}", {
    // TODO: define fields
    ...db.fields.timestamps(),
  })
  .permission(unsafeAllowAllTypePermission)
  .gqlPermission(unsafeAllowAllGqlPermission);
`;
    },
  },
  resolver: {
    render: (name: string) => {
      return `import { createResolver, t } from "@tailor-platform/sdk";
import { createContext } from "@tailor-platform/erp-kit/app";
import { getDB } from "@/generated/kysely-tailordb";

export default createResolver({
  name: "${name}",
  operation: "mutation",
  input: {
    // TODO: define input fields
  },
  body: async (context) => {
    const db = getDB("main-db");
    return db.transaction().execute(async (trx) => {
      // TODO: implement
      return {};
    });
  },
  output: t
    .object({
      // TODO: define output fields
    })
    .description("${toPascal(name)} response"),
});
`;
    },
  },
  storyTest: {
    render: (name: string, testCases: string[]) => {
      const its = testCases
        .map((tc) => `  it("${tc}", async () => {\n    // TODO: implement\n  });`)
        .join("\n\n");
      return `import { describe, expect, inject, it } from "vitest";
import { createGraphQLClient } from "@/tests/utils/graphql-client";

describe("${name}", () => {
  const graphQLClient = createGraphQLClient(inject("url"), inject("token"));

${its}
});
`;
    },
  },
} as const;

export type StubType = keyof typeof templates;

export function renderStub(type: "storyTest", name: string, testCases: string[]): string;
export function renderStub(type: Exclude<StubType, "storyTest">, name: string): string;
export function renderStub(type: StubType, name: string, testCases?: string[]): string {
  if (type === "storyTest") {
    return templates.storyTest.render(name, testCases!);
  }
  return templates[type].render(name);
}
