package com.atlassian.bitbucket.nav;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import static org.mockito.Mockito.mock;

/**
 * NavBuilder which can be used for tests without having to mock everything.
 * <p>
 * If you want to compare the resulting string to an expected one, it's best to also build it with this builder so that
 * the specific format is not hardcoded in your test.
 */
public class DummyNavBuilder {

    public static NavBuilder create() {
        return mock(NavBuilder.class, new RecordingAnswer(ImmutableList.<String>of()));
    }

    private static class RecordingAnswer implements Answer<Object> {

        private final ImmutableList<String> calls;

        private RecordingAnswer(ImmutableList<String> calls) {
            this.calls = calls;
        }

        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            Class<?> returnType = invocation.getMethod().getReturnType();
            String call = formatCall(invocation);
            ImmutableList<String> newCalls = ImmutableList.<String>builder().addAll(calls).add(call).build();
            if (returnType == String.class) {
                return Joiner.on(".").join(newCalls);
            }
            return mock(returnType, new RecordingAnswer(newCalls));
        }

        private String formatCall(InvocationOnMock invocation) {
            String methodName = invocation.getMethod().getName();
            Object[] args = invocation.getArguments();
            if (args == null || args.length == 0) {
                return methodName + "()";
            }
            return methodName + "(" + Joiner.on(", ").useForNull("null").join(args) + ")";
        }
    }
}
