package com.atlassian.bitbucket.internal.scm.git.lfs.rest.model;

import com.atlassian.bitbucket.internal.scm.git.lfs.model.*;
import com.atlassian.bitbucket.rest.RestMapEntity;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.junit.Test;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertEquals;

/**
 * Deep test (i.e. tests the whole JSON document) for the RestBatchResponse
 */
@SuppressWarnings({"unchecked", "MismatchedQueryAndUpdateOfCollection"})
public class RestBatchResponseTest {

    private static final String TEST_OID1 = "7a6df2e0c99ff38b23405f28ccb092b6455975cbbc7cef1c51dc17a9f52de413";
    private static final long TEST_SIZE1 = Long.MAX_VALUE;
    private static final String TEST_OID2 = "d4fd625dfd37377fa497408df01e4bd572e3078e9c094be9fbea18c97d7e1711";
    private static final long TEST_SIZE2 = 1;
    private static final String TEST_URL = "https://bitbucket.example.com/";

    @Test
    public void testFromRestWithActions() {
        // Setup
        RestBatchResponse restResponse = new RestBatchResponse(createResponseWithActions());

        // Execute
        BatchResponse response = restResponse.fromRest();

        // Verify
        Collection<ResponseObject> objects = response.getObjects();
        assertEquals(1, objects.size());
        ResponseActionObject responseObject = (ResponseActionObject) objects.iterator().next();
        assertEquals(TEST_OID1, responseObject.getOid());
        assertEquals(TEST_SIZE1, responseObject.getSize());

        // getActions()
        assertEquals(1, responseObject.getActions().size());
        ResponseAction action = responseObject.getActions().iterator().next();
        assertEquals(OperationType.DOWNLOAD, action.getType());
        assertEquals("url", action.getHref());
        assertEquals("atoken", action.getHeaders().get("Authorization"));

        // getAction()
        assertEquals(action, responseObject.getAction(OperationType.DOWNLOAD).get());
    }

    @Test
    public void testFromRestWithError() {
        // Setup
        RestBatchResponse restResponse = new RestBatchResponse(createResponseWithError());

        // Execute
        BatchResponse response = restResponse.fromRest();

        // Verify
        Collection<ResponseObject> objects = response.getObjects();
        assertEquals(1, objects.size());
        ResponseErrorObject responseObject = (ResponseErrorObject) objects.iterator().next();
        assertEquals(TEST_OID1, responseObject.getOid());
        assertEquals(TEST_SIZE1, responseObject.getSize());
        assertEquals(404, responseObject.getErrorCode());
        assertEquals("Not found", responseObject.getMessage());
    }

    @Test
    public void toRestWithActions() {
        // Setup
        BatchResponse response = new BatchResponse(ImmutableList.of(
                new ResponseActionObject(TEST_OID1, TEST_SIZE1, ImmutableList.of(
                        new ResponseAction(OperationType.DOWNLOAD, TEST_URL + TEST_OID1))),
                new ResponseActionObject(TEST_OID2, TEST_SIZE2, ImmutableList.of(
                        new ResponseAction(OperationType.DOWNLOAD, TEST_URL + TEST_OID2)))
        ));

        // Execute
        RestBatchResponse restResponse = new RestBatchResponse(response);

        // Verify
        List<RestMapEntity> objects = (List<RestMapEntity>) restResponse.get("objects");
        assertEquals(2, objects.size());
        verifyActionResponse(objects.get(0), TEST_OID1, TEST_SIZE1);
        verifyActionResponse(objects.get(1), TEST_OID2, TEST_SIZE2);
    }

    @Test
    public void toRestWithError() {
        // Setup
        String message = "Object not found";
        int code = 404;
        BatchResponse response = new BatchResponse(ImmutableList.of(
                new ResponseErrorObject(TEST_OID1, TEST_SIZE1, code, message)));

        // Execute
        RestBatchResponse restResponse = new RestBatchResponse(response);

        // Verify
        List<RestMapEntity> objects = (List<RestMapEntity>) restResponse.get("objects");
        assertEquals(1, objects.size());

        RestMapEntity first = objects.get(0);
        assertEquals(TEST_OID1, first.get("oid"));
        assertEquals(TEST_SIZE1, first.get("size"));

        RestMapEntity errorEntity = (RestMapEntity) first.get("error");
        assertEquals(code, errorEntity.get("code"));
        assertEquals(message, errorEntity.get("message"));
    }

    private static Map<String, Object> createResponseWithActions() {
        Map<String, Object> download = ImmutableMap.of(
                "href", "url",
                "header", ImmutableMap.of("Authorization", "atoken"));

        Map<String, Object> actions = ImmutableMap.of("download", download);

        Map<String, Object> responseObject = ImmutableMap.of(
                "oid", TEST_OID1,
                "size", TEST_SIZE1,
                "actions", actions);

        return ImmutableMap.of("objects", ImmutableList.of(responseObject));
    }

    private static Map<String, Object> createResponseWithError() {
        Map<String, Object> responseError = ImmutableMap.of(
                "code", 404,
                "message", "Not found");

        Map<String, Object> responseObject = ImmutableMap.of(
                "oid", TEST_OID1,
                "size", TEST_SIZE1,
                "error", responseError);

        return ImmutableMap.of("objects", ImmutableList.of(responseObject));
    }

    private static void verifyActionResponse(RestMapEntity response, String oid, long size) {
        assertEquals(oid, response.get("oid"));
        assertEquals(size, response.get("size"));
        RestMapEntity actions = (RestMapEntity) response.get("actions");
        RestMapEntity download = (RestMapEntity) actions.get("download");
        assertEquals(TEST_URL + oid, download.get("href"));
    }
}