import fs from "node:fs/promises";
import path from "node:path";
import type { SchemaJson, Table } from "./schema.js";
import {
  renderCqlCreateTable,
  renderSqlCreateTable,
  renderSqlCreateView,
  renderSqlExtensions,
  renderTableConstraintsSql,
} from "./sql-render.js";

type SeedOptions = {
  sqlPath: string;
  cqlPath: string;
  ifNotExists: boolean;
};

export const writeSeedFiles = async (
  schemaJson: SchemaJson,
  options: SeedOptions,
): Promise<void> => {
  const schema = schemaJson.schema ?? [];
  const extensions = schemaJson.extensions ?? [];
  const tables = schema.filter(
    (table: Table) => table.table_type === "table" && table.table_schema === "public",
  );
  const views = schema.filter(
    (view: Table) => view.table_type === "view" && view.table_schema === "public",
  );
  const sqlLines: string[] = [];
  const cqlLines: string[] = [];
  for (const table of tables) {
    sqlLines.push(
      renderSqlCreateTable(table, table.table_schema ?? "public", options.ifNotExists),
    );
    cqlLines.push(renderCqlCreateTable(table));
  }
  await fs.writeFile(path.resolve(options.sqlPath), sqlLines.join("\n"), {
    encoding: "utf-8",
  });
  await fs.writeFile(path.resolve(options.cqlPath), cqlLines.join("\n"), {
    encoding: "utf-8",
  });
  const viewsSql = views
    .map((view) => renderSqlCreateView(view, view.table_schema ?? "public"))
    .join("\n");
  const extensionsSql = renderSqlExtensions(extensions);
  await fs.writeFile(path.resolve("views.sql"), viewsSql, { encoding: "utf-8" });
  await fs.writeFile(path.resolve("extensions.sql"), extensionsSql, {
    encoding: "utf-8",
  });
  console.log(
    `Wrote ${options.sqlPath}, ${options.cqlPath}, views.sql, extensions.sql`,
  );
};

export const writeConstraintsFiles = async (
  schemaJson: SchemaJson,
  baseConstraintsPath = "constraints.sql",
): Promise<void> => {
  const schema = schemaJson.schema ?? [];
  const tables = schema.filter(
    (table: Table) => table.table_type === "table" && table.table_schema === "public",
  );
  const nonFk: string[] = [];
  const fk: string[] = [];
  for (const table of tables) {
    const { nonFk: tableNonFk, fk: tableFk } = renderTableConstraintsSql(
      table,
      table.table_schema ?? "public",
    );
    nonFk.push(...tableNonFk);
    fk.push(...tableFk);
  }
  const write = (target: string, lines: string[]) =>
    fs.writeFile(
      path.resolve(target),
      `${lines.join("\n")}${lines.length ? "\n" : ""}`,
      { encoding: "utf-8" },
    );
  await write("constraints_nofk.sql", nonFk);
  await write("constraints_fk.sql", fk);
  await write(
    baseConstraintsPath,
    [...nonFk, ...fk].filter(Boolean),
  );
  console.log(`Wrote ${baseConstraintsPath}, constraints_nofk.sql, constraints_fk.sql`);
};
