import * as $p from "@clack/prompts";
import { overrideJson } from "cli/commands/create/npm";
import { typewriter } from "cli/utils/cli";
import c from "picocolors";
import type { Template, TemplateSetupCtx } from ".";
import { exec } from "cli/utils/sys";

const WRANGLER_FILE = "wrangler.json";

export const cloudflare = {
   key: "cloudflare",
   title: "Cloudflare Basic",
   integration: "cloudflare",
   description: "A basic bknd Cloudflare worker",
   path: "gh:bknd-io/bknd/examples/cloudflare-worker",
   ref: true,
   setup: async (ctx) => {
      // overwrite assets directory & name
      await overrideJson(
         WRANGLER_FILE,
         (json) => ({
            ...json,
            name: ctx.name,
            assets: {
               directory: "node_modules/bknd/dist/static",
            },
         }),
         { dir: ctx.dir },
      );

      try {
         await createD1(ctx);
      } catch (e) {
         const message = (e as any).message || "An error occurred";
         $p.log.warn(
            "Couldn't add database. You can add it manually later. Error: " + c.red(message),
         );
      }

      try {
         await createR2(ctx);
      } catch (e) {
         const message = (e as any).message || "An error occurred";
         $p.log.warn(
            "Couldn't add R2 bucket. You can add it manually later. Error: " + c.red(message),
         );
      }
   },
} as const satisfies Template;

async function createD1(ctx: TemplateSetupCtx) {
   const default_db = "data";
   const name = ctx.skip
      ? default_db
      : await $p.text({
           message: "Enter database name",
           initialValue: default_db,
           placeholder: default_db,
           validate: (v) => {
              if (!v) {
                 return "Invalid name";
              }
              return;
           },
        });
   if ($p.isCancel(name)) {
      process.exit(1);
   }

   await $p.stream.info(
      (async function* () {
         yield* typewriter("Now running wrangler to create a D1 database...");
      })(),
   );

   await overrideJson(
      WRANGLER_FILE,
      (json) => ({
         ...json,
         d1_databases: [
            {
               binding: "DB",
               database_name: name,
               database_id: "00000000-0000-0000-0000-000000000000",
            },
         ],
      }),
      { dir: ctx.dir },
   );

   if (!ctx.skip) {
      exec(`npx wrangler d1 create ${name}`);

      await $p.stream.info(
         (async function* () {
            yield* typewriter("Please update your wrangler configuration with the output above.");
         })(),
      );
   }
}

async function createR2(ctx: TemplateSetupCtx) {
   const create = ctx.skip
      ? false
      : await $p.confirm({
           message: "Do you want to use a R2 bucket?",
           initialValue: true,
        });
   if ($p.isCancel(create)) {
      process.exit(1);
   }

   if (!create) {
      await overrideJson(
         WRANGLER_FILE,
         (json) => ({
            ...json,
            r2_buckets: undefined,
         }),
         { dir: ctx.dir },
      );
      return;
   }

   const default_bucket = "bucket";
   const name = ctx.skip
      ? default_bucket
      : await $p.text({
           message: "Enter bucket name",
           initialValue: default_bucket,
           placeholder: default_bucket,
           validate: (v) => {
              if (!v) {
                 return "Invalid name";
              }
              return;
           },
        });
   if ($p.isCancel(name)) {
      process.exit(1);
   }

   await $p.stream.info(
      (async function* () {
         yield* typewriter("Now running wrangler to create a R2 bucket...");
      })(),
   );

   await overrideJson(
      WRANGLER_FILE,
      (json) => ({
         ...json,
         r2_buckets: [
            {
               binding: "BUCKET",
               bucket_name: name,
            },
         ],
      }),
      { dir: ctx.dir },
   );

   if (!ctx.skip) {
      exec(`npx wrangler r2 bucket create ${name}`);
   }
}
