import Database from "better-sqlite3";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));

export type BuildStatus =
  | "pending"
  | "queued"
  | "in_progress"
  | "completed"
  | "failed";

export interface BuildRecord {
  id: string;
  app_name: string;
  app_name_en: string;
  app_identifier: string;
  status: BuildStatus;
  workflow_run_id: number | null;
  windows_url: string | null;
  android_url: string | null;
  error: string | null;
  created_at: string;
  updated_at: string;
}

let db: Database.Database | null = null;

export function getDb(): Database.Database {
  if (db) return db;

  const dataDir = path.resolve(__dirname, "../../data");
  fs.mkdirSync(dataDir, { recursive: true });
  const dbPath = path.join(dataDir, "web2app.db");
  db = new Database(dbPath);
  const schema = fs.readFileSync(path.join(__dirname, "schema.sql"), "utf8");
  db.exec(schema);
  migrateBuildsTable(db);
  return db;
}

function migrateBuildsTable(database: Database.Database) {
  const columns = database
    .prepare("PRAGMA table_info(builds)")
    .all() as Array<{ name: string }>;

  if (!columns.some((column) => column.name === "app_name_en")) {
    database.exec("ALTER TABLE builds ADD COLUMN app_name_en TEXT NOT NULL DEFAULT ''");
  }
}

export function insertBuild(record: {
  id: string;
  appName: string;
  appNameEn: string;
  appIdentifier: string;
}): BuildRecord {
  const database = getDb();
  database
    .prepare(
      `INSERT INTO builds (id, app_name, app_name_en, app_identifier, status)
       VALUES (@id, @appName, @appNameEn, @appIdentifier, 'pending')`,
    )
    .run(record);

  return getBuild(record.id)!;
}

export function getBuild(id: string): BuildRecord | null {
  const row = getDb()
    .prepare("SELECT * FROM builds WHERE id = ?")
    .get(id) as BuildRecord | undefined;
  return row ?? null;
}

export function listBuilds(limit = 20): BuildRecord[] {
  return getDb()
    .prepare("SELECT * FROM builds ORDER BY created_at DESC LIMIT ?")
    .all(limit) as BuildRecord[];
}

export function updateBuild(
  id: string,
  patch: Partial<
    Pick<
      BuildRecord,
      | "status"
      | "workflow_run_id"
      | "windows_url"
      | "android_url"
      | "error"
    >
  >,
): BuildRecord | null {
  const fields: string[] = [];
  const params: Record<string, unknown> = { id };

  for (const [key, value] of Object.entries(patch)) {
    if (value !== undefined) {
      fields.push(`${key} = @${key}`);
      params[key] = value;
    }
  }

  if (fields.length === 0) return getBuild(id);

  fields.push("updated_at = datetime('now')");
  getDb()
    .prepare(`UPDATE builds SET ${fields.join(", ")} WHERE id = @id`)
    .run(params);

  return getBuild(id);
}

export function toPublicBuild(record: BuildRecord) {
  return {
    id: record.id,
    appName: record.app_name,
    appNameEn: record.app_name_en || record.app_name,
    appIdentifier: record.app_identifier,
    status: record.status,
    workflowRunId: record.workflow_run_id,
    windowsUrl: record.windows_url,
    androidUrl: record.android_url,
    error: record.error,
    createdAt: record.created_at,
    updatedAt: record.updated_at,
  };
}
