import { createNodeSqliteKysely } 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 type { DB } from '../../../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,
  })

  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 base = await createSingletonServices(
    { ...config, sqliteDb: dbFile } as never,
    injected as never,
  )

  // Spreading a Proxy loses non-enumerable stubs; wrap the result so any
  // service not explicitly provided falls through to the tracker stub.
  const services = new Proxy(base as Record<string, unknown>, {
    get(target, prop: string) {
      if (prop in target && target[prop] !== undefined) return target[prop]
      return tracker.stub(prop)
    },
  })

  return { services: services as typeof base, kysely }
}
