package org.exoplatform.cs.rest;

import io.swagger.annotations.*;
import org.exoplatform.common.http.HTTPStatus;
import org.exoplatform.commons.utils.CommonsUtils;
import org.exoplatform.cs.dto.SpaceDTO;
import org.exoplatform.cs.dto.TicketDTO;
import org.exoplatform.cs.entity.TopicEntity;
import org.exoplatform.cs.rest.model.SupportAgent;
import org.exoplatform.cs.rest.utils.CSRestUtils;
import org.exoplatform.cs.service.CSSpaceService;
import org.exoplatform.cs.service.EnvironmentService;
import org.exoplatform.cs.service.TicketService;
import org.exoplatform.cs.service.util.CSUtils;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.organization.OrganizationService;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.organization.UserHandler;
import org.exoplatform.services.rest.resource.ResourceContainer;
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.exoplatform.social.core.space.spi.SpaceService;
import org.json.JSONArray;
import org.json.JSONObject;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.*;

@Path("/customerspace/info")
@Api(value = "/customerspace/info")
public class CustomerInfoRest implements ResourceContainer {

    private CSSpaceService csSpaceService;
    private IdentityManager identityManager;
    private SpaceService spaceService;
    private TicketService ticketService;
    private EnvironmentService environmentService;
    private static final Log LOG =
            ExoLogger.getLogger(CustomerInfoRest.class);

    public CustomerInfoRest(CSSpaceService csSpaceService, EnvironmentService environmentService, IdentityManager identityManager, SpaceService spaceService, TicketService ticketService) {
        this.csSpaceService = csSpaceService;
        this.environmentService = environmentService;
        this.identityManager = identityManager;
        this.spaceService = spaceService;
        this.ticketService = ticketService;
    }

    @GET
    @RolesAllowed("support-team")
    @Produces(MediaType.APPLICATION_JSON)
    @Path("getAllSpaces")
    @ApiOperation(value = "Get All Customer Spaces", httpMethod = "GET", response = Response.class, notes = "Get all cs spaces")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Request fulfilled"),
            @ApiResponse(code = 400, message = "Invalid query input"),
            @ApiResponse(code = 403, message = "Unauthorized operation"),
            @ApiResponse(code = 500, message = "Internal server error")})
    public Response getAllSpaces() {
        List<SpaceDTO> allspaces = csSpaceService.getAllSpaces();
        JSONArray spaces = new JSONArray();
        try {
            for (SpaceDTO spaceDTO : allspaces) {
                JSONObject spaceJson = new JSONObject();
                spaceJson.put("name", spaceDTO.getName());
                spaceJson.put("subscriptionStartDate", spaceDTO.getSubscriptionStartDate());
                spaceJson.put("subscriptionEndDate", spaceDTO.getSubscriptionEndDate());
                spaceJson.put("subscriptionActive", spaceDTO.isSubscriptionActive());
                spaceJson.put("language", spaceDTO.getLanguage());
                spaceJson.put("hosted", spaceDTO.isHosted());
                spaces.put(spaceJson);
            }
        } catch (Exception e) {
            LOG.error("Error while getting all spaces ", e);
            return Response.status(500).build();
        }
        return Response.ok(spaces.toString()).build();
    }

    @GET
    @RolesAllowed("support-team")
    @Produces(MediaType.APPLICATION_JSON)
    @Path("getAllSpacesWithMembers")
    @ApiOperation(value = "Get All Customer Spaces with members", httpMethod = "GET", response = Response.class, notes = "Get all cs spaces with members")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Request fulfilled"),
            @ApiResponse(code = 400, message = "Invalid query input"),
            @ApiResponse(code = 403, message = "Unauthorized operation"),
            @ApiResponse(code = 500, message = "Internal server error")})
    public Response getAllSpacesWithMembers() {
        List<SpaceDTO> allspaces = csSpaceService.getAllSpaces();
        JSONArray spaces = new JSONArray();
        try {
            for (SpaceDTO spaceDTO : allspaces) {
                JSONObject spaceJson = new JSONObject();
                JSONArray spaceMembersJSON = new JSONArray();
                String[] spaceMembers = getMembersOfSpaceDTO(spaceDTO);
                for (String member : spaceMembers) {
                        Profile userProfile = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME,member,false).getProfile();
                        JSONObject userJson = new JSONObject();
                        userJson.put("username",userProfile.getProperty(Profile.USERNAME));
                        userJson.put("firstname",userProfile.getProperty(Profile.FIRST_NAME));
                        userJson.put("lastname",userProfile.getProperty(Profile.LAST_NAME));
                        userJson.put("email",userProfile.getEmail());
                        userJson.put("createdtime",userProfile.getCreatedTime());
                        userJson.put("gender",userProfile.getProperty(Profile.GENDER));
                        userJson.put("deleted",userProfile.getProperty(Profile.DELETED));
                        spaceMembersJSON.put(userJson);
                }
                spaceJson.put("name", spaceDTO.getName());
                spaceJson.put("members", spaceMembersJSON);
                spaceJson.put("subscriptionStartDate", spaceDTO.getSubscriptionStartDate());
                spaceJson.put("subscriptionEndDate", spaceDTO.getSubscriptionEndDate());
                spaceJson.put("subscriptionActive", spaceDTO.isSubscriptionActive());
                spaceJson.put("language", spaceDTO.getLanguage());
                spaceJson.put("hosted", spaceDTO.isHosted());
                spaces.put(spaceJson);
            }
        } catch (Exception e) {
            LOG.error("Error while getting all spaces with members", e);
            return Response.status(500).build();
        }
        return Response.ok(spaces.toString()).build();
    }

    @GET
    @RolesAllowed("support-team")
    @Produces(MediaType.APPLICATION_JSON)
    @Path("getAllSpacesWithEnvironment")
    @ApiOperation(value = "Get All Customer Spaces with environment", httpMethod = "GET", response = Response.class, notes = "Get all cs spaces with environment")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Request fulfilled"),
            @ApiResponse(code = 400, message = "Invalid query input"),
            @ApiResponse(code = 403, message = "Unauthorized operation"),
            @ApiResponse(code = 500, message = "Internal server error")})
    public Response getAllSpacesWithEnvironment() {
        List<SpaceDTO> allspaces = csSpaceService.getAllSpaces();
        JSONArray spaces = new JSONArray();
        try {
            for (SpaceDTO spaceDTO : allspaces) {
                JSONObject spaceJson = new JSONObject();
                JSONArray envlist = new JSONArray(environmentService.getSpaceEnvironments(spaceDTO.getGroupId()));
                spaceJson.put("name", spaceDTO.getName());
                spaceJson.put("environments", envlist);
                spaceJson.put("subscriptionStartDate", spaceDTO.getSubscriptionStartDate());
                spaceJson.put("subscriptionEndDate", spaceDTO.getSubscriptionEndDate());
                spaceJson.put("subscriptionActive", spaceDTO.isSubscriptionActive());
                spaceJson.put("language", spaceDTO.getLanguage());
                spaceJson.put("hosted", spaceDTO.isHosted());
                spaces.put(spaceJson);
            }
        } catch (Exception e) {
            LOG.error("Error while getting all spaces with environments", e);
            return Response.status(500).build();
        }
        return Response.ok(spaces.toString()).build();
    }

    @GET
    @RolesAllowed("support-team")
    @Produces(MediaType.APPLICATION_JSON)
    @Path("getAllTickets")
    @ApiOperation(value = "Get All Support Tickets", httpMethod = "GET", response = Response.class)
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Request fulfilled"),
            @ApiResponse(code = 400, message = "Invalid query input"),
            @ApiResponse(code = 403, message = "Unauthorized operation"),
            @ApiResponse(code = 500, message = "Internal server error")})
    public Response getAllTickets(@ApiParam(value = "Offset", required = false, defaultValue = "0") @QueryParam("offset") int offset,
                                  @ApiParam(value = "Limit", required = false, defaultValue = "20") @QueryParam("limit") int limit) {

        if (offset < 0 || limit < 0 || offset > 100 || limit > 100) {
            return Response.status(400).build();
        }
        JSONArray tickets = new JSONArray();
        List<TicketDTO> allTickets = ticketService.getAllTicketsWithPagination(offset, limit);
        try {
            for (TicketDTO ticketDTO : allTickets) {
                JSONObject ticketJson = new JSONObject();
                ticketJson.put("Space", spaceService.getSpaceByGroupId(ticketDTO.getSpaceGroupId()).getPrettyName());
                ticketJson.put("id", ticketDTO.getId());
                ticketJson.put("ticketId", ticketDTO.getId());
                ticketJson.put("title", ticketDTO.getTitle());
                ticketJson.put("status", ticketDTO.getStatus());
                ticketJson.put("assignee", ticketDTO.getAssignee());
                ticketJson.put("severity", ticketDTO.getSeverity());
                ticketJson.put("startDate", ticketDTO.getStartDate() != null ? ticketDTO.getStartDate().getTimeInMillis() : null);
                ticketJson.put("endDate", ticketDTO.getEndDate() != null ? ticketDTO.getEndDate().getTimeInMillis() : null);
                ticketJson.put("updateDate", ticketDTO.getUpdateDate() != null ? ticketDTO.getUpdateDate().getTimeInMillis() : null);
                ticketJson.put("creatorId", ticketDTO.getCreatorId());
                ticketJson.put("attachedJira", ticketDTO.getAttachedJira());
                ticketJson.put("timeToFirstResponse", ticketDTO.getTimeToFirstResponse());
                ticketJson.put("timeToResolution", ticketDTO.getTimeToResolution());
                ticketJson.put("customerSatisfied", ticketDTO.getCustomerSatisfied());
                ticketJson.put("reason", ticketDTO.getReason());
                tickets.put(ticketJson);
            }
        } catch (Exception e) {
            LOG.error("Error while getting all tickets with page {} and size {}", offset, limit, e);
            return Response.status(500).build();
        }
        return Response.ok(tickets.toString()).build();
    }

    @GET
    @RolesAllowed("support-team")
    @Produces(MediaType.APPLICATION_JSON)
    @Path("getAllMemebersEmails")
    @ApiOperation(value = "Get All Customers email", httpMethod = "GET", response = Response.class)
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Request fulfilled"),
            @ApiResponse(code = 400, message = "Invalid query input"),
            @ApiResponse(code = 403, message = "Unauthorized operation"),
            @ApiResponse(code = 500, message = "Internal server error")})
    public Response getAllMemebersEmails() {


        JSONArray mails = new JSONArray();
        try {
            OrganizationService organizationService = CommonsUtils.getService(OrganizationService.class);
            UserHandler uh = organizationService.getUserHandler();
            List<SpaceDTO> spaces = csSpaceService.getAllSpaces();
            for (SpaceDTO space :spaces){
                Space space_ = spaceService.getSpaceByGroupId(space.getGroupId());
                if(space_!=null){
                    for(String member : space_.getMembers()){
                        User user = uh.findUserByName(member);
                        if (user!=null && !user.getEmail().contains("exoplatform.com")){
                            mails.put(user.getEmail());
                        }

                    }
                }
            }
        } catch (Exception e) {
            LOG.error("Error while getting all members mails", e);
            return Response.status(500).build();
        }
        return Response.ok(mails.toString()).build();
    }

    @GET
    @RolesAllowed({"users"})
    @Produces(MediaType.APPLICATION_JSON)
    @Path("support-members")
    @ApiOperation(
            value = "retrieves all support members",
            httpMethod = "GET", response = Response.class, produces = "application/json"
    )
    @ApiResponses(
            value = {@ApiResponse(code = HTTPStatus.OK, message = "Request fulfilled"),
                    @ApiResponse(code = HTTPStatus.INTERNAL_ERROR, message = "Internal server error"),}
    )
    public Response getSupportMembers() {
        List<SupportAgent> supportAgents = new ArrayList<>();
        List<User> supportMembers;
        try {
            supportMembers = CSRestUtils.getSupportMembers();
        } catch (Exception e) {
            LOG.error("Error while retrieving support agents", e);
            return Response.serverError().entity(e.getMessage()).build();
        }
        if (supportMembers == null) {
            return Response.status(Response.Status.NOT_FOUND).entity("no support agent was found").build();
        }
        supportMembers.stream().forEach(user -> {
            SupportAgent supportAgent = new SupportAgent();
            supportAgent.setUserName(user.getUserName());
            supportAgent.setFullName(user.getDisplayName());
            supportAgents.add(supportAgent);
        });
        return Response.ok(supportAgents).build();
    }

    private String[] getMembersOfSpaceDTO(SpaceDTO spaceDTO) throws Exception {
        Space space = spaceService.getSpaceByGroupId(spaceDTO.getGroupId());
        return space.getMembers();
    }
}