/*
 * Licensed to ObjectStyle LLC under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ObjectStyle LLC 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.
 */
package io.bootique.junit5;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.bootique.BQCoreModule;
import io.bootique.BQRuntime;
import io.bootique.cli.Cli;
import io.bootique.command.CommandOutcome;
import io.bootique.command.CommandWithMetadata;
import io.bootique.config.ConfigurationFactory;
import io.bootique.log.BootLogger;
import io.bootique.meta.application.CommandMetadata;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.inject.Inject;
import java.util.Collections;

import static org.junit.jupiter.api.Assertions.*;

@BQTest
public class BQTestFactory_PerClass_IT {

    @BQTestTool
    static final BQTestFactory testFactory = new BQTestFactory();

    @Test
    @DisplayName("Args passed")
    public void testArgsPassed() {
        BQRuntime rt = testFactory.app("-x").args("-y").args(Collections.singleton("-z")).autoLoadModules().createRuntime();
        assertArrayEquals(new String[]{"-x", "-y", "-z"}, rt.getArgs());
    }

    @Test
    @DisplayName("Custom BootLogger")
    public void testBootLogger() {

        TestIO io = TestIO.noTrace();

        CommandOutcome result = testFactory.app("-x")
                .autoLoadModules()
                .module(b -> BQCoreModule.extend(b).addCommand(XCommand.class))
                .bootLogger(io.getBootLogger())
                .createRuntime()
                .run();

        assertTrue(result.isSuccess());
        assertEquals("--out--", io.getStdout().trim());
        assertEquals("--err--", io.getStderr().trim());
    }

    @Test
    @DisplayName("System props don't leak to test")
    public void testConfigEnvExcludes_System() {
        System.setProperty("bq.a", "bq_a");
        System.setProperty("bq.c.m.k", "bq_c_m_k");
        System.setProperty("bq.c.m.l", "bq_c_m_l");

        BQRuntime runtime = testFactory.app("--config=src/test/resources/configEnvironment.yml").createRuntime();

        Bean1 b1 = runtime.getInstance(ConfigurationFactory.class).config(Bean1.class, "");

        assertEquals("e", b1.a);
        assertEquals("q", b1.c.m.k);
        assertEquals("n", b1.c.m.l);

        System.clearProperty("bq.a");
        System.clearProperty("bq.c.m.k");
        System.clearProperty("bq.c.m.l");
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    static class Bean1 {
        private String a;
        private Bean2 c;

        public void setA(String a) {
            this.a = a;
        }

        public void setC(Bean2 c) {
            this.c = c;
        }
    }

    static class Bean2 {

        private Bean3 m;

        public void setM(Bean3 m) {
            this.m = m;
        }
    }

    static class Bean3 {
        private String k;
        private String f;
        private String l;

        public void setK(String k) {
            this.k = k;
        }

        public void setF(String f) {
            this.f = f;
        }

        public void setL(String l) {
            this.l = l;
        }
    }

    public static class XCommand extends CommandWithMetadata {

        private BootLogger logger;

        @Inject
        public XCommand(BootLogger logger) {
            super(CommandMetadata.builder(XCommand.class));
            this.logger = logger;
        }

        @Override
        public CommandOutcome run(Cli cli) {
            logger.stderr("--err--");
            logger.stdout("--out--");
            return CommandOutcome.succeeded();
        }
    }

}
