type ContextConfigurationInfo = { target: string, required: boolean };
export interface ConfigurationInfo {
  unitTest: ContextConfigurationInfo;
  e2e: ContextConfigurationInfo;
};

export interface BrowserLauncherInfo {
  base: string;
  flags?: string[];
  version?: string;
  platform?: string;
  device?: string;
  browser?: string;
  browser_version?: string;
  os?: string;
  os_version?: string;
};

export type AliasMap = { [name: string]: string[] };


// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL)
// and BrowserStack (BS).
// If the target is set to null, then the browser is not run anywhere during CI.
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented
// out in Travis configuration.
const configuration: { [name: string]: ConfigurationInfo } = {
  'Chrome':       { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'Firefox':      { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'ChromeBeta':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'FirefoxBeta':  { unitTest: {target: null, required: false}, e2e: {target: null, required: true}},
  'ChromeDev':    { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
  'FirefoxDev':   { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
  'IE9':          { unitTest: {target: null, required: false}, e2e: {target: null, required: true}},
  'IE10':         { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
  'IE11':         { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'Edge':         { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'Android4.1':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.2':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.3':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.4':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android5':     { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Safari7':      { unitTest: {target: null, required: false}, e2e: {target: null, required: true}},
  'Safari8':      { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'Safari9':      { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'iOS7':         { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'iOS8':         { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
  // TODO(mlaval): iOS9 deactivated as not reliable, reactivate after
  //               https://github.com/angular/angular/issues/5408
  'iOS9':         { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
};

export const customLaunchers: { [name: string]: BrowserLauncherInfo } = {
  'ChromeNoSandbox': {
    base: 'Chrome',
    flags: ['--no-sandbox']
  },
  // Chrome set to 1024x768 resolution for *local testing only*.
  // On CI, both SauceLabs and Browserstack already default all browser window sizes to 1024x768.
  'Chrome_1024x768': {
    base : 'Chrome',
    flags: ['--window-size=1024,768']
  },
  'SL_CHROME': {
    base: 'SauceLabs',
    browserName: 'chrome',
    version: '46'
  },
  'SL_CHROMEBETA': {
    base: 'SauceLabs',
    browserName: 'chrome',
    version: 'beta'
  },
  'SL_CHROMEDEV': {
    base: 'SauceLabs',
    browserName: 'chrome',
    version: 'dev'
  },
  'SL_FIREFOX': {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: '42'
  },
  'SL_FIREFOXBETA': {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: 'beta'
  },
  'SL_FIREFOXDEV': {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: 'dev'
  },
  'SL_SAFARI7': {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.9',
    version: '7'
  },
  'SL_SAFARI8': {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.10',
    version: '8'
  },
  'SL_SAFARI9': {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.11',
    version: '9.0'
  },
  'SL_IOS7': {
    base: 'SauceLabs',
    browserName: 'iphone',
    platform: 'OS X 10.10',
    version: '7.1'
  },
  'SL_IOS8': {
    base: 'SauceLabs',
    browserName: 'iphone',
    platform: 'OS X 10.10',
    version: '8.4'
  },
  'SL_IOS9': {
    base: 'SauceLabs',
    browserName: 'iphone',
    platform: 'OS X 10.10',
    version: '9.1'
  },
  'SL_IE9': {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 2008',
    version: '9'
  },
  'SL_IE10': {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 2012',
    version: '10'
  },
  'SL_IE11': {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 8.1',
    version: '11'
  },
  'SL_EDGE': {
    base: 'SauceLabs',
    browserName: 'microsoftedge',
    platform: 'Windows 10',
    version: '20.10240'
  },
  'SL_ANDROID4.1': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.1'
  },
  'SL_ANDROID4.2': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.2'
  },
  'SL_ANDROID4.3': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.3'
  },
  'SL_ANDROID4.4': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.4'
  },
  'SL_ANDROID5': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '5.1'
  },

  'BS_CHROME': {
    base: 'BrowserStack',
    browser: 'chrome',
    os: 'OS X',
    os_version: 'Yosemite'
  },
  'BS_FIREFOX': {
    base: 'BrowserStack',
    browser: 'firefox',
    os: 'Windows',
    os_version: '10'
  },
  'BS_SAFARI7': {
    base: 'BrowserStack',
    browser: 'safari',
    os: 'OS X',
    os_version: 'Mavericks'
  },
  'BS_SAFARI8': {
    base: 'BrowserStack',
    browser: 'safari',
    os: 'OS X',
    os_version: 'Yosemite'
  },
  'BS_SAFARI9': {
    base: 'BrowserStack',
    browser: 'safari',
    os: 'OS X',
    os_version: 'El Capitan'
  },
  'BS_IOS7': {
    base: 'BrowserStack',
    device: 'iPhone 5S',
    os: 'ios',
    os_version: '7.0',
    resolution: '1024x768'
  },
  'BS_IOS8': {
    base: 'BrowserStack',
    device: 'iPhone 6',
    os: 'ios',
    os_version: '8.3',
    resolution: '1024x768'
  },
  'BS_IOS9': {
    base: 'BrowserStack',
    device: 'iPhone 6S',
    os: 'ios',
    os_version: '9.0',
    resolution: '1024x768'
  },
  'BS_IE9': {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '9.0',
    os: 'Windows',
    os_version: '7'
  },
  'BS_IE10': {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '10.0',
    os: 'Windows',
    os_version: '8'
  },
  'BS_IE11': {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '11.0',
    os: 'Windows',
    os_version: '10'
  },
  'BS_EDGE': {
    base: 'BrowserStack',
    browser: 'edge',
    os: 'Windows',
    os_version: '10'
  },
  'BS_WINDOWSPHONE' : {
    base: 'BrowserStack',
    device: 'Nokia Lumia 930',
    os: 'winphone',
    os_version: '8.1'
  },
  'BS_ANDROID5': {
    base: 'BrowserStack',
    device: 'Google Nexus 5',
    os: 'android',
    os_version: '5.0'
  },
  'BS_ANDROID4.4': {
    base: 'BrowserStack',
    device: 'HTC One M8',
    os: 'android',
    os_version: '4.4'
  },
  'BS_ANDROID4.3': {
    base: 'BrowserStack',
    device: 'Samsung Galaxy S4',
    os: 'android',
    os_version: '4.3'
  },
  'BS_ANDROID4.2': {
    base: 'BrowserStack',
    device: 'Google Nexus 4',
    os: 'android',
    os_version: '4.2'
  },
  'BS_ANDROID4.1': {
    base: 'BrowserStack',
    device: 'Google Nexus 7',
    os: 'android',
    os_version: '4.1'
  }
};

const sauceAliases: AliasMap = {
  'ALL': Object.keys(customLaunchers).filter(function(item) {
    return customLaunchers[item].base == 'SauceLabs';
  }),
  'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7',
              'SL_SAFARI8', 'SL_SAFARI9'],
  'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5',
             'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
  'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
  'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
  'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
  'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
  'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
  'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
  'REQUIRED': buildConfiguration('unitTest', 'SL', true),
  'OPTIONAL': buildConfiguration('unitTest', 'SL', false)
};

const browserstackAliases: AliasMap = {
  'ALL': Object.keys(customLaunchers).filter(function(item) {
    return customLaunchers[item].base == 'BrowserStack';
  }),
  'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7',
              'BS_SAFARI8', 'BS_SAFARI9'],
  'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_WINDOWSPHONE'],
  'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
  'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
  'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
  'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
  'REQUIRED': buildConfiguration('unitTest', 'BS', true),
  'OPTIONAL': buildConfiguration('unitTest', 'BS', false)
};

export const platformMap: { [name: string]: AliasMap } = {
  'saucelabs': sauceAliases,
  'browserstack': browserstackAliases,
};


/** Decode the token for Travis to use. */
function decode(str: string): string {
  return (str || '').split('').reverse().join('');
}


/** Setup the access keys */
if (process.env.TRAVIS) {
  process.env.SAUCE_ACCESS_KEY = decode(process.env.SAUCE_ACCESS_KEY);
  process.env.BROWSER_STACK_ACCESS_KEY = decode(process.env.BROWSER_STACK_ACCESS_KEY);
}

/** Build a list of configuration (custom launcher names). */
function buildConfiguration(type: string, target: string, required: boolean): string[] {
  return Object.keys(configuration)
    .map(item => [item, configuration[item][type]])
    .filter(([item, conf]) => conf.required == required && conf.target == target)
    .map(([item, conf]) => `${target}_${item.toUpperCase()}`);
}
