// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.acceptance.rest.change;

import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.extensions.client.ArchiveFormat;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.git.ObjectIds;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;

public class GetArchiveIT extends AbstractDaemonTest {
  private static final String DIRECTORY_NAME = "foo";
  private static final String FILE_NAME = DIRECTORY_NAME + "/bar.txt";
  private static final String FILE_CONTENT = "some content";

  private String changeId;
  private RevCommit commit;

  @Before
  public void setUp() throws Exception {
    PushOneCommit push =
        pushFactory.create(admin.newIdent(), testRepo, "My Change", FILE_NAME, FILE_CONTENT);
    PushOneCommit.Result result = push.to("refs/for/master");
    result.assertOkStatus();

    changeId = result.getChangeId();
    commit = result.getCommit();
  }

  @Test
  public void formatNotSpecified() throws Exception {
    BadRequestException ex =
        assertThrows(
            BadRequestException.class,
            () -> gApi.changes().id(changeId).current().getArchive(null));
    assertThat(ex).hasMessageThat().isEqualTo("format is not specified");
  }

  @Test
  public void unknownFormat() throws Exception {
    // Test this by a REST call, since the Java API doesn't allow to specify an unknown format.
    RestResponse res =
        adminRestSession.get(
            String.format(
                "/changes/%s/revisions/current/archive?format=%s", changeId, "unknownFormat"));
    res.assertBadRequest();
    assertThat(res.getEntityContent()).isEqualTo("unknown archive format");
  }

  @Test
  public void zipFormatIsDisabled() throws Exception {
    MethodNotAllowedException ex =
        assertThrows(
            MethodNotAllowedException.class,
            () -> gApi.changes().id(changeId).current().getArchive(ArchiveFormat.ZIP));
    assertThat(ex).hasMessageThat().isEqualTo("zip format is disabled");
  }

  @Test
  public void getTarArchive() throws Exception {
    BinaryResult res = gApi.changes().id(changeId).current().getArchive(ArchiveFormat.TAR);
    assertThat(res.getAttachmentName())
        .isEqualTo(commit.abbreviate(ObjectIds.ABBREV_STR_LEN).name() + ".tar");
    assertThat(res.getContentType()).isEqualTo("application/x-tar");
    assertThat(res.canGzip()).isFalse();

    byte[] archiveBytes = getBinaryContent(res);
    try (ByteArrayInputStream in = new ByteArrayInputStream(archiveBytes)) {
      HashMap<String, String> archiveEntries = getTarContent(in);
      assertThat(archiveEntries)
          .containsExactly(DIRECTORY_NAME + "/", null, FILE_NAME, FILE_CONTENT);
    }
  }

  @Test
  public void getTgzArchive() throws Exception {
    BinaryResult res = gApi.changes().id(changeId).current().getArchive(ArchiveFormat.TGZ);
    assertThat(res.getAttachmentName())
        .isEqualTo(commit.abbreviate(ObjectIds.ABBREV_STR_LEN).name() + ".tar.gz");
    assertThat(res.getContentType()).isEqualTo("application/x-gzip");
    assertThat(res.canGzip()).isFalse();

    byte[] archiveBytes = getBinaryContent(res);
    try (ByteArrayInputStream in = new ByteArrayInputStream(archiveBytes);
        GzipCompressorInputStream gzipIn = new GzipCompressorInputStream(in)) {
      HashMap<String, String> archiveEntries = getTarContent(gzipIn);
      assertThat(archiveEntries)
          .containsExactly(DIRECTORY_NAME + "/", null, FILE_NAME, FILE_CONTENT);
    }
  }

  private HashMap<String, String> getTarContent(InputStream in) throws Exception {
    HashMap<String, String> archiveEntries = new HashMap<>();
    int bufferSize = 100;
    try (TarArchiveInputStream tarIn = new TarArchiveInputStream(in)) {
      TarArchiveEntry entry;
      while ((entry = tarIn.getNextTarEntry()) != null) {
        if (entry.isDirectory()) {
          archiveEntries.put(entry.getName(), null);
        } else {
          byte data[] = new byte[bufferSize];
          try (ByteArrayOutputStream out = new ByteArrayOutputStream();
              BufferedOutputStream bufferedOut = new BufferedOutputStream(out, bufferSize)) {
            int count;
            while ((count = tarIn.read(data, 0, bufferSize)) != -1) {
              bufferedOut.write(data, 0, count);
            }
            bufferedOut.flush();
            archiveEntries.put(entry.getName(), out.toString(UTF_8));
          }
        }
      }
    }
    return archiveEntries;
  }

  private byte[] getBinaryContent(BinaryResult res) throws Exception {
    try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
      res.writeTo(out);
      return out.toByteArray();
    } finally {
      res.close();
    }
  }
}
