/*
 * Copyright (C) 2003-2016 eXo Platform SAS.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.exoplatform.cs.test;

import java.util.ArrayList;
import java.util.List;

import org.exoplatform.commons.testing.BaseExoTestCase;
import org.exoplatform.commons.utils.CommonsUtils;
import org.exoplatform.component.test.ConfigurationUnit;
import org.exoplatform.component.test.ConfiguredBy;
import org.exoplatform.component.test.ContainerScope;
import org.exoplatform.cs.dto.BasicEntityDTO;
import org.exoplatform.cs.dto.EnvironmentDTO;
import org.exoplatform.cs.dto.InfoType;
import org.exoplatform.cs.dto.IssueSeverity;
import org.exoplatform.cs.dto.IssueType;
import org.exoplatform.cs.dto.SpaceDTO;
import org.exoplatform.cs.dto.TicketDTO;
import org.exoplatform.cs.dto.TypeDTO;
import org.exoplatform.cs.entity.EnvTypeEntity;
import org.exoplatform.cs.service.CSSpaceService;
import org.exoplatform.cs.service.EnvironmentService;
import org.exoplatform.cs.service.TicketService;
import org.exoplatform.forum.service.ForumService;
import org.exoplatform.forum.service.Tag;
import org.exoplatform.forum.service.Topic;
import org.exoplatform.forum.service.Utils;
import org.exoplatform.services.organization.OrganizationService;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.security.ConversationState;
import org.exoplatform.services.security.Identity;
import org.exoplatform.social.core.space.SpaceUtils;
import org.exoplatform.task.domain.Priority;
import org.exoplatform.task.service.TaskService;

/**
 * Created by The eXo Platform SAS
 * 
 * @author boubaker.khanfir@exoplatform.com
 * @since Apr 27, 2016
 */
@ConfiguredBy({
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/exo.portal.component.identity-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/portal/exo.portal.component.portal-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/exo.portal.component.test.jcr-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/social/exo.social.test.portal-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/social/exo.social.test.jcr-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/social/exo.social.component.common.test.configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/social/exo.social.component.core.test.configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/social/exo.social.component.core.test.application.registry.configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/social/component.search.configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/portal/test-cs-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/portal/test-portal-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/forum/test-forum-jcr-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/forum/test-forum-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/task/integration-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/task/test-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/customer-space/cs-configuration.xml"),
    @ConfigurationUnit(scope = ContainerScope.ROOT, path = "conf/portal/test-db-configuration.xml") })
public class CSServicesTest extends BaseExoTestCase {
  private static final String TEST_USER            = "demo";

  private static final String TAG_PREF             = "TAGPREF";

  private static final String PRODUCT_VERSION      = "4.3.0";

  private static final String PRODUCTION_ENV_TYPE  = "PRODUCTION";

  private static final String ENVIRONMENT_NAME     = "Production";

  private static final String SPACE_GROUP_ID       = "/spaces/space_1";

  private static final String SPACE_NAME           = "space_1";

  private static final String SPACE_MANAGERS_GROUP = "/platform/administrators";

  private static final String INVITED_MEMBERS_GROUP = "/platform/invited";

  List<EnvironmentDTO>        environments         = new ArrayList<EnvironmentDTO>();

  EnvironmentService          environmentService;

  CSSpaceService              csSpaceService;

  TicketService               ticketService;

  OrganizationService         organizationService;

  ForumService                forumService;

  TaskService                 taskService;

  protected void setUp() {
    environmentService = CommonsUtils.getService(EnvironmentService.class);
    csSpaceService = CommonsUtils.getService(CSSpaceService.class);
    ticketService = CommonsUtils.getService(TicketService.class);
    organizationService = CommonsUtils.getService(OrganizationService.class);
    forumService = CommonsUtils.getService(ForumService.class);
    taskService = CommonsUtils.getService(TaskService.class);

    // Needed for Task management
    Identity testUser = new Identity(TEST_USER);
    ConversationState.setCurrent(new ConversationState(testUser));

    begin();
  }

  public void testSpace() {
    for (int i = 0; i < 3; i++) {
      String spaceName = SPACE_NAME + i;
      String spaceGroupId = SpaceUtils.SPACE_GROUP + "/" + spaceName;
      try {
        SpaceDTO spaceDTO = csSpaceService.getSpace(spaceGroupId);
        assertNull("Space '" + SPACE_NAME + i + "' shouldn't be found", spaceDTO);

        saveSpace(spaceName, spaceGroupId);

        spaceDTO = csSpaceService.getSpace(spaceGroupId);
        assertNotNull("Space '" + SPACE_NAME + i + "' shouldn't be null", spaceDTO);
      } catch (Exception e) {
        fail("Error while getting/saving Space '" + spaceName + "'", e);
      }
    }

    assertEquals("Spaces count is not coherent", 3, csSpaceService.getSpacesCount());

    List<SpaceDTO> spaceDTOs = csSpaceService.getSpaces(0, 2);
    assertNotNull(spaceDTOs);
    assertEquals("Requested spaces with offset+limit is not coherent", 2, spaceDTOs.size());
  }

  public void testEnvironment() throws Exception {
    saveSpace(SPACE_NAME, SPACE_GROUP_ID);
    for (int i = 0; i < 2; i++) {
      EnvironmentDTO environmentDTO = saveNewEnvironment(SPACE_GROUP_ID);
      assertNotNull(environmentDTO);
    }

    assertEquals(2, environmentService.getSpaceEnvironments(SPACE_GROUP_ID).size());
  }

  public void testTicket() {
    try {
      List<EnvironmentDTO> environmentDTOs = environmentService.getSpaceEnvironments(SPACE_GROUP_ID);

      TicketDTO ticketDTO = new TicketDTO();
      ticketDTO.setSpaceGroupId(environmentDTOs.get(0).getSpaceGroupId());
      ticketDTO.setEnvironmentId(environmentDTOs.get(0).getId());
      ticketDTO.setInfoType(InfoType.INFO_1);
      ticketDTO.setDescription("Description");
      ticketDTO.setType(IssueType.PRODUCT);
      ticketDTO.setTitle("Title");

      User user = organizationService.getUserHandler().findUserByName(TEST_USER);

      ticketService.createTicket(ticketDTO, user, null);

      String topicId = ticketDTO.getId();
      assertNotNull("id of ticket is null after save", topicId);

      long taskId = Long.parseLong(topicId);

      assertNotNull("Task with id '" + taskId + "' was not found", taskService.getTask(taskId));

      ticketDTO = new TicketDTO();
      ticketDTO.setSpaceGroupId(environmentDTOs.get(0).getSpaceGroupId());
      ticketDTO.setEnvironmentId(environmentDTOs.get(0).getId());
      ticketDTO.setSeverity(IssueSeverity.SEVERITY_1);
      ticketDTO.setDescription("Description");
      ticketDTO.setType(IssueType.INCIDENT);
      ticketDTO.setTitle("Title");

      ticketService.createTicket(ticketDTO, user, null);

      assertNotNull("id of ticket is null after save", topicId);

      String catId = forumService.getCategoryIncludedSpace().getId();
      String forumId = Utils.FORUM_SPACE_ID_PREFIX + SPACE_NAME;
      topicId = ticketDTO.getId();

      Topic topic = forumService.getTopic(catId, forumId, topicId, "root");
      assertNotNull("Forum Topic with id '" + topicId + "' was not found", topic);
      assertNotNull("link of ticket is null after save", ticketDTO.getLink());
      assertNotNull(ticketService.getTopicEnvironment(topicId));

      String[] tagsId = topic.getTagId();
      assertTrue("", tagsId != null && tagsId.length > 0);

      String tagId = tagsId[0].split(":")[1];
      Tag tag = forumService.getTag(tagId);
      assertNotNull("Tag for Topic '" + topicId + "' with id '" + tagId + "' wasn't found", tag);

    } catch (Exception e) {
      fail("Failed to save ticket", e);
    }
  }

  protected void tearDown() {
    ConversationState.setCurrent(null);
    end();
  }

  private SpaceDTO saveSpace(String spaceName, String spaceGroupId) {
    SpaceDTO spaceDTO = new SpaceDTO();
    spaceDTO.setGroupId(spaceGroupId);
    spaceDTO.setName(spaceName);
    spaceDTO.setManagersGroupId(new BasicEntityDTO("@" + SPACE_MANAGERS_GROUP, SPACE_MANAGERS_GROUP));
    spaceDTO.setInvitedMembersGroupId(new BasicEntityDTO("@" + INVITED_MEMBERS_GROUP, INVITED_MEMBERS_GROUP));
    spaceDTO.setTagPrefix(TAG_PREF);
    spaceDTO.setTaskDefaultAssignee(new BasicEntityDTO("@" + TEST_USER, TEST_USER));
    spaceDTO.setTaskPriority(Priority.NORMAL);
    spaceDTO.setOwner(TEST_USER);

    try {
      csSpaceService.saveSpace(spaceDTO);
    } catch (Exception e) {
      fail("Error while saving space", e);
    }
    return spaceDTO;
  }

  private EnvironmentDTO saveNewEnvironment(String groupId) throws Exception {
    TypeDTO typeDTO = new TypeDTO();
    typeDTO.setLabel(PRODUCTION_ENV_TYPE);
    typeDTO.setType(TypeDTO.getTypeFromClass(EnvTypeEntity.class));
    typeDTO = environmentService.saveType(typeDTO);

    EnvironmentDTO environment = new EnvironmentDTO();
    environment.setName(ENVIRONMENT_NAME);
    environment.setSpaceGroupId(groupId);
    environment.setTypeId(typeDTO.getId());
    environment.setDefaultEnvironment(true);
    environment.setProductVersion(PRODUCT_VERSION);

    try {
      environment = environmentService.saveEnvironment(environment);
    } catch (Exception e) {
      fail("Error while saving environment", e);
    }

    environments.add(environment);
    return environment;
  }
}
