import * as fs from 'fs';
import { vol } from 'memfs';

import { XcodeProject } from '../../Plugin.types';
import rnFixture from '../../plugins/__tests__/fixtures/react-native-project';
import * as WarningAggregator from '../../utils/warnings';
import { setBitcodeWithConfig } from '../Bitcode';
import { getPbxproj, isNotComment } from '../utils/Xcodeproj';

jest.mock('fs');
jest.mock('../../utils/warnings');

describe(setBitcodeWithConfig, () => {
  const projectRoot = '/tablet';
  beforeEach(async () => {
    vol.fromJSON(
      {
        'ios/testproject.xcodeproj/project.pbxproj':
          rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'],
        'ios/testproject/AppDelegate.m': '',
      },
      projectRoot
    );
  });

  afterEach(() => {
    vol.reset();
  });

  it('defaults to not modifying the bitcode settings', async () => {
    setBitcodeEnabledForRoot({ ios: {} }, projectRoot, validateDefaultBitcode);
  });

  it('enables bitcode for everything', async () => {
    setBitcodeEnabledForRoot({ ios: { bitcode: true } }, projectRoot, (project) => {
      const configurations = getConfigurations(project);
      for (const [, configuration] of configurations) {
        expect(configuration.buildSettings.ENABLE_BITCODE).toBe('YES');
      }
    });
  });

  it('disables bitcode for everything', async () => {
    setBitcodeEnabledForRoot({ ios: { bitcode: false } }, projectRoot, (project) => {
      const configurations = getConfigurations(project);
      for (const [, configuration] of configurations) {
        expect(configuration.buildSettings.ENABLE_BITCODE).toBe('NO');
      }
    });
  });

  it('enables bitcode on specific configuration', async () => {
    setBitcodeEnabledForRoot({ ios: { bitcode: 'Debug' } }, projectRoot, (project) => {
      const configurations = getConfigurations(project);
      for (const [, configuration] of configurations) {
        // ensure all others are disabled
        expect(configuration.buildSettings.ENABLE_BITCODE).toBe(
          configuration.name === 'Debug' ? 'YES' : 'NO'
        );
      }
    });
  });

  it('warns when enabling bitcode on an invalid configuration', async () => {
    setBitcodeEnabledForRoot({ ios: { bitcode: 'Bacon' } }, projectRoot, validateDefaultBitcode);
    expect(WarningAggregator.addWarningIOS).toHaveBeenLastCalledWith(
      'ios.bitcode',
      'No configuration named "Bacon". Expected one of: "Debug", "Release".'
    );
  });
});

function getConfigurations(project: XcodeProject) {
  return Object.entries(project.pbxXCBuildConfigurationSection()).filter(isNotComment);
}

function setBitcodeEnabledForRoot(
  config: { ios?: { bitcode?: boolean | string } & any },
  projectRoot: string,
  validate: (project: XcodeProject) => void
) {
  let project = getPbxproj(projectRoot);
  project = setBitcodeWithConfig(config, { project });
  validate(project);
  fs.writeFileSync(project.filepath, project.writeSync());
}

function validateDefaultBitcode(project: XcodeProject) {
  const configurations = getConfigurations(project);
  for (const [id, configuration] of configurations) {
    expect(configuration.buildSettings.ENABLE_BITCODE).toBe(
      // Ensure nothing changed.
      {
        '13B07F941A680F5B00A75B9A': 'NO',
        '13B07F951A680F5B00A75B9A': undefined,
        '83CBBA201A601CBA00E9B192': undefined,
        '83CBBA211A601CBA00E9B192': undefined,
      }[id]
    );
  }
}
