package org.exoplatform.cs.portlet.ticketAdministration;

import juzu.HttpMethod;
import juzu.MimeType;
import juzu.Path;
import juzu.Resource;
import juzu.Response;
import juzu.View;
import juzu.impl.common.JSON;
import juzu.plugin.jackson.Jackson;
import juzu.template.Template;
import org.exoplatform.commons.juzu.ajax.Ajax;
import org.exoplatform.cs.dto.*;
import org.exoplatform.cs.entity.SpaceEntity;
import org.exoplatform.cs.service.CSSpaceService;
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.util.CSUtils;
import org.exoplatform.cs.portlet.common.CSControllerBase;
import org.exoplatform.cs.service.TicketService;
import org.exoplatform.cs.service.tickets.FlowState;
import org.exoplatform.cs.service.tickets.TicketStatusFlowService;
import org.exoplatform.portal.application.PortalRequestContext;
import org.exoplatform.portal.mop.SiteType;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.security.ConversationState;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.identity.model.Profile;
import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
import org.exoplatform.social.core.manager.IdentityManager;
import org.exoplatform.social.core.space.model.Space;
import org.json.JSONArray;
import org.json.JSONObject;

import javax.inject.Inject;


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.*;


/**
 * Created by exo on 8/3/16.
 */
public class TicketAdministrationController extends CSControllerBase {
  private static Log  LOG = ExoLogger.getLogger(TicketAdministrationController.class);
  private final String JIRA_SRV_URL = "https://jira.exoplatform.org";
  private final String JIRA_REST_URL = JIRA_SRV_URL + "/rest/api/latest/issue/";
  private final String SERVICEID = "Jira-Rest-API";
  private final String OPERATION = "call-jira-issue-details";


  @Inject
  TicketService       ticketService;


  @Inject
  TicketStatusFlowService ticketStatusFlowService;

  @Inject
  CSSpaceService spaceService;


  @Inject
  SlaService slaService;

  @Inject
  SubscriptionService subscriptionService;

  @Inject
  IdentityManager identityManager;

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

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

  @Ajax
  @Resource
  @MimeType.JSON
  @Jackson
  public List<TicketDTO> getAllTickets(String filter, String selectedSpace, String selectedStatus) {
    try {
      Calendar from = Calendar.getInstance();
      from.add(Calendar.DATE, -7);
      if(filter.equals("allassignedtickets")){
        return ticketService.getAssignedTickets(getCurrentUser().getUserName(), selectedSpace, true, selectedStatus);
      } else if(filter.equals("allmytickets")){
        return ticketService.getMyTickets(getCurrentUser().getUserName(), selectedSpace, true, selectedStatus);
      } else if (filter.equals("allopentickets"))  {
        return ticketService.getTickets(selectedSpace, false, selectedStatus);
      } else if(filter.equals("alltickets")) {
        return ticketService.getTickets(selectedSpace, true, selectedStatus);
      }else if(filter.equals("assignedopentickets")) {
        return ticketService.getAssignedTickets(getCurrentUser().getUserName(),selectedSpace,false, selectedStatus);
      }else if(filter.equals("lastUpdated")) {
        return ticketService.getUpdatedTickets(selectedStatus,selectedSpace, from, Calendar.getInstance());
      }else if(filter.equals("lastCreated")) {
        return ticketService.getCreatedTickets(selectedSpace,from, Calendar.getInstance());
      }else if(filter.equals("notAssigned")) {
        return ticketService.getNotAssignedTickets(selectedSpace);
      }
      return ticketService.getMyTickets(getCurrentUser().getUserName(),selectedSpace,false, selectedStatus);
    } catch (Throwable e) {
      LOG.error("Exception when retrieving tickets" + e);
      return null;
    }
  }

  @Ajax
  @Resource
  @MimeType.JSON
  @Jackson
  public Response getJiraStatus(String id) {
    HttpURLConnection httpURLConnection = null;
    long startCalc = System.currentTimeMillis();
    int status = 500;
    try {
      URL url = new URL(JIRA_REST_URL + id + "?fields=status");
      httpURLConnection = (HttpURLConnection) url.openConnection();
      httpURLConnection.setRequestMethod("GET");
      httpURLConnection.setRequestProperty("Content-length", "0");
      httpURLConnection.setUseCaches(false);
      httpURLConnection.setAllowUserInteraction(false);
      httpURLConnection.setConnectTimeout(5000);
      httpURLConnection.connect();

      status = httpURLConnection.getResponseCode();
      if (status == 200 || status == 201) {
        LOG.info("service="+ SERVICEID + " operation=" + OPERATION + " parameters=\"" + id + "\" status=ok duration_ms=" + (System.currentTimeMillis() - startCalc));
        BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
          sb.append(line + "\n");
        }
        br.close();
        // Output to client
        return Response.ok(sb.toString());
      }
    } catch (Exception ex) {
         if( ex instanceof UnknownHostException )
           status = 404;  // httpURLConnection.connect() Error
         else if( ex instanceof SocketTimeoutException )
           status = 408; // httpURLConnection.setConnectTimeout(xxxxx);
         else
         LOG.error("service="+ SERVICEID + " operation=" + OPERATION + " parameters=\""+id+"\" status=ko duration_ms="+( System.currentTimeMillis() - startCalc ), ex);
      }  finally {
        // Close connection
        if (httpURLConnection != null) {
          try {
            httpURLConnection.disconnect();
          } catch (Exception ex) {
            // Nothing to show for connection closing.
          }
        }
    }
       // Error Code Forwarding
    if (status >= 400 && status < 500) {
      String errormessage = "";
      if(status == 400) errormessage = "400 - Bad Request";
      if(status == 401) errormessage = "401 - Unauthorized";
      if(status == 403) errormessage = "403 - Forbidden";
      if(status == 404) errormessage = "404 - Not Found";
      if(status == 408) errormessage = "408 - Connection Timeout";
      LOG.error("service="+ SERVICEID + " operation=" + OPERATION + " parameters=\""+id+"\" status=ko duration_ms="+( System.currentTimeMillis() - startCalc ) + " error_msg=\"Error calling Jira Rest API, response is "+ errormessage +"\"" );
    }
    return Response.status(500);
  }

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

  @Ajax
  @Resource(method = HttpMethod.POST)
  @MimeType.JSON
  @Jackson
  public TicketDTO saveTicket(@Jackson TicketDTO ticketDTO) throws Exception {
    try {
      return ticketService.updateTicket(ticketDTO, getCurrentUser());
    } catch (Exception e) {
      LOG.error("Error when updating ticket", e);
      throw e;
    }
  }

  /**
   * This service will return the names of all support team members
   * @param ticketDTO
   * @return
   */
  @Ajax
  @Resource(method = HttpMethod.POST)
  @MimeType.JSON
  @Jackson
  public List<User> getSupportUsernames(@Jackson TicketDTO ticketDTO) {
    try {
      return CSUtils.getSupportMembers();
    } catch (Throwable e) {
      LOG.error("Can't retrieve the list of support engineers " + e);
      return null;
    }
  }

  /**
   * This service will return the names and avatars of all support team members
   * @return
   */

  @Ajax
  @juzu.Resource
  @MimeType.JSON
  @Jackson
  public Response getSupportAgents() {
    try {
      JSONArray agentsList = new JSONArray();

      List<User> agents = CSUtils.getSupportMembers();
      for(User agent :agents){
        JSONObject data = new JSONObject();
        data.put("userName",agent.getUserName());
        data.put("displayName",agent.getDisplayName());
        agentsList.put(data);
      }

      return Response.ok(agentsList.toString());
    } catch (Throwable e) {
      LOG.error("error while getting context", e);
      return Response.status(500);
    }
  }


  /**
   * this method will return the list of severities
   * @return List of ticket severity
   */
  @Ajax
  @Resource(method = HttpMethod.POST)
  @MimeType.JSON
  @Jackson
  public List<String> getSeverities(@Jackson TicketDTO ticketDTO) {
      List<String> severities = new ArrayList<>();
      if(ticketDTO.getType().equals(IssueType.INCIDENT)){
        severities.add(IssueSeverity.SEVERITY_1.name());
        severities.add(IssueSeverity.SEVERITY_2.name());
        severities.add(IssueSeverity.SEVERITY_3.name());
      } else if(ticketDTO.getType().equals(IssueType.INFORMATION)) {
        severities.add(IssueSeverity.SEVERITY_4.name());
      }
      return severities;
  }

  /**
   * this method returns the static list of ticket types
   *
   * @return
   */
  @Ajax
  @Resource(method = HttpMethod.POST)
  @MimeType.JSON
  @Jackson
  public List<String> getTicketTypes() {
      List<String> ticketTypes = new ArrayList<>();
      ticketTypes.add(IssueType.INCIDENT.name());
      ticketTypes.add(IssueType.INFORMATION.name());
      return ticketTypes;
  }


  /**
   * this method returns the static list of Owners
   *
   * @return
   */

  @Ajax
  @Resource(method = HttpMethod.POST)
  @MimeType.JSON
  @Jackson
  public List<String> getOwnersList() {
    List<String> ownersList = new ArrayList<>();
    Owner[] owners = Owner.values();
    for (int i=0; i<owners.length; i++ ){
      ownersList.add(owners[i].name());
    }
      return ownersList;
  }


  /**
   * this method returns the application Context
   *
   * @return
   */

  @Ajax
  @juzu.Resource
  @MimeType.JSON
  @Jackson
  public Response getContext() {
    try {
      JSON data = new JSON();
      String currentSpace=getCurrentSpaceId();
      if(currentSpace == null || currentSpace.equals("/spaces/exo_support")) {
        data.set("currentSpace", "");
      }
      else{
        data.set("currentSpace", currentSpace);
        SpaceDTO spaceDTO = spaceService.getSpace(currentSpace);
        data.set("currentSpaceIncidentFlow", spaceDTO.getIncidentFlow());
        data.set("currentSpaceInformationFlow", spaceDTO.getInformationFlow());
      }

      data.set("canManage",CSUtils.canManage());
      return Response.ok(data.toString());
    } catch (Exception e) {
      LOG.error("error while getting context", e);
      return Response.status(500);
    }
  }

  /**
   * this method returns the static list of ticket types
   *
   * @return
   */
  @Ajax
  @Resource(method = HttpMethod.GET )
  @MimeType.JSON
  @Jackson
  public Map<String, List<FlowState>> loadStatuses() {
    return ticketStatusFlowService.getAllStatuses();
  }

  /**
   * this method returns the list of customer spaces
   *
   * @return
   */
  @Ajax
  @Resource(method = HttpMethod.GET )
  @MimeType.JSON
  @Jackson
  public List<SpaceDTO> getSpaces() {
    return spaceService.getActiveSpaces();
  }

  @Ajax
  @Resource(method = HttpMethod.POST)
  @MimeType.JSON
  @Jackson
  public String deleteTicket(@Jackson TicketDTO ticket) {
    ticketService.deleteTicket(ticket);
    return "OK";
  }

  public String getCurrentSpaceId() {
    String spaceGroupId = null;
    PortalRequestContext requestContext = Util.getPortalRequestContext();
    if (requestContext != null) {
      if (requestContext.getSiteType().equals(SiteType.GROUP) && requestContext.getSiteName().startsWith("/spaces")) {
        spaceGroupId = requestContext.getSiteName();
      }
    }
    return spaceGroupId;
  }


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