/*
 * Copyright 2022 the original author or authors.
 *
 * 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.
 */

package org.gradle.api.tasks.diagnostics;

import org.gradle.api.DefaultTask;
import org.gradle.api.Incubating;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal;
import org.gradle.api.internal.file.FileResolver;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.diagnostics.internal.configurations.formatter.TextConfigurationReportWriter;
import org.gradle.api.tasks.diagnostics.internal.configurations.formatter.ConfigurationReportSpec;
import org.gradle.api.tasks.diagnostics.internal.configurations.formatter.ConfigurationReportWriter;
import org.gradle.api.tasks.diagnostics.internal.configurations.model.ReportConfiguration;
import org.gradle.api.tasks.diagnostics.internal.configurations.model.ConfigurationReportModel;
import org.gradle.api.tasks.options.Option;
import org.gradle.internal.logging.text.StyledTextOutputFactory;
import org.gradle.work.DisableCachingByDefault;

import javax.inject.Inject;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Base class for tasks which reports on attributes of a variant or configuration.
 *
 * @since 7.5
 */
@Incubating
@DisableCachingByDefault(because = "Produces only non-cacheable console output")
public abstract class AbstractConfigurationReportTask extends DefaultTask {
    protected final Property<String> format = getProject().getObjects().property(String.class).convention("text");

    @Input
    @org.gradle.api.tasks.Optional
    @Option(option = "format", description = "The output format (text, json), defaults to text")
    public Property<String> getFormat() {
        return format;
    }

    @Inject
    protected StyledTextOutputFactory getTextOutputFactory() {
        throw new UnsupportedOperationException();
    }

    @Inject
    protected FileResolver getFileResolver() {
        throw new UnsupportedOperationException();
    }

    protected abstract ConfigurationReportSpec buildReportSpec();
    protected abstract Predicate<Configuration> buildEligibleConfigurationsFilter();

    @TaskAction
    public void report() {
        final ConfigurationReportSpec reportSpec = buildReportSpec();
        final ConfigurationReportModel reportModel = buildReportModel();
        final ConfigurationReportWriter writer = buildReportWriter();
        writer.writeReport(reportSpec, reportModel);
    }

    private ConfigurationReportModel buildReportModel() {
        return new ConfigurationReportModel(
            getProject().getName(),
            gatherConfigurationData(buildEligibleConfigurationsFilter()));
    }

    private ConfigurationReportWriter buildReportWriter() {
        switch (getFormat().get()) {
            case "text":
                return new TextConfigurationReportWriter(getTextOutputFactory().create(getClass()));
            default:
                throw new IllegalArgumentException("Unknown format: " + getFormat().get());
        }
    }

    private List<ReportConfiguration> gatherConfigurationData(Predicate<Configuration> filter) {
        return getProject().getConfigurations()
            .stream()
            .filter(filter)
            .sorted(Comparator.comparing(Configuration::getName))
            .map(ConfigurationInternal.class::cast)
            .map(c -> ReportConfiguration.fromConfigurationInProject(c, getProject(), getFileResolver()))
            .collect(Collectors.toList());
    }
}

@@ -2099,124 +2099,8 @@
 k %7B%0A
-    protected final Property%3CString%3E format = getProject().getObjects().property(String.class).convention(%22text%22);%0A%0A
     
@@ -2249,16 +2249,25 @@
  public 
+abstract 
 Property
@@ -2290,39 +2290,9 @@
 at()
- %7B%0A        return format;%0A    %7D
+;
 %0A%0A  
@@ -2315,16 +2315,25 @@
 otected 
+abstract 
 StyledTe
@@ -2374,68 +2374,14 @@
 ry()
- %7B%0A        throw new UnsupportedOperationException()
 ;%0A    
-%7D%0A
 %0A   
@@ -2403,16 +2403,25 @@
 otected 
+abstract 
 FileReso
@@ -2446,67 +2446,9 @@
 er()
- %7B%0A        throw new UnsupportedOperationException();%0A    %7D
+;
 %0A%0A  

Switch to abstract methods which are created by runtime decoration.