/**
 * End-to-end validator tests for imageTool._validateParameters.
 *
 * The validator now resolves the effective model first (respecting the
 * transparency / sourceImage auto-switch) and applies per-model rules.
 * These tests exercise all four quadrants:
 *
 *   { explicit gpt-image-1.5, transparency auto-switch, sourceImage
 *     auto-switch, default Flux }  ×  { valid size, invalid size }
 */

import { describe, test, expect, beforeEach, jest } from '@jest/globals';

// The ImageTool constructor pulls in heavy services — we don't need
// any of them for validator tests. Shallow-instantiate via bypass.
let ImageTool;
beforeEach(async () => {
  const mod = await import('../imageTool.js');
  ImageTool = mod.ImageTool;
});

function makeTool() {
  const tool = new ImageTool({}, { info() {}, warn() {}, error() {}, debug() {} });
  return tool;
}

function expectValidates(params) {
  const tool = makeTool();
  expect(() => tool._validateParameters(params)).not.toThrow();
}
function expectRejects(params, pattern) {
  const tool = makeTool();
  expect(() => tool._validateParameters(params)).toThrow(pattern);
}

// ── gpt-image-1.5 (explicit) ────────────────────────────────────────────

describe('_validateParameters — gpt-image-1.5 explicit', () => {
  test('accepts 1024x1024', () => {
    expectValidates({ images: [{ prompt: 'cat', model: 'gpt-image-1.5', size: '1024x1024' }] });
  });

  test('accepts 1024x1536 (portrait enum)', () => {
    expectValidates({ images: [{ prompt: 'cat', model: 'gpt-image-1.5', size: '1024x1536' }] });
  });

  test('accepts 1536x1024 (landscape enum)', () => {
    expectValidates({ images: [{ prompt: 'cat', model: 'gpt-image-1.5', size: '1536x1024' }] });
  });

  test('accepts "auto"', () => {
    expectValidates({ images: [{ prompt: 'cat', model: 'gpt-image-1.5', size: 'auto' }] });
  });

  test('rejects 1024x1440 (Flux-shaped, not in enum)', () => {
    // The exact case from the user's failure.
    expectRejects(
      { images: [{ prompt: 'cat', model: 'gpt-image-1.5', size: '1024x1440' }] },
      /not supported by gpt-image-1\.5.*Valid sizes/
    );
  });

  test('rejects 1280x720 with a hint', () => {
    expectRejects(
      { images: [{ prompt: 'cat', model: 'gpt-image-1.5', size: '1280x720' }] },
      /for landscape use "1536x1024"/
    );
  });

  test('error message lists all valid sizes', () => {
    try {
      makeTool()._validateParameters({ images: [{ prompt: 'x', model: 'gpt-image-1.5', size: '2000x2000' }] });
      throw new Error('expected throw');
    } catch (err) {
      expect(err.message).toContain('1024x1024');
      expect(err.message).toContain('1024x1536');
      expect(err.message).toContain('1536x1024');
      expect(err.message).toContain('auto');
    }
  });
});

// ── Auto-switch: transparency / sourceImage ─────────────────────────────

describe('_validateParameters — auto-switch to gpt-image-1.5', () => {
  test('transparency=true: Flux size rejected with gpt-image-1.5 enum', () => {
    // Before the fix, this passed the Flux validator (1024x1440 is
    // within 256-1440, multiple of 32), then failed downstream.
    expectRejects(
      { images: [{ prompt: 'logo', transparency: true, size: '1024x1440' }] },
      /not supported by gpt-image-1\.5.*transparency=true/
    );
  });

  test('transparency=true: 1024x1536 passes', () => {
    expectValidates({ images: [{ prompt: 'logo', transparency: true, size: '1024x1536' }] });
  });

  test('sourceImage auto-switch: Flux size rejected', () => {
    expectRejects(
      { images: [{ prompt: 'edit', sourceImage: '/tmp/x.png', size: '1280x960' }] },
      /not supported by gpt-image-1\.5.*sourceImage/
    );
  });
});

// ── Flux (default) ──────────────────────────────────────────────────────

describe('_validateParameters — Flux default rules', () => {
  test('accepts 1024x1024', () => {
    expectValidates({ images: [{ prompt: 'scene', model: 'flux-1.1-pro', size: '1024x1024' }] });
  });

  test('accepts 1280x960 (Flux-native)', () => {
    expectValidates({ images: [{ prompt: 'scene', model: 'flux-1.1-pro', size: '1280x960' }] });
  });

  test('rejects "auto" — with helpful hint', () => {
    expectRejects(
      { images: [{ prompt: 'scene', model: 'flux-1.1-pro', size: 'auto' }] },
      /only valid for gpt-image-1\.5/
    );
  });

  test('rejects too-large width with model-named message', () => {
    expectRejects(
      { images: [{ prompt: 'scene', model: 'flux-1.1-pro', size: '2048x1024' }] },
      /Width 2048 out of range for flux-1\.1-pro/
    );
  });

  test('rejects non-multiple-of-32 with nearest-valid hint', () => {
    expectRejects(
      { images: [{ prompt: 'scene', model: 'flux-1.1-pro', size: '1000x1024' }] },
      /must be a multiple of 32.*Nearest valid: 992/
    );
  });
});

// ── Presets (model-aware) ───────────────────────────────────────────────

describe('_validateParameters — presets are model-aware', () => {
  test('"portrait" on default model resolves to 1024x1440 (Flux-shaped)', () => {
    const params = { images: [{ prompt: 'p', size: 'portrait' }] };
    const tool = makeTool();
    tool._validateParameters(params);
    expect(params.images[0].size).toBe('1024x1440');
  });

  test('"portrait" with transparency=true resolves to 1024x1536 (gpt-image enum)', () => {
    const params = { images: [{ prompt: 'p', transparency: true, size: 'portrait' }] };
    const tool = makeTool();
    tool._validateParameters(params);
    expect(params.images[0].size).toBe('1024x1536');
  });

  test('"landscape" with transparency=true resolves to 1536x1024', () => {
    const params = { images: [{ prompt: 'p', transparency: true, size: 'landscape' }] };
    const tool = makeTool();
    tool._validateParameters(params);
    expect(params.images[0].size).toBe('1536x1024');
  });

  test('"square_hd" on gpt-image-1.5 remaps to 1024x1024 (no 1440 enum value)', () => {
    const params = { images: [{ prompt: 'p', model: 'gpt-image-1.5', size: 'square_hd' }] };
    const tool = makeTool();
    tool._validateParameters(params);
    expect(params.images[0].size).toBe('1024x1024');
  });
});

// ── Baseline error cases still fire ─────────────────────────────────────

describe('_validateParameters — baseline errors still fire', () => {
  test('missing prompt', () => {
    expectRejects({ images: [{ prompt: '' }] }, /prompt is required/);
  });

  test('prompt too long', () => {
    const bigPrompt = 'x'.repeat(5000);
    expectRejects({ images: [{ prompt: bigPrompt }] }, /too long/);
  });

  test('invalid output file extension', () => {
    expectRejects(
      { images: [{ prompt: 'x', outputPath: '/tmp/out.bmp' }] },
      /Invalid format: bmp/
    );
  });

  test('empty images array', () => {
    expectRejects({ images: [] }, /No images specified/);
  });
});
