/**
 * Boot-time ValidationPipe metatype self-check (#1391).
 *
 * The check exists to fail loud at boot when the global pipe cannot see a
 * guarded DTO's decorated properties — the #436 class-erasure signature and
 * its dependency-graph cousins. Red/green arms:
 *
 *   GREEN  real module state: BootstrapSetupDto's three properties are
 *          decorated and visible through the globalThis-shared storage.
 *   RED    a control class with NO decorators (the erasure shape): the
 *          check throws PipeMetatypeCheckError naming every property.
 *   RED-2  a control where one property is decorated and two are not: the
 *          error names exactly the missing two — the miss list is precise,
 *          not a blanket failure.
 */
import { describe, expect, it } from 'vitest';
import { IsString } from 'class-validator';
import {
  assertValidationPipeSeesDtoDecorators,
  PipeMetatypeCheckError,
} from './validation-pipe-check.js';

describe('assertValidationPipeSeesDtoDecorators (#1391 boot check)', () => {
  it('GREEN: passes on real module state (decorated DTO visible to the pipe)', () => {
    expect(() => assertValidationPipeSeesDtoDecorators()).not.toThrow();
  });

  it('RED control: a class whose properties lost their decorators throws, naming them', async () => {
    // Simulate metatype erasure: an undecorated class standing where a
    // decorated DTO should be. Redefine the guard table for the test by
    // importing the module and pointing its table at the eroded class —
    // the check reads the table at call time, so a fresh module instance
    // with a swapped table reproduces the boot failure deterministically.
    const { PIPE_GUARDED_DTOS } = await import('./validation-pipe-check.js');

    class ErodedDto {
      name?: string;
      email?: string;
      password?: string;
    }

    const original = PIPE_GUARDED_DTOS[0];
    expect(original).toBeDefined();
    // Swap in the eroded target (same declared properties, zero decorators).
    (
      PIPE_GUARDED_DTOS as unknown as Array<{ name: string; target: object; properties: string[] }>
    ).splice(0, PIPE_GUARDED_DTOS.length, {
      name: 'ErodedDto',
      target: ErodedDto,
      properties: ['name', 'email', 'password'],
    });

    try {
      expect(() => assertValidationPipeSeesDtoDecorators()).toThrow(PipeMetatypeCheckError);
      try {
        assertValidationPipeSeesDtoDecorators();
      } catch (err) {
        const message = err instanceof Error ? err.message : '';
        expect(message).toContain('ErodedDto.name');
        expect(message).toContain('ErodedDto.email');
        expect(message).toContain('ErodedDto.password');
      }
    } finally {
      // Restore real module state for any later test in this file.
      (PIPE_GUARDED_DTOS as unknown as unknown[]).splice(0, PIPE_GUARDED_DTOS.length, original);
    }
    // And confirm the restore is real.
    expect(() => assertValidationPipeSeesDtoDecorators()).not.toThrow();
  });

  it('RED-2 control: a partially decorated class names exactly the missing properties', async () => {
    const { PIPE_GUARDED_DTOS } = await import('./validation-pipe-check.js');

    class HalfErodedDto {
      @IsString()
      name?: string;
      email?: string;
      password?: string;
    }

    const original = PIPE_GUARDED_DTOS[0];
    (
      PIPE_GUARDED_DTOS as unknown as Array<{ name: string; target: object; properties: string[] }>
    ).splice(0, PIPE_GUARDED_DTOS.length, {
      name: 'HalfErodedDto',
      target: HalfErodedDto,
      properties: ['name', 'email', 'password'],
    });

    try {
      try {
        assertValidationPipeSeesDtoDecorators();
        expect.unreachable('partially decorated DTO must fail the boot check');
      } catch (err) {
        const message = err instanceof Error ? err.message : '';
        expect(message).toContain('HalfErodedDto.email');
        expect(message).toContain('HalfErodedDto.password');
        expect(message).not.toContain('HalfErodedDto.name has no');
      }
    } finally {
      (PIPE_GUARDED_DTOS as unknown as unknown[]).splice(0, PIPE_GUARDED_DTOS.length, original);
    }
  });
});
