/*
 * Copyright 2000-2013 JetBrains s.r.o.
 *
 * 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.intellij.tasks.integration;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.intellij.tasks.Task;
import com.intellij.tasks.TaskManagerTestCase;
import com.intellij.tasks.TaskState;
import com.intellij.tasks.config.TaskSettings;
import com.intellij.tasks.impl.LocalTaskImpl;
import com.intellij.tasks.impl.TaskUtil;
import com.intellij.tasks.jira.JiraRepository;
import com.intellij.tasks.jira.JiraRepositoryType;
import com.intellij.tasks.jira.JiraVersion;
import org.apache.commons.httpclient.methods.GetMethod;
import org.jetbrains.annotations.NonNls;

import java.util.Date;

/**
 * @author Dmitry Avdeev
 *         Date: 1/15/13
 */
public class JiraIntegrationTest extends TaskManagerTestCase {

  /**
   * JIRA 4.4.5, REST API 2.0.alpha1
   */
  @NonNls private static final String JIRA_4_TEST_SERVER_URL = "http://trackers-tests.labs.intellij.net:8014";
  /**
   * JIRA 5.0.6, REST API 2.0
   */
  @NonNls private static final String JIRA_5_TEST_SERVER_URL = "http://trackers-tests.labs.intellij.net:8015";

  private JiraRepository myRepository;

  public void testGerman() throws Exception {
    myRepository.setUsername("german");
    myRepository.setPassword("german");
    Task[] issues = myRepository.getIssues(null, 50, 0);
    assertEquals(3, issues.length);
    assertEquals(TaskState.OPEN, issues[0].getState());
    assertFalse(issues[0].isClosed());
  }

  public void testLogin() throws Exception {
    myRepository.setUsername("german");
    myRepository.setUsername("wrong password");
    //noinspection ConstantConditions
    Exception exception = myRepository.createCancellableConnection().call();
    assertNotNull(exception);
    assertEquals(JiraRepository.LOGIN_FAILED_CHECK_YOUR_PERMISSIONS, exception.getMessage());
  }

  public void testVersionDiscovery() throws Exception {
    myRepository.setUrl(JIRA_5_TEST_SERVER_URL);
    assertEquals("2.0", myRepository.discoverRestApiVersion().getVersionName());
    myRepository.setUrl(JIRA_4_TEST_SERVER_URL);
    assertEquals("2.0.alpha1", myRepository.discoverRestApiVersion().getVersionName());
  }

  public void testJqlQuery() throws Exception {
    myRepository.setSearchQuery("assignee = currentUser() AND (summary ~ 'foo' or resolution = Fixed)");
    assertEquals(2, myRepository.getIssues("", 50, 0).length);
  }

  /**
   * Holds only for JIRA > 5.x.x
   */
  public void testExtractedErrorMessage() throws Exception {
    myRepository.setSearchQuery("foo < bar");
    try {
      myRepository.getIssues("", 50, 0);
      fail();
    }
    catch (Exception e) {
      assertEquals("Request failed. Reason: \"Field 'foo' does not exist or you do not have permission to view it.\"", e.getMessage());
    }
  }

  public void testSetTaskState() throws Exception {
    changeStateAndCheck(JIRA_4_TEST_SERVER_URL, "PRJONE-8");
    changeStateAndCheck(JIRA_5_TEST_SERVER_URL, "UT-8");
  }

  public void testSetTimeSpend() throws Exception {
    // only REST API 2.0 supports this feature
    myRepository.setUrl(JIRA_5_TEST_SERVER_URL);
    Task task = myRepository.findTask("UT-9");
    assertNotNull("Test task not found", task);

    // timestamp as comment
    String comment = "Timestamp: " + TaskUtil.formatDate(new Date());

    // semi-unique duration as timeSpend
    // should be no longer than 8 hours in total, because it's considered as one full day
    int minutes = (int)(System.currentTimeMillis() % 240) + 1;
    String duration = String.format("%dh %dm", minutes / 60, minutes % 60);
    myRepository.updateTimeSpent(new LocalTaskImpl(task), duration, comment);

    // possible race conditions?
    GetMethod request = new GetMethod(myRepository.getRestUrl("issue", task.getId(), "worklog"));
    String response = myRepository.executeMethod(request);
    JsonObject object = new Gson().fromJson(response, JsonObject.class);
    JsonArray worklogs = object.get("worklogs").getAsJsonArray();
    JsonObject last = worklogs.get(worklogs.size() - 1).getAsJsonObject();
    assertEquals(comment, last.get("comment").getAsString());
    assertEquals(duration, last.get("timeSpent").getAsString());
  }

  private void changeStateAndCheck(String url, String key) throws Exception {
    myRepository.setUrl(url);
    Task task = myRepository.findTask(key);
    assertNotNull("Test task not found", task);
    assertEquals(String.format("Initial state of test task '%s' should be 'Reopened'", key),
                 TaskState.REOPENED, task.getState());
    try {
      myRepository.setTaskState(task, TaskState.RESOLVED);
      task = myRepository.findTask(key);
      assertEquals(task.getState(), TaskState.RESOLVED);
    } finally {
      try {
        // always attempt to restore original state of the issue
        myRepository.setTaskState(task, TaskState.REOPENED);
      }
      catch (Exception ignored) {
        // empty
      }
    }
  }

  public void testParseVersionNumbers() throws Exception {
    assertEquals(new JiraVersion("6.1-OD-09-WN").toString(), "6.1.9");
    assertEquals(new JiraVersion("5.0.6").toString(), "5.0.6");
    assertEquals(new JiraVersion("4.4.5").toString(), "4.4.5");
  }

  @Override
  public void setUp() throws Exception {
    super.setUp();
    TaskSettings.getInstance().CONNECTION_TIMEOUT = 10000;
    myRepository = new JiraRepository(new JiraRepositoryType());
    myRepository.setUrl(JIRA_5_TEST_SERVER_URL);
    myRepository.setUsername("buildtest");
    myRepository.setPassword("buildtest");
  }
}

@@ -4631,24 +4631,25 @@
 onObject();%0A
+%0A
     assertEq
@@ -4694,24 +4694,118 @@
 sString());%0A
+    // don't depend on concrete response format: zero hours stripping, zero padding and so on%0A
     assertEq
@@ -4809,24 +4809,28 @@
 tEquals(
-duration
+minutes * 60
 , last.g
@@ -4842,24 +4842,31 @@
 imeSpent
+Seconds
 %22).getAs
 String()
@@ -4853,30 +4853,27 @@
 onds%22).getAs
-String
+Int
 ());%0A  %7D%0A%0A  

Fix Jira test related to time tracking (zero hours case)