import { describe, it, expect } from 'vitest';
import { buildMasterPrompt, buildSubjectDescription, buildCameraSettings } from './prompt-builder.js';
import type { CharacterDNA } from '../../types/character.js';

function makeDNA(overrides?: Partial<CharacterDNA>): CharacterDNA {
  return {
    id: 'test-char-1',
    createdAt: '2025-01-01T00:00:00Z',
    updatedAt: '2025-01-01T00:00:00Z',
    status: 'active',
    identity: { name: 'Aylin', age: 24, nationality: 'Turkish', city: 'Istanbul', occupation: 'model', personality_tags: ['fun', 'outgoing'], mbti: 'ENFP', backstory: 'A vibrant model from Istanbul' },
    physicalMeasurements: { height_cm: 172, weight_kg: 56, body_type: 'slim', measurements: { bust: 88, waist: 62, hips: 90 } },
    skinMap: { base: '#F5D0A9', shadow: '#D4A574', highlight: '#FFE4C4' },
    faceAnatomy: { eye_shape: 'almond', eye_color: '#8B4513', eyebrow_shape: 'arched', nose_type: 'straight', lip_shape: 'full', cheekbones: 'high', jawline: 'soft', distinctive_marks: ['beauty mark on left cheek'] },
    hairDNA: { style: 'wavy', length: 'long', texture: 'silky', root_color: '#3B2F2F', mid_color: '#5C4033', highlight_color: '#8B6914' },
    bodyBiometrics: { body_type_detail: 'hourglass', posture: 'upright', skin_texture: 'smooth' },
    profileView: { best_angle: 'left-45', signature_pose: 'hand-on-hip' },
    expressionMotion: { default_expression: 'smile', smile_type: 'warm', gaze_style: 'direct' },
    makeupStyle: { philosophy: 'natural', skin_finish: 'dewy', colors: { primary: '#C48793', secondary: '#E8B4B8', accent: '#8B0000' } },
    fashionStyle: { aesthetic: 'casual-chic', main_colors: ['#000000', '#FFFFFF'], signature_pieces: ['jeans', 'crop top'] },
    technicalSettings: { camera_body: 'Canon R5', portrait_lens: '85mm f/1.4', full_body_lens: '35mm f/1.4', film_stock: 'Portra 400' },
    ...overrides,
  };
}

describe('buildSubjectDescription', () => {
  it('should include physical features from DNA', () => {
    const dna = makeDNA();
    const subject = buildSubjectDescription(dna);

    expect(subject).toContain('24 year old');
    expect(subject).toContain('Turkish');
    expect(subject).toContain('172cm tall');
    expect(subject).toContain('slim');
    expect(subject).toContain('hourglass');
  });

  it('should include skin HEX colors', () => {
    const dna = makeDNA();
    const subject = buildSubjectDescription(dna);

    expect(subject).toContain('#F5D0A9');
    expect(subject).toContain('#D4A574');
    expect(subject).toContain('#FFE4C4');
  });

  it('should include hair details with HEX colors', () => {
    const dna = makeDNA();
    const subject = buildSubjectDescription(dna);

    expect(subject).toContain('long');
    expect(subject).toContain('silky');
    expect(subject).toContain('wavy');
    expect(subject).toContain('#3B2F2F');
    expect(subject).toContain('#5C4033');
    expect(subject).toContain('#8B6914');
  });

  it('should include face anatomy details', () => {
    const dna = makeDNA();
    const subject = buildSubjectDescription(dna);

    expect(subject).toContain('almond');
    expect(subject).toContain('#8B4513');
    expect(subject).toContain('arched');
    expect(subject).toContain('straight nose');
    expect(subject).toContain('full lips');
    expect(subject).toContain('high cheekbones');
    expect(subject).toContain('soft jawline');
  });

  it('should include distinctive marks when present', () => {
    const dna = makeDNA();
    const subject = buildSubjectDescription(dna);
    expect(subject).toContain('beauty mark on left cheek');
  });

  it('should omit distinctive marks section when empty', () => {
    const dna = makeDNA({
      faceAnatomy: { eye_shape: 'round', eye_color: '#000', eyebrow_shape: 'flat', nose_type: 'button', lip_shape: 'thin', cheekbones: 'low', jawline: 'sharp', distinctive_marks: [] },
    });
    const subject = buildSubjectDescription(dna);
    expect(subject).not.toContain('distinctive marks');
  });

  it('should include expression and gaze', () => {
    const dna = makeDNA();
    const subject = buildSubjectDescription(dna);

    expect(subject).toContain('smile expression');
    expect(subject).toContain('warm smile');
    expect(subject).toContain('direct gaze');
  });
});

describe('buildCameraSettings', () => {
  it('should include all technical settings', () => {
    const dna = makeDNA();
    const camera = buildCameraSettings(dna);

    expect(camera).toContain('Canon R5');
    expect(camera).toContain('85mm f/1.4');
    expect(camera).toContain('35mm f/1.4');
    expect(camera).toContain('Portra 400');
  });

  it('should format as shot on camera with lens and film stock', () => {
    const dna = makeDNA();
    const camera = buildCameraSettings(dna);
    expect(camera).toMatch(/^shot on /);
    expect(camera).toContain('portrait lens');
    expect(camera).toContain('full body lens');
    expect(camera).toContain('film stock');
  });
});

describe('buildMasterPrompt', () => {
  it('should return a valid MasterJSONPrompt with all fields', () => {
    const dna = makeDNA();
    const prompt = buildMasterPrompt(dna);

    expect(prompt.characterId).toBe('test-char-1');
    expect(prompt.subject).toBeTruthy();
    expect(prompt.clothing).toBeTruthy();
    expect(prompt.environment).toBeTruthy();
    expect(prompt.lighting).toBeTruthy();
    expect(prompt.camera).toBeTruthy();
    expect(prompt.aesthetic).toBeTruthy();
    expect(prompt.negative_prompt).toBeTruthy();
    expect(prompt.createdAt).toBeTruthy();
    expect(prompt.updatedAt).toBeTruthy();
  });

  it('should include character physical features in subject', () => {
    const dna = makeDNA();
    const prompt = buildMasterPrompt(dna);

    expect(prompt.subject).toContain('#F5D0A9');
    expect(prompt.subject).toContain('wavy');
    expect(prompt.subject).toContain('hourglass');
  });

  it('should include fashion style in clothing', () => {
    const dna = makeDNA();
    const prompt = buildMasterPrompt(dna);

    expect(prompt.clothing).toContain('casual-chic');
    expect(prompt.clothing).toContain('jeans');
    expect(prompt.clothing).toContain('crop top');
    expect(prompt.clothing).toContain('#000000');
  });

  it('should include camera settings with technical details', () => {
    const dna = makeDNA();
    const prompt = buildMasterPrompt(dna);

    expect(prompt.camera).toContain('Canon R5');
    expect(prompt.camera).toContain('85mm f/1.4');
    expect(prompt.camera).toContain('Portra 400');
  });

  it('should include makeup and fashion in aesthetic', () => {
    const dna = makeDNA();
    const prompt = buildMasterPrompt(dna);

    expect(prompt.aesthetic).toContain('natural');
    expect(prompt.aesthetic).toContain('casual-chic');
  });

  it('should include makeup colors in lighting', () => {
    const dna = makeDNA();
    const prompt = buildMasterPrompt(dna);

    expect(prompt.lighting).toContain('dewy');
    expect(prompt.lighting).toContain('#C48793');
  });

  it('should include profile view in environment', () => {
    const dna = makeDNA();
    const prompt = buildMasterPrompt(dna);

    expect(prompt.environment).toContain('left-45');
    expect(prompt.environment).toContain('hand-on-hip');
  });

  it('should have a non-empty negative prompt', () => {
    const dna = makeDNA();
    const prompt = buildMasterPrompt(dna);

    expect(prompt.negative_prompt).toContain('blurry');
    expect(prompt.negative_prompt).toContain('deformed');
  });

  it('should set ISO timestamps for createdAt and updatedAt', () => {
    const dna = makeDNA();
    const before = new Date().toISOString();
    const prompt = buildMasterPrompt(dna);
    const after = new Date().toISOString();

    expect(prompt.createdAt >= before).toBe(true);
    expect(prompt.createdAt <= after).toBe(true);
    expect(prompt.updatedAt).toBe(prompt.createdAt);
  });
});
