/*
 * 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.
 */

/*
 * SOLR-14920 modelled on LUCENE-9564: This adds automatic (and enforced) code formatting using
 * spotless and Google Java Format.
 */

configure(allprojects) { prj ->
  plugins.withType(JavaPlugin) {
    prj.apply plugin: libs.plugins.diffplug.spotless.get().pluginId

    project.ext {
      spotlessJavaSetup = (Action){
        it.toggleOffOn() // obviously, only to be used sparingly.
        // TODO: Work out how to support multiple different header files (we have
        // classes in the codebase that have original headers). We currently use
        // Apache RAT to enforce headers so this is of lesser priority.
        //
        // it.licenseHeaderFile(file("${resources}/asl-header.txt"), '^(\\s*package)')
        it.setLineEndings(Enum.valueOf(rootProject.buildscript.classLoader.loadClass("com.diffplug.spotless.LineEnding"), "UNIX"))
        it.endWithNewline()
        it.googleJavaFormat(libs.versions.google.javaformat.get())

        it.custom('Refuse wildcard imports', { line ->
          // Wildcard imports can't be resolved by spotless itself.
          // This will require the developer themselves to adhere to best practices.
          if (line =~ /\nimport .*\*;/) {
            throw new AssertionError("Do not use wildcard imports.  'spotlessApply' cannot resolve this issue.")
          }
          line
        })
      }
    }

    spotless {
      java {
        prj.ext.spotlessJavaSetup.execute(it)

        // Apply to all Java sources
        target "src/**/*.java"

        // Exclude certain files (generated ones, mostly).
        switch (project.path) {
          case ":solr:core":
            // These are excluded since they are generated by javacc
            targetExclude "src/java/org/apache/solr/parser/ParseException.java",
              "src/java/org/apache/solr/parser/QueryParser.java",
              "src/java/org/apache/solr/parser/QueryParserConstants.java",
              "src/java/org/apache/solr/parser/QueryParserTokenManager.java",
              "src/java/org/apache/solr/parser/Token.java",
              "src/java/org/apache/solr/parser/TokenMgrError.java"
            break
          case ":solr:solr-ref-guide":
            // Apply to all example Java sources in the ref-guide
            target "modules/**/examples/*.java"
            break
        }
      }
    }

    // Workaround for an odd problem in spotless where it fails because
    // of a missing folder.
    spotlessJava {
      doFirst {
        project.mkdir("${buildDir}/spotless/spotlessJava")
      }
    }

    // Schedule the core formatting task to run after Java compilation (GH-12012)
    spotlessJava {
      mustRunAfter tasks.withType(JavaCompile)
    }
  }

  // Configure spotless for kotlin sources
  plugins.withId("org.jetbrains.kotlin.multiplatform") {
    prj.apply plugin: libs.plugins.diffplug.spotless.get().pluginId

    spotless {
      kotlin {
        // Apply to all Kotlin and Kotlin DSL files
        target "**/*.kt", "**/*.kts"

        ktlint(libs.versions.ktlint.get())
            .customRuleSets([libs.nlopez.compose.ktlintrules.get().toString()])
      }
    }
  }

  // Emit a custom message about how to fix formatting errors.
  tasks.matching { task -> task.name == "spotlessJavaCheck" }.configureEach {
    it.runToFixMessage.set("\nIMPORTANT: run the top-level './gradlew tidy' to format code automatically (see dev-docs/gradle-help/formatting.txt for more info).")
  }

  // Hook up spotless to tidy and check tasks.

  tasks.matching { it.name == "tidy" }.configureEach { v ->
    v.dependsOn tasks.matching { it.name == "spotlessApply" }
  }

  tasks.matching { it.name == "check" }.configureEach { v ->
    v.dependsOn tasks.matching { it.name == "spotlessCheck" }
  }

  tasks.matching { task -> task.name in ["spotlessApply", "spotlessCheck"] }.configureEach { v ->
    v.dependsOn ":checkJdkInternalsExportedToGradle"
  }
}
