import { AppController } from './app.controller';

//* 의존성은 treat-provider.service.spec.ts 패턴대로 직접 주입한다. TestingModule 안 쓴다.
const make = (
  db: { ok: boolean; ms: number },
  redis: { ok: boolean; ms: number } | null,
) =>
  new AppController({
    probeDb: jest.fn().mockResolvedValue(db),
    probeRedis: jest.fn().mockResolvedValue(redis),
  } as any);

const res = () => ({ status: jest.fn() }) as any;

describe('AppController 헬스 (M2 §D6 단계 3)', () => {
  it('/live 는 의존성과 무관하게 상수 OK — 재시작으로 못 고치는 장애에 태스크를 순환시키지 않는다', () => {
    expect(make({ ok: false, ms: 1 }, { ok: false, ms: 1 }).liveness()).toBe('OK');
  });

  it('DB·Redis 정상이면 200 (상태코드 미변경)', async () => {
    const r = res();
    const body = await make({ ok: true, ms: 3 }, { ok: true, ms: 1 }).healthCheck(r);
    expect(body.ok).toBe(true);
    expect(r.status).not.toHaveBeenCalled();
  });

  it('DB 실패면 503 + 본문 db.ok=false', async () => {
    const r = res();
    const body = await make({ ok: false, ms: 9 }, { ok: true, ms: 1 }).healthCheck(r);
    expect(body.ok).toBe(false);
    expect(body.db.ok).toBe(false);
    expect(r.status).toHaveBeenCalledWith(503);
  });

  it('Redis 실패면 503 + 본문 redis.ok=false — UI3 는 두 축 모두를 요구한다', async () => {
    const r = res();
    const body = await make({ ok: true, ms: 3 }, { ok: false, ms: 9 }).healthCheck(r);
    expect(body.ok).toBe(false);
    expect(body.redis).toEqual({ ok: false, ms: 9 });
    expect(r.status).toHaveBeenCalledWith(503);
  });

  it('Redis 미구성(null)은 장애가 아니다 — DB 정상이면 200', async () => {
    const r = res();
    const body = await make({ ok: true, ms: 3 }, null).healthCheck(r);
    expect(body.ok).toBe(true);
    expect(body.redis).toBeNull();
    expect(r.status).not.toHaveBeenCalled();
  });

  it('본문에 예외 메시지를 싣지 않는다 — 무인증 경로', async () => {
    const c = new AppController({
      probeDb: jest.fn().mockResolvedValue({ ok: false, ms: 9, error: 'ECONNREFUSED 10.0.0.5:3306' }),
      probeRedis: jest.fn().mockResolvedValue({ ok: true, ms: 1 }),
    } as any);
    expect(JSON.stringify(await c.healthCheck(res()))).not.toContain('ECONNREFUSED');
  });

  it('/health/detail 은 상태코드를 건드리지 않는다 — A6 규칙이 본문으로 판정한다', async () => {
    const body = await make({ ok: false, ms: 9 }, { ok: true, ms: 1 }).healthDetail();
    expect(body).toEqual({ ok: false, db: { ok: false, ms: 9 }, redis: { ok: true, ms: 1 } });
  });
});
