/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.carrotsearch.gradle.buildinfra.buildoptions.BuildOption
import java.nio.file.Files;
import org.apache.lucene.gradle.plugins.help.ExecOperationsProvider


description = 'Analyzers for indexing content in different languages and domains'

dependencies {
  moduleApi project(':lucene:core')
  moduleTestImplementation project(':lucene:test-framework')
}

// Enable Hunspell tests against LibreOffice/ Woorm dictionaries. We pull
// these dictionaries dynamically from git of each respective project. To keep
// things consistent across pull requests/ re-runs, we use a fixed git commit
// for each project ({@linkplain https://github.com/apache/lucene/issues/14235 #14235}),
// with a periodic workflow running against the latest commit on each
// project's respective development branch.

// A gradle property with the parent directory for all git clones for each project.
def cloneDirProperty = project.layout.buildDirectory.dir("hunspell-regressions")

// The list of dictionary projects to pull/ check against. Also includes
// a full commit reference for each project. These should be updated
// from time to time based on what's available at the head reference.
def dictionaryProjects = [
  [
    "name": "libreoffice",
    "url": "https://github.com/LibreOffice/dictionaries",
    "ref": "762abe74008b94b2ff06db6f4024b59a8254c467" // head: master
  ],
  [
    "name": "woorm",
    "url": "https://github.com/wooorm/dictionaries",
    "ref": "8cfea406b505e4d7df52d5a19bce525df98c54ab" // head: main
  ]
]

// Generate a set of tasks cloning the git repository of each project
// and setting it to the given reference (hash or named).
def cloningTasks = dictionaryProjects.collect { repoSpec ->
  def cloningTask = tasks.register(repoSpec.name + "CloneAndSetRef", {task ->
    def targetDir = cloneDirProperty.map { dir -> dir.dir(repoSpec.name) }

    // The repository reference should be taken from a gradle property or default to the stable
    // reference above.
    def ref = providers.gradleProperty("tests.hunspell." + repoSpec.name + ".ref").orElse(repoSpec.ref)

    // register task outputs.
    outputs.dir(targetDir)

    // register task inputs; we care about the url and ref.
    inputs.property("ref", ref)
    inputs.properties(repoSpec)

    doFirst {
      def execOps = objects.newInstance(ExecOperationsProvider).execOperations

      def logger = task.logger
      def dotGitPath = targetDir.get().asFile.toPath().toAbsolutePath().resolve(".git")
      def gitExec = { List<String> cmdArgs ->
        logger.lifecycle("Executing git " + cmdArgs.join(" "))
        execOps.exec {
          executable = buildGlobals.externalTool("git")
          ignoreExitValue = false
          workingDir dotGitPath.getParent().toString()
          args = cmdArgs

          // An explicit GIT_DIR to prevent .git upward scanning.
          environment("GIT_DIR", dotGitPath.toString())
        }
      }

      // if the target doesn't exist, create an empty repository, set
      // the remote url (origin) but don't fetch anything.
      if (!Files.exists(dotGitPath)) {
        Files.createDirectories(dotGitPath.getParent())
        gitExec([
          "init",
          "--initial-branch",
          "irrelevant"
        ])
        gitExec([
          "config",
          "advice.detachedHead",
          "false"
        ])
        gitExec([
          "remote",
          "add",
          "origin",
          repoSpec.url
        ])
      }

      // Fetch just the revision we're interested in.
      // This avoids downloading the entire repo.
      gitExec([
        "fetch",
        "--depth",
        "1",
        "origin",
        ref.get()
      ])
      gitExec(["checkout", "FETCH_HEAD"])
    }
  })
  return cloningTask
}

// check if we should run tests with hunspell dictionaries.
Provider<Boolean> testRegressionsOption = buildOptions.addBooleanOption("tests.hunspell.regressions",
    "Include testing for regressions against hunspell dictionaries", false)

if (testRegressionsOption.get()) {
  tasks.withType(Test).configureEach {
    dependsOn cloningTasks
    inputs.dir cloneDirProperty
    systemProperty "hunspell.dictionaries", cloneDirProperty.map { dir -> dir.asFile.absolutePath }.get()
  }
}

// Pass all hunspell-tests-specific project properties to tests as system properties, if they're specified.
buildOptions.addOption("hunspell.dictionaries", "Path to hunspell dictionaries for TestAllDictionaries.")
buildOptions.addOption("hunspell.corpora", "Path to hunspell test work corpora for TestPerformance.")
buildOptions.addOption("hunspell.repo.path", "Path to hunspell repo path for TestHunspellRepositoryTestCases")

tasks.withType(Test).configureEach {
  [
    "hunspell.dictionaries",
    "hunspell.corpora",
    "hunspell.repo.path"
  ].each {optionName ->
    BuildOption option = buildOptions.getOption(optionName)
    if (option.isPresent()) {
      def val = option.asStringProvider().get()
      logger.lifecycle("Passing property: ${optionName}=${val}")
      systemProperty(optionName, val)
    }
  }
}
