package org.exoplatform.cs.portlet.space;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;


import javax.inject.Inject;

import juzu.HttpMethod;
import juzu.MimeType;
import juzu.Path;
import juzu.Resource;
import juzu.Response;
import juzu.SessionScoped;
import juzu.View;
import juzu.plugin.jackson.Jackson;
import juzu.template.Template;

import org.exoplatform.commons.api.notification.NotificationContext;
import org.exoplatform.commons.api.notification.model.PluginKey;
import org.exoplatform.commons.juzu.ajax.Ajax;
import org.exoplatform.commons.notification.impl.NotificationContextImpl;
import org.exoplatform.commons.utils.ListAccess;
import org.exoplatform.cs.dto.BasicEntityDTO;
import org.exoplatform.cs.dto.SpaceDTO;
import org.exoplatform.cs.dto.TicketDTO;
import org.exoplatform.cs.entity.SpaceEntity;
import org.exoplatform.cs.exception.EntityAlreadyExistsException;
import org.exoplatform.cs.integration.notification.CSAnnouncementPlugin;
import org.exoplatform.cs.portlet.common.CSControllerBase;
import org.exoplatform.cs.service.CSSpaceService;
import org.exoplatform.cs.service.TicketService;
import org.exoplatform.cs.service.sla.Sla;
import org.exoplatform.cs.service.sla.SlaService;
import org.exoplatform.cs.service.subscription.Subscription;
import org.exoplatform.cs.service.subscription.SubscriptionService;
import org.exoplatform.cs.service.tickets.Flow;
import org.exoplatform.cs.service.tickets.TicketStatusFlowService;
import org.exoplatform.cs.service.util.SpacePageUtils;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.organization.Group;
import org.exoplatform.services.organization.OrganizationService;
import org.exoplatform.services.organization.Query;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.organization.UserStatus;
import org.exoplatform.social.core.manager.IdentityManager;
import org.exoplatform.social.core.space.SpaceUtils;

@SessionScoped
public class SpaceController extends CSControllerBase {
  private static Log log = ExoLogger.getLogger(SpaceController.class);

  @Inject
  OrganizationService organizationService;

  @Inject
  CSSpaceService csSpaceService;

  @Inject
  TicketService ticketService;

  @Inject
  TicketStatusFlowService ticketStatusFlowService;

  @Inject
  SlaService slaService;

  @Inject
  SubscriptionService subscriptionService;

  @Inject
  @Path("index.gtmpl")
  Template indexTmpl;

  @View
  public Response.Content index() {
    return indexTmpl.ok();
  }

  @Ajax
  @Resource
  @MimeType.JSON
  @Jackson
  public List<SpaceDTO> getSpaces(String filter) {
    // tt
    try {

      if (filter.equals("all")) {
        return addSpaceURL(csSpaceService.getAllSpaces());
      } else if (filter.equals("suspended")) {
        return addSpaceURL(csSpaceService.getDeactvatedSpaces());
      } else {
        return addSpaceURL(csSpaceService.getActiveSpaces());
      }
    } catch (Exception e) {
      log.error(e);
      throw e;
    }
  }

  @Ajax
  @Resource
  @MimeType.JSON
  @Jackson
  public List<SpaceDTO> getActiveSpaces() {
    // tt
    try {
      return addSpaceURL(csSpaceService.getActiveSpaces());
    } catch (Exception e) {
      log.error(e);
      throw e;
    }
  }

  @Ajax
  @Resource
  @MimeType.JSON
  @Jackson
  public List<SpaceDTO> getDeactvatedSpaces() {
    // tt
    try {
      return addSpaceURL(csSpaceService.getDeactvatedSpaces());
    } catch (Exception e) {
      log.error(e);
      throw e;
    }
  }

  @Ajax
  @Resource
  @MimeType.JSON
  @Jackson
  public List<String> loadSlaList() {
    try {
      List<String> slaList = new ArrayList<>();
      for (Sla sla : slaService.getSlas()) {
        slaList.add(sla.getName());
      }
      return slaList;
    } catch (Exception e) {
      log.error(e);
      throw e;
    }
  }


  @Ajax
  @Resource
  @MimeType.JSON
  @Jackson
  public List<String> loadSubscriptionList() {
    try {
      List<String> subscriptionList = new ArrayList<>();
      for (Subscription subscription : subscriptionService.getSubscriptions()) {
        subscriptionList.add(subscription.getName());
      }
      return subscriptionList;
    } catch (Exception e) {
      log.error(e);
      throw e;
    }
  }


  private List<SpaceDTO> addSpaceURL(List<SpaceDTO> allSpaces) {
    List<SpaceDTO> spaces = new ArrayList<>();
    for (SpaceDTO spaceDTO : allSpaces) {
      spaceDTO.setUrl(SpacePageUtils.getSpaceHomeURL(spaceDTO.getGroupId(), spaceDTO.getName()));
      spaces.add(spaceDTO);
    }
    return spaces;
  }

  @Ajax
  @Resource(method = HttpMethod.POST)
  @MimeType.JSON
  @Jackson
  public List<TicketDTO> getTicketsOfSpace(@Jackson SpaceDTO spaceDTO) {
    if (spaceDTO == null) {
      throw new IllegalStateException("Wrong HTTP Request, spaceDTO is null");
    }
    // FIXME JUZU-47 : accents aren't well displayed
    return ticketService.getTicketsOfSpace(spaceDTO.getGroupId());
  }

  @Ajax
  @Resource(method = HttpMethod.POST)
  public Response saveSpace(@Jackson SpaceDTO spaceDTO) {
    try {
      if (spaceDTO == null) {
        throw new IllegalStateException("Wrong HTTP Request, spaceDTO is null");
      }
      spaceDTO.setOwner(getCurrentUser().getUserName());
      spaceDTO = csSpaceService.saveSpace(spaceDTO);
      return Response.ok(spaceDTO.getUrl());
    } catch (EntityAlreadyExistsException e) {
      log.warn("Space already exists", e);
      return Response.status(500).content("#cs.spaceAlreadyExists");
    } catch (Exception e) {
      log.error("Error when saving Space", e);
      return Response.status(500);
    }
  }

  @Ajax
  @Resource(method = HttpMethod.POST)
  public Response updateSpace(@Jackson SpaceDTO spaceDTO) {
    try {
      if (spaceDTO == null) {
        throw new IllegalStateException("Wrong HTTP Request, spaceDTO is null");
      }
      spaceDTO = csSpaceService.updateSpace(spaceDTO);
      return Response.ok(spaceDTO.getUrl());
    } catch (Exception e) {
      log.error("Error when saving Space", e);
      return Response.status(500);
    }
  }

  @Resource
  @Ajax
  @MimeType.JSON
  @Jackson
  public List<BasicEntityDTO> findGroups(String query) throws Exception {
    Query usersQuery = new Query();
    usersQuery.setFirstName("*" + query + "*");
    Collection<Group> list = organizationService.getGroupHandler().findGroupsOfUser(getCurrentUser().getUserName());

    List<BasicEntityDTO> groupDTOs = new ArrayList<BasicEntityDTO>();
    for (Group group : list) {
      if (!group.getLabel().toLowerCase().contains(query.toLowerCase())) {
        continue;
      }
      groupDTOs.add(new BasicEntityDTO("@" + group.getId(), group.getLabel(), null, null, null));
    }
    return groupDTOs;
  }

  @Resource
  @Ajax
  @MimeType.JSON
  @Jackson
  public List<BasicEntityDTO> findUsers(String query) throws Exception {
    Query usersQuery = new Query();
    usersQuery.setUserName("*" + query + "*");
    ListAccess<User> list = organizationService.getUserHandler().findUsersByQuery(usersQuery, UserStatus.ENABLED);
    User[] users = list.load(0, list.getSize() < 10 ? list.getSize() : 10);
    List<BasicEntityDTO> userDTOs = new ArrayList<BasicEntityDTO>();
    for (User user : users) {
      userDTOs.add(new BasicEntityDTO("@" + user.getUserName(), user.getDisplayName(), null, "contact", user.getUserName()));
    }
    return userDTOs;
  }

  @Ajax
  @juzu.Resource
  @MimeType.JSON
  @Jackson
  public Response getBundle(String locale) {
    return super.getBundle(new Locale(locale));
  }

  @Ajax
  @juzu.Resource
  @MimeType.JSON
  @Jackson
  public Map<String, Flow> getFlows() {
    return ticketStatusFlowService.getFlows();
  }

  @Override
  public Log getLogger() {
    return log;
  }

  @Ajax
  @Resource
  @MimeType.JSON
  @Jackson
  public Response sendAnnouncement(String plfVersion) {
      try {
        if (plfVersion.trim().isEmpty() || ! plfVersion.matches("^[0-9]\\.[0-9]\\.[0-9]+(-(M|RC|CP)[0-9][0-9])?$")) {
          return Response.status(400);
        }
        NotificationContext ctx = NotificationContextImpl.cloneInstance().append(CSAnnouncementPlugin.PLF_VERSION,plfVersion);
        ctx.getNotificationExecutor().with(ctx.makeCommand(PluginKey.key(CSAnnouncementPlugin.ID))).execute(ctx);
        return Response.ok("Announce created");
      }  catch (Exception e) {
        log.error("Error when creating announce", e);
        return Response.status(500);
      }
  }
}
