import { Readable } from 'stream';

import { ContractTransitionService } from './contract-transition.service';

/**
 * A stamp may be uploaded as JPEG/WebP while a drawn signature is always PNG.
 * The type must survive the round-trip: data URL in → stored object extension
 * → data URL out. Getting this wrong labels JPEG bytes as image/png in the
 * contract PDF and leaves the seal to browser content-sniffing.
 */
describe('ContractTransitionService signature/stamp asset typing', () => {
  const pngPixel =
    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==';
  const jpegPixel = `data:image/jpeg;base64,${Buffer.from('fake-jpeg').toString('base64')}`;

  /** Minimal service instance — only filesService/minioService are exercised. */
  const build = () => {
    const uploaded: Array<{ code: string; mimetype: string; name: string }> = [];
    const filesService = {
      upsertByCode: jest.fn(({ code, file }) => {
        uploaded.push({ code, mimetype: file.mimetype, name: file.originalname });
        return Promise.resolve({ id: `file-${code}`, url: `https://minio/x/${file.originalname}` });
      }),
    };
    const minioService = {
      getObjectNameFromUrl: (url: string) => url.split('/').pop() ?? '',
      getFileStream: () => Promise.resolve(Readable.from(Buffer.from('bytes'))),
    };
    const service = Object.create(
      ContractTransitionService.prototype,
    ) as ContractTransitionService;
    Object.assign(service, { filesService, minioService });
    return { service, uploaded };
  };

  const contract = { id: 'c-1', reference: 'CTR-2026-00001' };

  it('stores a drawn PNG signature as image/png', async () => {
    const { service, uploaded } = build();
    await (service as never as {
      uploadSignatureAsset: (c: unknown, code: string, b64: string) => Promise<unknown>;
    }).uploadSignatureAsset(contract, 'signature_customer', pngPixel);

    expect(uploaded[0].mimetype).toBe('image/png');
    expect(uploaded[0].name).toBe('signature-customer-CTR-2026-00001.png');
  });

  it('keeps an uploaded JPEG stamp as image/jpeg, not image/png', async () => {
    const { service, uploaded } = build();
    await (service as never as {
      uploadSignatureAsset: (c: unknown, code: string, b64: string) => Promise<unknown>;
    }).uploadSignatureAsset(contract, 'stamp_customer', jpegPixel);

    expect(uploaded[0].mimetype).toBe('image/jpeg');
    expect(uploaded[0].name).toBe('stamp-customer-CTR-2026-00001.jpg');
  });

  it('inlines a stored .jpg back as a data:image/jpeg URI', async () => {
    const { service } = build();
    const inline = (service as never as {
      inlineImageUrl: (url?: string | null) => Promise<string | null | undefined>;
    }).inlineImageUrl.bind(service);

    await expect(inline('https://minio/x/stamp-customer-CTR.jpg')).resolves.toMatch(
      /^data:image\/jpeg;base64,/,
    );
    await expect(inline('https://minio/x/signature-customer-CTR.png')).resolves.toMatch(
      /^data:image\/png;base64,/,
    );
  });

  it('passes through empty and already-inlined values untouched', async () => {
    const { service } = build();
    const inline = (service as never as {
      inlineImageUrl: (url?: string | null) => Promise<string | null | undefined>;
    }).inlineImageUrl.bind(service);

    await expect(inline(null)).resolves.toBeNull();
    await expect(inline(pngPixel)).resolves.toBe(pngPixel);
  });
});
