package com.atlassian.bitbucket.rest.exception;

import com.atlassian.bitbucket.rest.RestErrorMessage;
import com.atlassian.bitbucket.rest.RestErrors;
import com.atlassian.bitbucket.rest.util.StatefulJsonWriter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Test;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Collections;
import java.util.List;

import static org.junit.Assert.*;

public class RestErrorsTest {

    @Test
    public void testEndScopeAndWriteTo() throws IOException {
        try (StringWriter out = new StringWriter();
             StatefulJsonWriter writer = new StatefulJsonWriter(new ObjectMapper().getJsonFactory().createJsonGenerator(out))) {
            writer.beginObject();
            writer.name("foo").value("bar");
            assertTrue("Error property should have been written", new RestErrors("error").endScopeAndTryWriteTo(writer));
            writer.flush();

            assertEquals("{\"foo\":\"bar\",\"errors\":[{\"context\":null,\"message\":\"error\",\"exceptionName\":null}]}", out.toString());
        }
    }

    @Test
    public void testEndScopeAndWriteToWhenAtRoot() throws IOException {
        try (StringWriter out = new StringWriter();
             StatefulJsonWriter writer = new StatefulJsonWriter(new ObjectMapper().getJsonFactory().createJsonGenerator(out))) {
            assertTrue("Error property should have been written", new RestErrors("error").endScopeAndTryWriteTo(writer));
            writer.flush();

            assertEquals("{\"errors\":[{\"context\":null,\"message\":\"error\",\"exceptionName\":null}]}", out.toString());
        }
    }

    @Test
    public void testEndScopeAndWriteToWhenAtRootWithObjectAlreadyOutput() throws IOException {
        try (StringWriter out = new StringWriter();
             StatefulJsonWriter writer = new StatefulJsonWriter(new ObjectMapper().getJsonFactory().createJsonGenerator(out))) {
            writer.beginObject();
            writer.name("foo").value("bar");
            writer.endObject();
            assertFalse("Error property should not have been written", new RestErrors("error").endScopeAndTryWriteTo(writer));
            writer.flush();

            assertEquals("{\"foo\":\"bar\"}", out.toString());
        }
    }

    @Test
    public void testEndScopeAndWriteToWhenAtRootWithArrayInProgress() throws IOException {
        try (StringWriter out = new StringWriter();
             StatefulJsonWriter writer = new StatefulJsonWriter(new ObjectMapper().getJsonFactory().createJsonGenerator(out))) {
            writer.beginArray();
            assertFalse("Error property should not have been written", new RestErrors("error").endScopeAndTryWriteTo(writer));
            writer.flush();

            assertEquals("[]", out.toString());
        }
    }

    @Test
    public void testRestErrorMessageConversion() throws Exception {
        RestErrors errors = new RestErrors();
        errors.put("errors", ImmutableList.builder()
                .add(ImmutableMap.builder().put("context", "foo").put("message", "Error!").build())
                .add(ImmutableMap.builder().put("context", "bar").put("message", "Error!").build())
                .add(new RestErrorMessage("baz", "Error!"))
                .add(Collections.emptyMap())
                .add(new Object())
                .build());

        List<RestErrorMessage> errorMessages = errors.getErrors();

        assertEquals(4, errorMessages.size());

        assertEquals("foo", errorMessages.get(0).getContext());
        assertEquals("Error!", errorMessages.get(0).getMessage());
        assertNull(errorMessages.get(0).getExceptionName());
        assertEquals("bar", errorMessages.get(1).getContext());
        assertEquals("Error!", errorMessages.get(1).getMessage());
        assertNull(errorMessages.get(1).getExceptionName());
        assertEquals("baz", errorMessages.get(2).getContext());
        assertEquals("Error!", errorMessages.get(2).getMessage());
        assertNull(errorMessages.get(2).getExceptionName());
        assertNull(errorMessages.get(3).getContext());
        assertNull(errorMessages.get(3).getMessage());
        assertNull(errorMessages.get(3).getExceptionName());
    }
}
