/**
 * SQL rendering shared by adapters and the migration runner. Column types are
 * dialect-neutral in the model; this maps them to each dialect's SQL types and
 * renders `CREATE TABLE`. (Postgres/MySQL land in later phases; the mappings are
 * here so the model layer is already portable.)
 */

import type { ColumnDef, Model } from "./schema.ts";

export type Dialect = "sqlite" | "postgres" | "mysql";

function sqlType(def: ColumnDef, dialect: Dialect): string {
  if (def.type === "id") {
    if (dialect === "postgres") return "SERIAL";
    if (dialect === "mysql") return "INT AUTO_INCREMENT";
    return "INTEGER";
  }
  switch (def.type) {
    case "int":
      return "INTEGER";
    case "real":
      return dialect === "mysql" ? "DOUBLE" : "REAL";
    case "bool":
      return dialect === "postgres" ? "BOOLEAN" : "INTEGER";
    case "timestamp":
      return dialect === "sqlite" ? "TEXT" : "TIMESTAMP";
    case "json":
      return dialect === "postgres" ? "JSONB" : "TEXT";
    default:
      return dialect === "mysql" ? "VARCHAR(255)" : "TEXT";
  }
}

function quoteId(id: string, dialect: Dialect): string {
  return dialect === "mysql" ? `\`${id}\`` : `"${id}"`;
}

function renderDefault(value: unknown, dialect: Dialect): string {
  if (value === "now") return "CURRENT_TIMESTAMP";
  if (typeof value === "number") return String(value);
  if (typeof value === "boolean") return dialect === "postgres" ? String(value) : value ? "1" : "0";
  return `'${String(value).replace(/'/g, "''")}'`;
}

/** Render `CREATE TABLE` for a model in the given dialect. */
export function createTableSql(model: Model, dialect: Dialect, ifNotExists = true): string {
  const cols: string[] = [];
  for (const [name, column] of Object.entries(model.columns)) {
    const def = column.def;
    const parts = [quoteId(name, dialect), sqlType(def, dialect)];
    if (def.primaryKey) {
      parts.push(
        dialect === "sqlite" && def.type === "id" ? "PRIMARY KEY AUTOINCREMENT" : "PRIMARY KEY",
      );
    }
    if (def.notNull && !def.primaryKey) parts.push("NOT NULL");
    if (def.unique && !def.primaryKey) parts.push("UNIQUE");
    if (def.default !== undefined) parts.push(`DEFAULT ${renderDefault(def.default, dialect)}`);
    if (def.references) {
      parts.push(
        `REFERENCES ${quoteId(def.references.table, dialect)}(${quoteId(def.references.column, dialect)})`,
      );
    }
    cols.push("  " + parts.join(" "));
  }
  const head = `CREATE TABLE ${ifNotExists ? "IF NOT EXISTS " : ""}${quoteId(model.name, dialect)}`;
  return `${head} (\n${cols.join(",\n")}\n);`;
}
