package org.exoplatform.cs.rest;

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

import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.commons.lang3.StringUtils;

import org.exoplatform.cs.dto.IssueSeverity;
import org.exoplatform.cs.dto.IssueType;
import org.exoplatform.cs.dto.TicketDTO;
import org.exoplatform.cs.rest.model.Ticket;
import org.exoplatform.cs.rest.utils.CSRestUtils;
import org.exoplatform.cs.rest.utils.EntityBuilder;
import org.exoplatform.cs.service.TicketService;
import org.exoplatform.cs.service.tickets.FlowState;
import org.exoplatform.cs.service.tickets.TicketStatusFlowService;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.rest.resource.ResourceContainer;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;

/**
 * Rest Ticket Service
 */
@Path("/customer-space/ticket")
@Tag(name = "/customer-space/ticket", description = "Manages ticket information")
public class CustomerTicketRest implements ResourceContainer {
    private TicketService ticketService;
    private TicketStatusFlowService ticketStatusFlowService;

    private static final String SPACE_GROUP = "/spaces/";

    private static final Log LOG = ExoLogger.getLogger(CustomerRateRest.class);

    public CustomerTicketRest(TicketService ticketService, TicketStatusFlowService ticketStatusFlowService) {
        this.ticketService = ticketService;
        this.ticketStatusFlowService = ticketStatusFlowService;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/flowstate/{name}")
    @RolesAllowed("users")
    @Operation(
            description = "retrieves a ticket flow stats",
            method = "GET"
    )
    @ApiResponses(
            value = {@ApiResponse(responseCode = "200", description = "Request fulfilled"),
                    @ApiResponse(responseCode = "401", description = "Unauthorized operation"),
                    @ApiResponse(responseCode = "500", description = "Internal server error"),}
    )
    public Response getFlowStatsByName(@Parameter(description = "Ticket Flow name", required = true) @PathParam("name") String name) {
        List<FlowState> flowStates = new ArrayList<FlowState>();
        try {
            if (StringUtils.isNotBlank(name)) {
                flowStates = ticketStatusFlowService.getFlowbyName(name).getStates();
            }
            if (flowStates == null) {
                return Response.status(Response.Status.NOT_FOUND).entity("no flow state found").build();
            }
        } catch (Exception e) {
            LOG.error("Error while retrieving ticket flow stats", e);
            return Response.serverError().entity(e.getMessage()).build();
        }
        return Response.ok(flowStates).build();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/info/{ticketId}")
    @RolesAllowed("users")
    @Operation(
            description = "retrieves a ticket information",
                method = "GET"
    )
    @ApiResponses(
            value = {@ApiResponse(responseCode = "200", description = "Request fulfilled"),
                     @ApiResponse(responseCode = "401", description = "Unauthorized operation"),
                     @ApiResponse(responseCode = "500", description = "Internal server error"),}
    )
    public Response getTicketById(@Parameter(description = "Ticket Id", required = true) @PathParam("ticketId") String ticketId) {
        TicketDTO ticketDTO = null;
        try {
            if (ticketId == null) {
                return Response.status(Response.Status.BAD_REQUEST).entity("ticket Id is mandatory").build();
            }
            ticketDTO = ticketService.findById(ticketId);

            if (!CSRestUtils.authorizedOnCS(ticketDTO.getSpaceGroupId())) {
                return Response.status(Response.Status.UNAUTHORIZED).entity("Your are not authorized").build();
            }
            if (ticketDTO == null) {
                return Response.status(Response.Status.NOT_FOUND).entity("ticket not found").build();
            }
            ticketDTO.setCreatorAvatar(CSRestUtils.getProfile(ticketDTO.getCreatorId()).getAvatarUrl());
            if (StringUtils.isNotBlank(ticketDTO.getAssignee()) && CSRestUtils.getProfile(ticketDTO.getAssignee()) != null) {
                ticketDTO.setAssigneeAvatar(CSRestUtils.getProfile(ticketDTO.getAssignee()).getAvatarUrl());
            }
        } catch (Exception e) {
            LOG.error("Error while retrieving ticket information", e);
            return Response.serverError().entity(e.getMessage()).build();
        }
        return Response.ok(EntityBuilder.fromTicketDto(ticketDTO)).build();
    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed("users")
    @Operation(
            description = "update an existing ticket information",
                method = "PUT"
    )
    @ApiResponses(
           value = {@ApiResponse(responseCode = "200", description = "Request fulfilled"),
                    @ApiResponse(responseCode = "401", description = "Unauthorized operation"),
                    @ApiResponse(responseCode = "400", description = "Invalid query input"),
                    @ApiResponse(responseCode = "500", description = "Internal server error"),}
    )
    public Response updateTicket(@Parameter(description = "Ticket Object to update", required = true) Ticket ticket,
                                 @Parameter(description = "Ticket new rate to be update", required = false)
                                 @QueryParam("rate") String rate) {

        if(!CSRestUtils.authorizedOnCS(ticket.getSpaceGroupId())){
            return Response.status(Response.Status.UNAUTHORIZED).entity("Your are not authorized").build();
        }
        if (ticket == null) {
            return Response.status(Response.Status.BAD_REQUEST).entity("Invalid ticket Object input").build();
        }
        if (ticket.getTicketId() == null) {
            return Response.status(Response.Status.NOT_FOUND).entity("ticket id is mandatory").build();
        }
        TicketDTO ticketDTO = null;
        try {
            ticketDTO = EntityBuilder.toTicketDto(ticket);
            if(rate != null && rate.equals("update")) {
                ticketService.updateTicketSatisfaction(ticketDTO, CSRestUtils.getCurrentUser().getUserName());
                ticketService.notifyCustomerRate(ticketDTO, CSRestUtils.getCurrentUser().getUserName(), false);
            } else {
                ticketDTO = ticketService.updateTicket(ticketDTO, CSRestUtils.getCurrentUser());
            }

        } catch (Exception e) {
            LOG.warn("Error updating a ticket", e);
            return Response.serverError().entity(e.getMessage()).build();
        }
        return getTicketById(ticketDTO.getId());
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed("users")
    @Operation(
            description = "create a new support ticket",
                method = "POST"
    )
    @ApiResponses(
            value = {@ApiResponse(responseCode = "200", description = "Request fulfilled"),
                     @ApiResponse(responseCode = "401", description = "Unauthorized operation"),
                     @ApiResponse(responseCode = "400", description = "Invalid query input"),
                     @ApiResponse(responseCode = "500", description = "Internal server error"),}
    )
    public Response createTicket(@Parameter(description = "Ticket Object to save", required = true) Ticket ticket) {

        if (ticket == null) {
            return Response.status(Response.Status.BAD_REQUEST).entity("Invalid ticket Object input").build();
        }
        if(!CSRestUtils.authorizedOnCS(SPACE_GROUP + ticket.getSpaceGroupId())){
            return Response.status(Response.Status.UNAUTHORIZED).entity("Your are not authorized").build();
        }
        TicketDTO ticketDTO = null;
        try {
            ticketDTO = EntityBuilder.toTicketDto(ticket);
            ticketDTO.setSpaceGroupId(SPACE_GROUP + ticketDTO.getSpaceGroupId());
            ticketDTO.setFiles(CSRestUtils.getFiles(ticketDTO.getAttachments()));
            if (IssueType.INFORMATION.equals(ticketDTO.getType())) {
                ticketDTO.setSeverity(IssueSeverity.SEVERITY_4);
            }
            User currentUser = CSRestUtils.getCurrentUser();
            ticketService.createTicket(ticketDTO, currentUser, null);
        } catch (Exception e) {
            LOG.warn("Error saving a ticket", e);
            return Response.serverError().entity(e.getMessage()).build();
        }
        if (ticketDTO.getType().equals(IssueType.PRODUCT)) {
            return Response.ok(EntityBuilder.fromTicketDto(ticketDTO)).build();
        }
        return getTicketById(ticketDTO.getId());
    }
}
