package com.wishurgift.entry.controller;

import com.wishurgift.entry.security.Connected;
import com.wishurgift.entry.security.Secured;
import com.wishurgift.entry.validator.CommentValidator;
import com.wishurgift.entry.validator.ElementUpdateValidator;
import com.wishurgift.entry.validator.ImageValidator;
import com.wishurgift.service.CommentService;
import com.wishurgift.service.ElementService;
import com.wishurgift.service.dto.CommentDTO;
import com.wishurgift.service.dto.ElementDTO;
import com.wishurgift.service.dto.ImageDTO;
import com.wishurgift.service.dto.UserDTO;
import com.wishurgift.service.dto.request.CommentRequestDTO;
import com.wishurgift.service.dto.request.ElementRequestDTO;
import com.wishurgift.service.dto.request.ImageRequestDTO;
import com.wishurgift.utils.Constant;
import com.wishurgift.utils.JwtUtils;
import com.wishurgift.wrapper.Page;
import com.wishurgift.wrapper.Result;
import lombok.extern.slf4j.Slf4j;

import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;

@Slf4j
@Path("/elements")
@Produces(MediaType.APPLICATION_JSON)
public class ElementController {

    @Inject
    private ElementService service;

    @Inject
    private CommentService commentService;

    @Inject
    private ElementUpdateValidator elementUpdateValidator;

    @Inject
    private ImageValidator imageValidator;

    @Inject
    private CommentValidator commentValidator;

    @GET
    @Connected
    @Path("/{id}")
    public Response get(@PathParam("id") long id, @Context SecurityContext securityContext) {
        log.info("Begin ElementController get, id={}", id);
        // Verification données
        if (id < 1) {
            log.info("End ElementController get, invalid id");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(Constant.INVALID_ID).response();
        }
        // Recup utilisateur connecté
        UserDTO principal = JwtUtils.getUser(securityContext.getUserPrincipal());
        // Recupération de l'element
        ElementDTO elementDTO = service.getElement(principal, id);
        if (elementDTO == null) {
            log.info("End ElementController get, unable to get data");
            return Result.error().data(Result.Error.UNABLE_TO_GET_DATA).response();
        }
        log.info("End ElementController get");
        return Result.success().data(elementDTO).response();
    }

    @GET
    @Connected
    @Path("/{id}/comments")
    public Response getComments(@PathParam("id") long id, @Context SecurityContext securityContext) {
        log.info("Begin ElementController getComments, id={}", id);
        //Verification id
        if (id < 1) {
            log.info("End ElementController getComments, invalid id");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(Constant.INVALID_ID).response();
        }

        UserDTO principal = JwtUtils.getUser(securityContext.getUserPrincipal());
        Page<CommentDTO> page = commentService.getByElement(principal, id);
        if (page == null) {
            log.info("End ElementController getComments, unable to get data");
            return Result.error().data(Result.Error.UNABLE_TO_GET_DATA).response();
        }
        log.info("End ElementController getComments");
        return Result.success().data(page).response();
    }

    @GET
    @Connected
    @Path("/{id}/comments/page/{num}/{nb}")
    public Response getCommentsPage(@PathParam("id") long id, @PathParam("num") int page, @PathParam("nb") int size, @Context SecurityContext securityContext) {
        log.info("Begin Element Controller getCommentsPage, id={} page={} size={}", id, page, size);
        //Verification id et page
        if (id < 1) {
            log.info("End ElementController getCommentsPage, invalid id");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(Constant.INVALID_ID).response();
        }
        if (page < 1) {
            log.info("End ElementController getCommentsPage, invalid page");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(Constant.PAGE_NUMBER_INVALID).response();
        }

        UserDTO principal = JwtUtils.getUser(securityContext.getUserPrincipal());
        Page<CommentDTO> pagedto = commentService.getByElement(principal, page, size, id);
        if (pagedto == null) {
            log.info("End ElementController getCommentsPage, unable to get data");
            return Result.error().data(Result.Error.UNABLE_TO_GET_DATA).response();
        }
        log.info("End ElementController getCommentsPage");
        return Result.success().data(pagedto).response();
    }

    @POST
    @Secured
    @Path("/{id}/image")
    public Response image(@PathParam("id") long id, ImageRequestDTO request, @Context SecurityContext securityContext) {
        log.info("Begin ElementController image, id={} image={}", id, request);
        // Verification données
        if (id < 1) {
            log.info("End ElementController image, invalid id");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(Constant.INVALID_ID).response();
        }
        if (imageValidator.isNotValid(request)) {
            log.info("End ElementController image, invalid request");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(imageValidator.getAllErrors()).response();
        }
        // Recup utilisateur connecté
        UserDTO principal = JwtUtils.getUser(securityContext.getUserPrincipal());
        if (principal == null) {
            log.info("End ElementController image, unable to connect");
            return Result.error().data(Result.Error.UNABLE_TO_CONNECT).trace(Constant.USER_NOT_FOUND).response();
        }
        // Ajoute l'image
        ImageDTO imageDTO = service.addImage(principal, id, request);
        if (imageDTO == null) {
            log.info("End ElementController image, unable to insert");
            return Result.error().data(Result.Error.UNAUTHORIZED).response();
        }
        log.info("End ElementController image");
        return Result.success().data(imageDTO).response();
    }

    @POST
    @Secured
    @Path("/{id}/comment")
    public Response comment(@PathParam("id") long id, CommentRequestDTO request, @Context SecurityContext securityContext) {
        log.info("Begin ElementController comment, id={}", id);
        //Verification id
        if (id < 1) {
            log.info("End ElementController comment, invalid id");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(Constant.INVALID_ID).response();
        }
        if (commentValidator.isNotValid(request)) {
            log.info("End ElementController image, invalid request");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(commentValidator.getAllErrors()).response();
        }
        //Verification user
        UserDTO principal = JwtUtils.getUser(securityContext.getUserPrincipal());
        if (principal == null) {
            log.info("End ElementController comment, unable to connect");
            return Result.error().data(Result.Error.UNABLE_TO_CONNECT).trace(Constant.USER_NOT_FOUND).response();
        }
        //insertcomment
        CommentDTO comment = commentService.insert(principal, id, request);
        if (comment == null) {
            log.info("End ElementController comment, unable to insert");
            return Result.error().data(Result.Error.UNAUTHORIZED).response();
        }
        log.info("End ElementController comment");
        return Result.success().data(comment).response();
    }

    @PUT
    @Secured
    @Path("/{id}")
    public Response update(@PathParam("id") long id, ElementRequestDTO request, @Context SecurityContext securityContext) {
        log.info("Begin ElementController update id={} element={}", id, request);
        // Verification données
        if (id < 1) {
            log.info("End ElementController update, invalid id");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(Constant.INVALID_ID).response();
        }
        if (elementUpdateValidator.isNotValid(request)) {
            log.info("End ElementController update, invalid request");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(elementUpdateValidator.getAllErrors()).response();
        }
        // Recup utilisateur connecté
        UserDTO principal = JwtUtils.getUser(securityContext.getUserPrincipal());
        if (principal == null) {
            log.info("End ElementController update, unable to connect");
            return Result.error().data(Result.Error.UNABLE_TO_CONNECT).trace(Constant.USER_NOT_FOUND).response();
        }
        // Modifie l'element
        ElementDTO element = service.update(principal, id, request);
        if (element == null) {
            log.info("End ElementController update, unauthorized");
            return Result.error().data(Result.Error.UNAUTHORIZED).response();
        }
        log.info("End ElementController update");
        return Result.success().data(element).response();
    }

    @PUT
    @Secured
    @Path("/{id}/status/{status}")
    public Response status(@PathParam("id") long id, @PathParam("status") String status, @Context SecurityContext securityContext) {
        log.info("Begin ElementController status, id={} status={}", id, status);
        // Verification données
        if (id < 1) {
            log.info("End ElementController status, invalid id");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(Constant.INVALID_ID).response();
        }
        Constant.Status newStatus = Constant.Status.fromName(status);
        if (newStatus == null) {
            log.info("End ElementController status, invalid status");
            return Result.error().data(Result.Error.INVALID_REQUEST).response();
        }
        // Recup utilisateur connecté
        UserDTO principal = JwtUtils.getUser(securityContext.getUserPrincipal());
        if (principal == null) {
            log.info("End ElementController status, unable to connect");
            return Result.error().data(Result.Error.UNABLE_TO_CONNECT).trace(Constant.USER_NOT_FOUND).response();
        }
        // Changement du status
        ElementDTO elementDTO = service.setStatus(principal, id, newStatus);
        if (elementDTO == null) {
            log.info("End ElementController status, unautohrized");
            return Result.error().data(Result.Error.UNAUTHORIZED).response();
        }
        log.info("End ElementController status");
        return Result.success().data(elementDTO).response();
    }

    @DELETE
    @Secured
    @Path("/{id}")
    public Response remove(@PathParam("id") long id, @Context SecurityContext securityContext) {
        log.info("Begin ElementController remove, id={}", id);
        // Verification données
        if (id < 1) {
            log.info("End ElementController remove, invalid id");
            return Result.error().data(Result.Error.INVALID_REQUEST).trace(Constant.INVALID_ID).response();
        }
        // Recup utilisateur connecté
        UserDTO principal = JwtUtils.getUser(securityContext.getUserPrincipal());
        if (principal == null) {
            log.info("End ElementController remove, unable to connect");
            return Result.error().data(Result.Error.UNABLE_TO_CONNECT).trace(Constant.USER_NOT_FOUND).response();
        }
        // Suppr
        boolean result = service.remove(principal, id);
        if (!result) {
            log.info("End ElementController remove, unauthorized");
            return Result.error().data(Result.Error.UNAUTHORIZED).response();
        }
        log.info("End ElementController remove");
        return Result.success().response();
    }

}
