/*
 * Copyright Thoughtworks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.thoughtworks.go.build.Architecture
import com.thoughtworks.go.build.DownloaderTask
import com.thoughtworks.go.build.YarnRunTask

import java.util.regex.Pattern

import static com.thoughtworks.go.build.OperatingSystemHelper.CURRENT_OS

Architecture currentArch = Architecture.current()

// Chrome:        See https://googlechromelabs.github.io/chrome-for-testing/ Must match version of Chrome on build host
// Firefox/gecko: See https://github.com/mozilla/geckodriver/releases and review compatibility at
//                https://firefox-source-docs.mozilla.org/testing/geckodriver/Support.html
final Map<String, String> seleniumDrivers = [
  chromedriver: '141.0.7390.76',
  geckodriver : '0.36.0',
]

def execute = { String path, String... argv ->
  try {
    return providers.exec {
      def pathVariable = 'PATH'
      if (CURRENT_OS.isWindows()) {
        // because windows PATH variable is case-insensitive :-/
        pathVariable = environment.keySet().find { eachKey -> eachKey.toUpperCase().equals("PATH") }
      }
      environment[pathVariable] = path
      executable = argv.head()

      // java's ProcessBuilder does not lookup executables on `PATH` specified in the environment map
      // it instead looks up executable on the PATH of the caller.
      def executableName = CURRENT_OS.getExecutableName(executable)

      for (String entryInPath : path.split(Pattern.quote(File.pathSeparator))) {
        def candidateExecutable = new File(entryInPath, executableName)
        if (candidateExecutable.isFile() && candidateExecutable.canExecute()) {
          executable = candidateExecutable
          break
        }
      }

      commandLine(argv.tail())
    }.standardOutput.asText.getOrElse("could not determine version!").trim()
  } catch (Exception ignored) {
    return "could not determine version!"
  }
}

def browser = { ->
  if (System.getenv('BROWSER')) {
    return System.getenv('BROWSER')
  }

  return 'firefox'
}

def browserExecutable = { String path ->
  def separator = "=" * 72
  println "Browser versions"
  println(separator)
  switch (browser()) {
    case 'chrome':
      println("       chrome: ${execute(path, "google-chrome", "--version")}")
      println(" chromedriver: ${execute(path, "chromedriver", "--version").readLines().first()}")
      return
    default:
      println("     firefox: ${execute(path, "firefox", "--version")}")
      println(" geckodriver: ${execute(path, "geckodriver", "--version").readLines().first()}")
      return
  }
}

def driverImpl = { ->
  switch (browser()) {
    case 'chrome':
      return downloadChromeDriver
    default:
      return downloadGeckoDriver
  }
}

tasks.register('downloadGeckoDriver', DownloaderTask) { thisTask ->
  executable = 'geckodriver'
  packageName = 'geckodriver'
  packageVersion = seleniumDrivers.geckodriver

  String archiveExtension = CURRENT_OS.isWindows() ? 'zip' : 'tar.gz'
  String osURIPart
  if (CURRENT_OS.isMacOsX()) {
    osURIPart = currentArch == Architecture.aarch64 ? 'macos-aarch64' : 'macos'
  } else if (CURRENT_OS.isWindows()) {
    osURIPart = currentArch == Architecture.aarch64 ? 'win-aarch64' : 'win64'
  } else if (CURRENT_OS.isLinux()) {
    osURIPart = currentArch == Architecture.aarch64 ? 'linux-aarch64' : 'linux64'
  } else {
    throw new IllegalStateException("Unsupported OS ${CURRENT_OS}")
  }
  url = "https://github.com/mozilla/geckodriver/releases/download/v${packageVersion}/geckodriver-v${packageVersion}-${osURIPart}.${archiveExtension}"
}

tasks.register('downloadChromeDriver', DownloaderTask) { thisTask ->
  executable = 'chromedriver'
  packageName = 'chromedriver'
  packageVersion = seleniumDrivers.chromedriver

  String osURIPart
  if (CURRENT_OS.isMacOsX()) {
    osURIPart = currentArch == Architecture.aarch64 ? 'mac-arm64' : 'mac-x64'
  } else if (CURRENT_OS.isWindows()) {
    osURIPart = 'win64'
  } else if (CURRENT_OS.isLinux()) {
    osURIPart = 'linux64'
  } else {
    throw new IllegalStateException("Unsupported OS ${CURRENT_OS}")
  }
  url = "https://storage.googleapis.com/chrome-for-testing-public/${packageVersion}/${osURIPart}/chromedriver-${osURIPart}.zip"
}

tasks.register('jasmineKarma', YarnRunTask) {
  description = 'Run new jasmine tests (typescript) via karma'
  dependsOn ':server:yarnInstall'
  dependsOn ':server:lintNew'
  dependsOn ':server:compileAssetsWebpackDev'

  outputs.upToDateWhen { false }
  workingDir = project.railsRoot

  yarnCommand = ['jasmine-ci']
}

tasks.register('jasmineOld', YarnRunTask) {
  description = 'Run old jasmine tests (legacy JS) via jasmine-browser-runner'
  dependsOn driverImpl()
  dependsOn ':server:yarnInstall'
  dependsOn ':server:lintOld'
  dependsOn ':server:compileAssetsRailsTest'

  outputs.upToDateWhen { false }
  workingDir = project.railsRoot

  yarnCommand = ['jasmine-old-ci']

  doFirst {
    additionalPath = driverImpl().ext.outputDir
    browserExecutable(additionalPath)
  }
}

tasks.register('jasmine') {
  dependsOn ':server:lint', jasmineKarma, jasmineOld
}

tasks.register('jasmineKarmaServer', YarnRunTask) {
  description = 'Run new jasmine tests (typescript) via karma inside a browser'
  dependsOn ':server:yarnInstall'
  dependsOn ':server:compileAssetsWebpackDev'

  outputs.upToDateWhen { false }
  workingDir = project.railsRoot

  yarnCommand = ['jasmine-server']
}

tasks.register('jasmineOldServer', YarnRunTask) {
  description = 'Run old jasmine tests (legacy JS) via jasmine-browser-runner inside a browser'
  dependsOn driverImpl()
  dependsOn ':server:yarnInstall'
  dependsOn ':server:compileAssetsRailsTest'

  outputs.upToDateWhen { false }
  workingDir = project.railsRoot

  yarnCommand = ['jasmine-old-server']

  doFirst {
    additionalPath = driverImpl().ext.outputDir
    browserExecutable(additionalPath)
  }
}
