import type { HealthCheck, HealthResult } from '@platform-modules/util/health'
import type { CacheBackend } from './index.js'

export interface CacheHealthOptions {
  /** Name surfaced in the `HealthResult` (default `'cache'`). */
  name?: string
  /** Probe key written then deleted (default `'__health_probe__'`). */
  key?: string
  /**
   * Probe-key TTL in whole seconds (default 30). Bounds the key so a failed
   * `del` cleanup self-expires rather than leaving a dangling key.
   */
  ttlSeconds?: number
}

/**
 * A set→get→del probe over any `CacheBackend`.
 *
 * Returns a `HealthCheck` whose `check()` NEVER throws — a backend failure becomes
 * `status:'down'` with a GENERIC `detail` (the raw error is swallowed; it can leak
 * connection/host detail — info-disclosure hard floor). A silent write-drop (read
 * back a value that does not match what was set) reports `status:'degraded'`.
 *
 * The probe key is written with a short TTL so a failed `del` self-expires.
 */
export function healthCheck(backend: CacheBackend, opts?: CacheHealthOptions): HealthCheck {
  const name = opts?.name ?? 'cache'
  const key = opts?.key ?? '__health_probe__'
  const ttlSeconds = opts?.ttlSeconds ?? 30
  return {
    name,
    async check(): Promise<HealthResult> {
      const start = Date.now()
      const token = `ok:${start}`
      try {
        await backend.set(key, token, ttlSeconds)
        const got = await backend.get(key)
        // Best-effort cleanup; a throw here is harmless — the TTL self-expires the key.
        try {
          await backend.del(key)
        } catch {
          /* self-expires via ttlSeconds */
        }
        if (got !== token) {
          return { name, status: 'degraded', detail: 'probe value mismatch', latencyMs: Date.now() - start }
        }
        return { name, status: 'ok', latencyMs: Date.now() - start }
      } catch {
        return { name, status: 'down', detail: 'probe failed', latencyMs: Date.now() - start }
      }
    },
  }
}
