import {
  JsonConsoleLogger,
  LocalSecretService,
  LocalVariablesService,
} from '@pikku/core/services'
import { pikkuServices } from '../.pikku/pikku-types.gen.js'
import { CFWorkerSchemaService } from '@pikku/schema-cfworker'
import { LibsqlWebDialect } from '@pikku/kysely-sqlite'
import { Kysely, CamelCasePlugin } from 'kysely'
import { LocalBrowserService } from '@pikku/browser'
import type { DB } from './types/db.types.js'
import './wire-services.js'

export const createSingletonServices = pikkuServices(async (
  config,
  existingServices,
) => {
  const variables =
    existingServices?.variables ?? new LocalVariablesService()
  const secrets =
    existingServices?.secrets ?? new LocalSecretService(variables)
  const logger = existingServices?.logger ?? new JsonConsoleLogger()
  const schema =
    existingServices?.schema ?? new CFWorkerSchemaService(logger)

  let kysely = existingServices?.kysely as Kysely<DB> | undefined
  if (!kysely) {
    const databaseUrl = await variables.get('DATABASE_URL')
    if (!databaseUrl) {
      throw new Error(
        'DATABASE_URL not set — in dev, enable `dev.db` in your pikku config; in prod, Fabric injects DATABASE_URL',
      )
    }
    kysely = new Kysely<DB>({
      dialect: new LibsqlWebDialect({ url: databaseUrl }),
      plugins: [new CamelCasePlugin()],
    })
  }

  const content = existingServices?.content
  // On CF the browserContributor injects a Cloudflare Browser Rendering-backed
  // service; locally/sandbox/server we fall back to the node-puppeteer pool.
  const browser =
    existingServices?.browser ?? new LocalBrowserService({ logger })

  return {
    ...(existingServices ?? {}),
    config,
    variables,
    secrets,
    logger,
    schema,
    kysely,
    content,
    browser,
  }
})
