package org.implab.gradle.variants;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.util.Properties;

import org.gradle.testkit.runner.BuildResult;
import org.junit.jupiter.api.Test;

class PluginMarkerFunctionalTest extends AbstractFunctionalTest {

    @Test
    void pluginMarkersPointToCurrentImplementations() throws Exception {
        assertMarker("org.implab.gradle-variants.properties", VariantsPlugin.class);
        assertMarker("org.implab.gradle-sources.properties", SourcesPlugin.class);
        assertMarker("org.implab.gradle-variants-sources.properties", VariantSourcesPlugin.class);
        assertMarker("org.implab.gradle-variants-artifacts.properties", VariantArtifactsPlugin.class);
    }

    @Test
    void pluginIdsApplyCurrentExtensions() throws Exception {
        writeSettings("variants-plugin-ids");
        writeBuildFile("""
                apply plugin: 'org.implab.gradle-variants'
                apply plugin: 'org.implab.gradle-sources'
                apply plugin: 'org.implab.gradle-variants-sources'
                apply plugin: 'org.implab.gradle-variants-artifacts'

                tasks.register('probe') {
                    doLast {
                        println("variantsExtension=" + (project.extensions.findByName('variants') != null))
                        println("sourcesExtension=" + (project.extensions.findByName('sources') != null))
                        println("variantSourcesExtension=" + (project.extensions.findByName('variantSources') != null))
                        println("variantArtifactsExtension=" + (project.extensions.findByName('variantArtifacts') != null))
                    }
                }
                """);

        BuildResult result = runner("probe").build();

        assertTrue(result.getOutput().contains("variantsExtension=true"));
        assertTrue(result.getOutput().contains("sourcesExtension=true"));
        assertTrue(result.getOutput().contains("variantSourcesExtension=true"));
        assertTrue(result.getOutput().contains("variantArtifactsExtension=true"));
    }

    @Test
    void sourcesPluginSupportsStandaloneSourceSetWorkflow() throws Exception {
        writeSettings("sources-plugin-standalone");
        writeFile("inputs/main.js", "console.log('main')\n");
        writeBuildFile("""
                apply plugin: 'org.implab.gradle-sources'

                sources.create('main') {
                    declareOutputs('js')
                    registerOutput('js', layout.projectDirectory.file('inputs/main.js'))
                }

                tasks.register('probe') {
                    doLast {
                        def main = sources.named('main').get()
                        println("sourceSet=" + main.name)
                        println("sourceSetDir=" + project.relativePath(main.sourceSetDir.get().asFile))
                        println("outputsDir=" + project.relativePath(main.outputsDir.get().asFile))
                        println("jsFiles=" + main.output('js').files.collect { it.name }.sort().join(','))
                    }
                }
                """);

        BuildResult result = runner("probe").build();

        assertTrue(result.getOutput().contains("sourceSet=main"));
        assertTrue(result.getOutput().contains("sourceSetDir=src/main"));
        assertTrue(result.getOutput().contains("outputsDir=build/out/main"));
        assertTrue(result.getOutput().contains("jsFiles=main.js"));
    }

    private static void assertMarker(String markerName, Class<?> implementationClass) throws IOException {
        var resourceName = "META-INF/gradle-plugins/" + markerName;
        var resource = PluginMarkerFunctionalTest.class.getClassLoader().getResourceAsStream(resourceName);
        assertNotNull(resource, "Missing plugin marker " + resourceName);

        var properties = new Properties();
        properties.load(resource);
        assertEquals(implementationClass.getName(), properties.getProperty("implementation-class"));
    }
}
