package com.atlassian.bitbucket.internal.mirroring.mirror.user;

import com.atlassian.bitbucket.permission.*;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.collection.IsIterableContainingInAnyOrder;
import org.hamcrest.collection.IsIterableWithSize;

import javax.annotation.Nonnull;

import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.equalTo;

public class EffectivePermissionsMatchers {
    public static Matcher<Iterable<? extends EffectivePermission>> matcherFor(@Nonnull Iterable<EffectivePermission> expectedEffectivePermissions) {
        return allOf(new IsIterableWithSize<>(equalTo(Iterables.size(expectedEffectivePermissions))),
                new IsIterableContainingInAnyOrder(Lists.newArrayList(Iterables.transform(expectedEffectivePermissions, item -> matcherFor(item)))));
    }

    public static Matcher<EffectivePermission> matcherFor(EffectivePermission effectivePermission) {
        return effectivePermission.accept(new EffectivePermissionVisitor<Matcher<EffectivePermission>>() {
            @Override
            public Matcher<EffectivePermission> visit(@Nonnull final EffectiveGlobalPermission permission) {
                return new BaseMatcher<EffectivePermission>() {
                    @Override
                    public boolean matches(Object item) {
                        return item instanceof EffectiveGlobalPermission && ((EffectiveGlobalPermission) item).getPermission() == permission.getPermission();
                    }

                    @Override
                    public void describeTo(Description description) {
                        description.appendText("EffectiveGlobalPermission{" + permission.getPermission() + "}");
                    }
                };
            }

            @Override
            public Matcher<EffectivePermission> visit(@Nonnull final EffectiveRepositoryPermission permission) {
                return new BaseMatcher<EffectivePermission>() {
                    @Override
                    public boolean matches(Object item) {
                        return item instanceof EffectiveRepositoryPermission
                                && ((EffectiveRepositoryPermission) item).getPermission() == permission.getPermission()
                                && ((EffectiveRepositoryPermission) item).getRepositoryId() == permission.getRepositoryId();
                    }

                    @Override
                    public void describeTo(Description description) {
                        description.appendText("EffectiveRepositoryPermission{" + permission.getPermission() + ",repositoryId=" + permission.getRepositoryId() + "}");
                    }
                };
            }

            @Override
            public Matcher<EffectivePermission> visit(@Nonnull final EffectiveProjectPermission permission) {
                return new BaseMatcher<EffectivePermission>() {
                    @Override
                    public boolean matches(Object item) {
                        return item instanceof EffectiveProjectPermission
                                && ((EffectiveProjectPermission) item).getPermission() == permission.getPermission()
                                && ((EffectiveProjectPermission) item).getProjectId() == permission.getProjectId();
                    }

                    @Override
                    public void describeTo(Description description) {
                        description.appendText("EffectiveProjectPermission{" + permission.getPermission() + ",projectId=" + permission.getProjectId() + "}");
                    }
                };
            }
        });
    }
}
