import { createNodeSqliteKysely, createCoercionPlugin } from '@pikku/kysely-node-sqlite'
import { createDbUtils, type StubTracker } from '@pikku/cucumber'
import { createConfig } from '../../../src/config.js'
import { createSingletonServices } from '../../../src/services.js'
import { coercionMap } from '../../../.pikku/db/coercion.gen.js'
import type { DB } from '../../../.pikku/db/schema.js'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'

const __dirname = dirname(fileURLToPath(import.meta.url))
const repoRoot = (p: string) => resolve(__dirname, '../../../../..', p)

export const db = createDbUtils({
  migrationsDir: repoRoot('db/migrations'),
  seedFile: repoRoot('db/seed.sql'),
})

type StubKysely = ReturnType<typeof createNodeSqliteKysely<DB>>

const REAL_SERVICES = (kysely: StubKysely) => ({ kysely })

export async function createStubServices(dbFile: string, tracker: StubTracker) {
  const kysely = createNodeSqliteKysely<DB>({
    filename: dbFile,
    camelCase: true,
    plugins: [createCoercionPlugin({ map: coercionMap })],
  })

  const real = REAL_SERVICES(kysely)
  const injected = new Proxy(real as Record<string, unknown>, {
    get(target, prop: string) {
      if (prop in target) return target[prop]
      return tracker.stub(prop)
    },
  })

  const config = await createConfig()
  const services = await createSingletonServices(
    { ...config, dev: { db: { file: dbFile } } } as never,
    injected as never,
  )

  return { services, kysely }
}
