import { Controller, Get, Inject } from '@nestjs/common';
import type { HealthResponse } from '@siop/shared';
import Redis from 'ioredis';
import { Public } from '../auth/public.decorator';
import { loadEnv } from '../config/env';
import { FILE_STORAGE, type FileStorage } from '../files/file-storage';
import { PrismaService } from '../prisma/prisma.service';

@Controller('health')
export class HealthController {
  constructor(
    private readonly prisma: PrismaService,
    @Inject(FILE_STORAGE) private readonly storage: FileStorage,
  ) {}

  @Public()
  @Get()
  async health(): Promise<HealthResponse> {
    const [database, redis, storage] = await Promise.all([
      this.check(() => this.prisma.$queryRaw`SELECT 1`),
      this.check(async () => {
        const client = new Redis(loadEnv().REDIS_URL, {
          lazyConnect: true,
          maxRetriesPerRequest: 0,
          connectTimeout: 2000,
        });
        try {
          await client.connect();
          await client.ping();
        } finally {
          client.disconnect();
        }
      }),
      this.check(() => this.storage.healthCheck()),
    ]);
    const services = { database, redis, storage };
    return {
      status: Object.values(services).every((s) => s === 'up')
        ? 'ok'
        : 'degraded',
      services,
    };
  }

  private async check(fn: () => Promise<unknown>): Promise<'up' | 'down'> {
    try {
      await fn();
      return 'up';
    } catch {
      return 'down';
    }
  }
}
