// @flow
import {
  enumerateAllInstructions,
  getObjectParameterIndex,
  enumerateObjectAndBehaviorsInstructions,
  enumerateFreeInstructions,
} from './EnumerateInstructions';
import { setupInstructionParameters } from './SetupInstructionParameters';
const gd: libGDevelop = global.gd;

describe('setupInstructionParameters', () => {
  it('sets the proper number of parameters', () => {
    const project = new gd.ProjectHelper.createNewGDJSProject();
    const layout = project.insertNewLayout('Scene', 0);
    const objectName = 'MySpriteObject';
    layout.insertNewObject(project, 'Sprite', objectName, 0);

    // Simulate that we select an instruction
    const enumeratedInstructions = enumerateFreeInstructions(false);
    const playMusicInstruction = enumeratedInstructions.find(
      enumeratedInstruction => enumeratedInstruction.type === 'PlayMusic'
    );

    if (!playMusicInstruction) {
      throw new Error('PlayMusic action was not found');
    }

    const instruction = new gd.Instruction();
    setupInstructionParameters(
      project,
      layout,
      instruction,
      playMusicInstruction.metadata
    );

    // Check that parameters were created
    expect(instruction.getParametersCount()).toBe(5);
    expect(instruction.getParameter(0)).toBe('');
    expect(instruction.getParameter(1)).toBe('');
    expect(instruction.getParameter(2)).toBe('');
    expect(instruction.getParameter(3)).toBe('');
    expect(instruction.getParameter(4)).toBe('');
  });

  it('sets the proper number of parameters and the object name', () => {
    const project = new gd.ProjectHelper.createNewGDJSProject();
    const layout = project.insertNewLayout('Scene', 0);
    const objectName = 'MySpriteObject';
    layout.insertNewObject(project, 'Sprite', objectName, 0);

    // Simulate that we select an instruction for the object
    const enumeratedInstructions = enumerateObjectAndBehaviorsInstructions(
      false,
      project,
      layout,
      objectName
    );
    const setAnimationNameInstruction = enumeratedInstructions.find(
      enumeratedInstruction => enumeratedInstruction.type === 'SetAnimationName'
    );

    if (!setAnimationNameInstruction) {
      throw new Error('SetAnimationName action was not found');
    }

    const instruction = new gd.Instruction();
    setupInstructionParameters(
      project,
      layout,
      instruction,
      setAnimationNameInstruction.metadata,
      objectName
    );

    // Check that parameters were created and the object name set
    expect(instruction.getParametersCount()).toBe(2);
    expect(instruction.getParameter(0)).toBe(objectName);
    expect(instruction.getParameter(1)).toBe('');
  });

  it('sets the proper parameters for a behavior', () => {
    const project = new gd.ProjectHelper.createNewGDJSProject();
    const layout = project.insertNewLayout('Scene', 0);
    const objectName = 'MySpriteObject';
    const object = layout.insertNewObject(project, 'Sprite', objectName, 0);
    object.addNewBehavior(
      project,
      'PlatformBehavior::PlatformerObjectBehavior',
      'PlatformerObject'
    );

    // Simulate that we select an instruction of the object behavior
    const enumeratedInstructions = enumerateObjectAndBehaviorsInstructions(
      false,
      project,
      layout,
      objectName
    );
    const jumpSpeedInstruction = enumeratedInstructions.find(
      enumeratedInstruction =>
        enumeratedInstruction.type === 'PlatformBehavior::JumpSpeed'
    );

    if (!jumpSpeedInstruction) {
      throw new Error('PlatformBehavior::JumpSpeed action was not found');
    }

    const instruction = new gd.Instruction();
    setupInstructionParameters(
      project,
      layout,
      instruction,
      jumpSpeedInstruction.metadata,
      objectName
    );

    // Check that parameters were created, the object name and behavior set
    expect(instruction.getParametersCount()).toBe(4);
    expect(instruction.getParameter(0)).toBe(objectName);
    expect(instruction.getParameter(1)).toBe('PlatformerObject');
    expect(instruction.getParameter(2)).toBe(''); // In the future, this could be set to a default value.
    expect(instruction.getParameter(3)).toBe('');
  });

  it('sets the proper parameters for a behavior, selecting the first behavior if multiple', () => {
    const project = new gd.ProjectHelper.createNewGDJSProject();
    const layout = project.insertNewLayout('Scene', 0);
    const objectName = 'MySpriteObject';
    const object = layout.insertNewObject(project, 'Sprite', objectName, 0);
    object.addNewBehavior(
      project,
      'PlatformBehavior::PlatformerObjectBehavior',
      'FirstPlatformerObject'
    );
    object.addNewBehavior(
      project,
      'PlatformBehavior::PlatformerObjectBehavior',
      'OtherPlatformerObject'
    );

    // Simulate that we select an instruction of the object behavior
    const enumeratedInstructions = enumerateObjectAndBehaviorsInstructions(
      false,
      project,
      layout,
      objectName
    );
    const jumpSpeedInstruction = enumeratedInstructions.find(
      enumeratedInstruction =>
        enumeratedInstruction.type === 'PlatformBehavior::JumpSpeed'
    );

    if (!jumpSpeedInstruction) {
      throw new Error('PlatformBehavior::JumpSpeed action was not found');
    }

    const instruction = new gd.Instruction();
    setupInstructionParameters(
      project,
      layout,
      instruction,
      jumpSpeedInstruction.metadata,
      objectName
    );

    // Check that parameters were created, the object name and behavior set
    expect(instruction.getParametersCount()).toBe(4);
    expect(instruction.getParameter(0)).toBe(objectName);
    expect(instruction.getParameter(1)).toBe('FirstPlatformerObject');
  });

  it('sets the proper parameters for a behavior, changing it if a wrong behavior name is entered', () => {
    const project = new gd.ProjectHelper.createNewGDJSProject();
    const layout = project.insertNewLayout('Scene', 0);
    const objectName = 'MySpriteObject';
    const object = layout.insertNewObject(project, 'Sprite', objectName, 0);
    object.addNewBehavior(
      project,
      'PlatformBehavior::PlatformerObjectBehavior',
      'FirstPlatformerObject'
    );
    object.addNewBehavior(
      project,
      'PlatformBehavior::PlatformerObjectBehavior',
      'OtherPlatformerObject'
    );

    // Simulate that we select an instruction of the object behavior
    const enumeratedInstructions = enumerateObjectAndBehaviorsInstructions(
      false,
      project,
      layout,
      objectName
    );
    const jumpSpeedInstruction = enumeratedInstructions.find(
      enumeratedInstruction =>
        enumeratedInstruction.type === 'PlatformBehavior::JumpSpeed'
    );

    if (!jumpSpeedInstruction) {
      throw new Error('PlatformBehavior::JumpSpeed action was not found');
    }

    const instruction = new gd.Instruction();
    instruction.setParametersCount(4);
    instruction.setParameter(0, objectName);
    instruction.setParameter(1, 'WrongName');
    setupInstructionParameters(
      project,
      layout,
      instruction,
      jumpSpeedInstruction.metadata,
      objectName
    );

    // Check that parameters were created, the object name and behavior set
    expect(instruction.getParametersCount()).toBe(4);
    expect(instruction.getParameter(0)).toBe(objectName);
    expect(instruction.getParameter(1)).toBe('FirstPlatformerObject');
  });

  it('sets the proper parameters for a behavior, letting an existing behavior name if it is valid', () => {
    const project = new gd.ProjectHelper.createNewGDJSProject();
    const layout = project.insertNewLayout('Scene', 0);
    const objectName = 'MySpriteObject';
    const object = layout.insertNewObject(project, 'Sprite', objectName, 0);
    object.addNewBehavior(
      project,
      'PlatformBehavior::PlatformerObjectBehavior',
      'FirstPlatformerObject'
    );
    object.addNewBehavior(
      project,
      'PlatformBehavior::PlatformerObjectBehavior',
      'OtherPlatformerObject'
    );

    // Simulate that we select an instruction of the object behavior
    const enumeratedInstructions = enumerateObjectAndBehaviorsInstructions(
      false,
      project,
      layout,
      objectName
    );
    const jumpSpeedInstruction = enumeratedInstructions.find(
      enumeratedInstruction =>
        enumeratedInstruction.type === 'PlatformBehavior::JumpSpeed'
    );

    if (!jumpSpeedInstruction) {
      throw new Error('PlatformBehavior::JumpSpeed action was not found');
    }

    const instruction = new gd.Instruction();
    instruction.setParametersCount(4);
    instruction.setParameter(0, objectName);
    instruction.setParameter(1, 'OtherPlatformerObject');
    setupInstructionParameters(
      project,
      layout,
      instruction,
      jumpSpeedInstruction.metadata,
      objectName
    );

    // Check that parameters were created, the object name and behavior set
    expect(instruction.getParametersCount()).toBe(4);
    expect(instruction.getParameter(0)).toBe(objectName);
    expect(instruction.getParameter(1)).toBe('OtherPlatformerObject');
  });
});
