import type { CliCommand } from "../types";
import { makeAppFromEnv } from "cli/commands/run";
import { writeFile } from "node:fs/promises";
import c from "picocolors";
import { withConfigOptions } from "cli/utils/options";

export const sync: CliCommand = (program) => {
   withConfigOptions(program.command("sync"))
      .description("sync database")
      .option("--force", "perform database syncing operations")
      .option("--seed", "perform seeding operations")
      .option("--drop", "include destructive DDL operations")
      .option("--out <file>", "output file")
      .option("--sql", "use sql output")
      .action(async (options) => {
         const app = await makeAppFromEnv(options);
         const schema = app.em.schema();
         console.info(c.dim("Checking database state..."));
         const stmts = await schema.sync({ drop: options.drop });

         console.info("");
         if (stmts.length === 0) {
            console.info(c.yellow("No changes to sync"));
            process.exit(0);
         }
         // @todo: currently assuming parameters aren't used
         const sql = stmts.map((d) => d.sql).join(";\n") + ";";

         if (options.force) {
            console.info(c.dim("Executing:") + "\n" + c.cyan(sql));
            await schema.sync({ force: true, drop: options.drop });

            console.info(`\n${c.dim(`Executed ${c.cyan(stmts.length)} statement(s)`)}`);
            console.info(`${c.green("Database synced")}`);

            if (options.seed) {
               console.info(c.dim("\nExecuting seed..."));
               const seed = app.options?.seed;
               if (seed) {
                  await app.options?.seed?.({
                     ...app.modules.ctx(),
                     app: app,
                  });
                  console.info(c.green("Seed executed"));
               } else {
                  console.info(c.yellow("No seed function provided"));
               }
            }
         } else {
            if (options.out) {
               const output = options.sql ? sql : JSON.stringify(stmts, null, 2);
               await writeFile(options.out, output);
               console.info(`SQL written to ${c.cyan(options.out)}`);
            } else {
               console.info(c.dim("DDL to execute:") + "\n" + c.cyan(sql));

               console.info(
                  c.yellow(
                     "\nNo statements have been executed. Use --force to perform database syncing operations",
                  ),
               );
            }
         }
         process.exit(0);
      });
};
