import { drizzle } from 'drizzle-orm/d1'
import type { DrizzleD1Database } from 'drizzle-orm/d1'
import type { SQLWrapper } from 'drizzle-orm'
import type { Schema, SQLiteTransactionalDatabase } from './types.js'

/**
 * D1Database binding type from Cloudflare Workers runtime.
 * Typed as unknown here to avoid requiring @cloudflare/workers-types as a dep.
 * The host provides the typed binding; we just pass it to drizzle.
 */
export type D1Binding = unknown

export interface D1ClientOptions<S extends Schema> {
  schema?: S
}

/**
 * Create a D1 database client.
 * D1 transactions use IMMEDIATE mode (no mid-tx lock escalation).
 *
 * @param binding - D1Database binding from Cloudflare Workers env
 */
export function createD1Client<S extends Schema = Record<string, never>>(
  binding: D1Binding,
  opts: D1ClientOptions<S> = {}
): SQLiteTransactionalDatabase<S> {
  const db = drizzle(binding as Parameters<typeof drizzle>[0], { schema: opts.schema })
  // drizzle-orm/d1 exposes raw-SQL execution as `.run()`/`.all()`, not `.execute()` (that's
  // the Postgres-shaped drizzle API). Postgres's `.execute()` returns result rows (callers rely
  // on this for `RETURNING`, e.g. claimInstall's atomic lease) — `.run()` returns D1's raw
  // {success,meta} envelope with no rows, so it must be `.all()` here, not `.run()`.
  const withExecute = Object.assign(db, {
    execute: (query: SQLWrapper) => db.all(query),
  })
  return withExecute as unknown as SQLiteTransactionalDatabase<S>
}

export type { DrizzleD1Database }
