use v6;
use Test::Async <When Base>;
use Test::Async::X;

plan 5, :parallel;

# Delete and set environment variables to build the testing environment.
%*ENV<RELEASE_TESTING>:delete;
%*ENV<NETWORK_TESTING>:delete;
%*ENV<SMOKE_TESTING>:delete;
%*ENV<AUTHOR_TESTING> = 1;
%*ENV<TEST_WHEN_FOO> = 1;
%*ENV<TEST_WHEN_BAR>:delete;

sub no-match($expect_msg, $message, *@p, *%n) {
    subtest $message => {
        plan 2;
        nok my $res = test-requires(|@p, |%n), "condition not fulfilled";
        is $res.message, $expect_msg, "no-match message";
    }
}

subtest "Conditions" => {
    plan 12, :parallel, :random;
    ok test-requires(:all(<author>)), "have AUTHOR_TESTING";
    ok test-requires(<release>, :all(<author>)), "positionals treated as any, second sub-condition fulfilled";
    ok test-requires(<author>, :all(<release>)), "positionals again, first sub-condition fulfilled";
    ok test-requires(:env<TEST_WHEN_FOO>), "with :env _TESTING isn't appened";
    ok test-requires(:any(:module(<Test::Async::__NOMOD>), :module<Test::Async>)), ":any with one successfull module";

    no-match '$RELEASE_TESTING', "no RELEASE_TESTING", :all(<release>);
    no-match '$RELEASE_TESTING', ":all with one fail", :all(<author release>);
    no-match 'any($RELEASE_TESTING, $NETWORK_TESTING)', ":any with all failing conditions", :any(<release network>);
    no-match 'module(Test::Async::__NOMOD)', "missing module", :module(<Test::Async::__NOMOD>);
    no-match 'module(Test::Async::__NOMOD1)',
             ":all with non-existing modules",
             :all(:module<Test::Async>,
                  :module<Test::Async::__NOMOD1>,
                  :module<Test::Async::__NOMOD2>);
    no-match 'any(module(Test::Async::__NOMOD1), module(Test::Async::__NOMOD2), $RELEASE_TESTING)',
             ":all with nested failing :any",
             :all(:any(:module<Test::Async::__NOMOD1>,
                  :module<Test::Async::__NOMOD2>, <release>),
                  :module<Test>);
    no-match '$TEST_WHEN_BAR', ":env fails on a missing env var", :env<TEST_WHEN_BAR>;
}

subtest "Nones" => {
    plan 6, :parallel, :random;
    ok test-requires(:none(<release netowrk>)), ":none with all environment variables missing";
    ok test-requires(:none(:any(<release smoke>), :all(<author>, :module(<Test::Async::__NOMOD>)))), ":none on both all and any";
    no-match 'none($AUTHOR_TESTING)', ":none with an existing environment variable", :none<release author>;
    no-match 'none(any(module(Test::Async)))', ":none on a fulfilled :any", :none(:any(<release>, :module<Test::Async>));
    no-match 'none(any(all(module(Test::Async), module(Test))))',
             ":none on a fulfilled :all",
             :none(:any(<release network>, :all(:module<Test::Async>, :module<Test>)));
    no-match 'none(none($RELEASE_TESTING, $NETWORK_TESTING))',
             ":none on a fulfilled :none",
             :none(:none(<release network>));
}

subtest "Errors" => {
    plan 1;
    throws-like { test-requires(:what<something>) },
                X::WhenCondition,
                "when with unknown condition throws",
                :message("Bad 'when' condition :what");
}

subtest "Plan 'when' condition skips" => {
    plan 2, :when(:any(<release network>));
    flunk "must not fail because 'when' would result in skipping this flunk";
    flunk "must not fail because 'when' would result in skipping this flunk";
}

subtest "Top suite 'when'" => {
    my @default-args = '-I' ~ $?FILE.IO.parent(2).add('lib');
    is-run q:to/TEST_CODE/, "'when' in a top suite plan",
                use Test::Async <When Base>;
                plan 4, :when(<release>);
                flunk "1. this flunk must be skipped";
                flunk "2. this flunk must be skipped";
                flunk "3. this flunk must be skipped";
                flunk "4. this flunk must be skipped";
                TEST_CODE
            :compiler-args(@default-args),
            :out("1..0 # Skipped: Unfulfilled when condition: \$RELEASE_TESTING\n# You planned 4 tests, but ran 0\n"),
            :err(''),
            :exitcode(0);
}

done-testing;
