import { Injectable, ServiceUnavailableException } from '@nestjs/common';
import type { HealthResponse } from '@ali-ismail/contracts';
import { PrismaService } from './prisma/prisma.service';

@Injectable()
export class HealthService {
  constructor(private readonly prisma: PrismaService) {}

  getHealth(): HealthResponse {
    return {
      status: 'ok',
      service: 'ali-ismail-api',
      timestamp: new Date().toISOString(),
      version: '0.0.0-phase0',
    };
  }

  /**
   * Readiness distinguishes "process up" from "database reachable" (§27V).
   * The DB ping is bounded so a hung connection cannot hang the probe.
   * Returns no infrastructure details beyond an up/down flag and latency.
   */
  private lastReadiness: { at: number; result: object } | null = null;

  async getReadiness() {
    // Probe throttle: this is a public endpoint hitting the DB; cache the
    // result for 2s so a probe flood cannot occupy the connection pool.
    if (this.lastReadiness && Date.now() - this.lastReadiness.at < 2000) {
      return this.lastReadiness.result;
    }
    const startedAt = Date.now();
    try {
      await Promise.race([
        this.prisma.$queryRaw`SELECT 1`,
        new Promise((_, reject) =>
          setTimeout(() => reject(new Error('db ping timeout')), 5000),
        ),
      ]);
      const result = {
        status: 'ready',
        database: 'up',
        dbLatencyMs: Date.now() - startedAt,
        timestamp: new Date().toISOString(),
      };
      this.lastReadiness = { at: Date.now(), result };
      return result;
    } catch {
      throw new ServiceUnavailableException({
        status: 'not_ready',
        database: 'down',
        timestamp: new Date().toISOString(),
      });
    }
  }
}
