package ru.yandex.qe.dispenser.ws.bot;

import java.util.Optional;

import javax.annotation.ParametersAreNonnullByDefault;
import javax.ws.rs.BeanParam;
import javax.ws.rs.DELETE;
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.Context;
import javax.ws.rs.core.UriInfo;

import io.swagger.annotations.Api;
import io.swagger.annotations.Authorization;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import ru.yandex.qe.dispenser.api.v1.DiBotServiceReserve;
import ru.yandex.qe.dispenser.api.v1.response.DiListPageResponse;
import ru.yandex.qe.dispenser.domain.Campaign;
import ru.yandex.qe.dispenser.domain.Person;
import ru.yandex.qe.dispenser.domain.Service;
import ru.yandex.qe.dispenser.domain.dao.bot.service.reserve.BotReserve;
import ru.yandex.qe.dispenser.domain.dao.bot.service.reserve.BotServiceReserve;
import ru.yandex.qe.dispenser.domain.dao.bot.service.reserve.BotServiceReserveDao;
import ru.yandex.qe.dispenser.domain.dao.campaign.CampaignDao;
import ru.yandex.qe.dispenser.domain.hierarchy.Session;
import ru.yandex.qe.dispenser.swagger.DispenserSecurityDefinition;
import ru.yandex.qe.dispenser.swagger.SwaggerTags;
import ru.yandex.qe.dispenser.ws.Access;
import ru.yandex.qe.dispenser.ws.ServiceBase;
import ru.yandex.qe.dispenser.ws.aspect.ForbiddenException;
import ru.yandex.qe.dispenser.ws.param.BotServiceReserveFilterParam;
import ru.yandex.qe.dispenser.ws.param.PaginationParam;
import ru.yandex.qe.dispenser.ws.reqbody.BotServiceReserveBody;
import ru.yandex.qe.dispenser.ws.reqbody.BotServiceReserveCreate;

import static ru.yandex.qe.dispenser.ws.aspect.AccessAspect.isServiceAdmin;
import static ru.yandex.qe.dispenser.ws.param.PageParam.LIMIT_PARAM;
import static ru.yandex.qe.dispenser.ws.param.PageParam.PAGE_PARAM;
import static ru.yandex.qe.dispenser.ws.param.PageParam.PAGE_SIZE_PARAM;
import static ru.yandex.qe.dispenser.ws.quota.request.workflow.ResourceWorkflow.isUserProcessResponsible;

@ParametersAreNonnullByDefault
@Controller
@Path("/v1/bot/reserves")
@Produces(ServiceBase.APPLICATION_JSON_UTF_8)
@org.springframework.stereotype.Service("botReserve")
@Api(tags = {SwaggerTags.DISPENSER_API}, authorizations = {@Authorization(value = DispenserSecurityDefinition.AUTHORIZATION_SCHEME_NAME)})
@Deprecated
public class BotServiceReserveService extends ServiceBase {
    private static final Logger LOG = LoggerFactory.getLogger(BotServiceReserveService.class);

    public static final String RESERVE_ID = "reserve_id";

    @Autowired
    private BotServiceReserveDao botServiceReserveDao;

    @Autowired
    private CampaignDao campaignDao;

    @GET
    @NotNull
    @Access
    @Deprecated
    public DiListPageResponse<DiBotServiceReserve> getReserves(@BeanParam final BotServiceReserveFilterParam filterParam,
                                                               @QueryParam(PAGE_PARAM) final Long pageNumberParam,
                                                               @QueryParam(PAGE_SIZE_PARAM) final Long pageSizeParam,
                                                               @QueryParam(LIMIT_PARAM) final Long limitParam,
                                                               @Context final UriInfo uriInfo) {
        final PaginationParam paginationParam = PaginationParam.from(pageNumberParam, pageSizeParam, limitParam, uriInfo);
        return collectToPage(paginationParam, filterParam.getFilteredReserveStream(botServiceReserveDao, campaignDao), BotServiceReserve::toView);
    }

    @GET
    @NotNull
    @Path("/{" + RESERVE_ID + "}")
    @Access
    @Deprecated
    public DiBotServiceReserve getReserve(@NotNull @PathParam(RESERVE_ID) final Long id) {
        return botServiceReserveDao.read(id).toView();
    }

    @POST
    @NotNull
    @Access
    @Deprecated
    public DiBotServiceReserve createReserve(@NotNull final BotServiceReserveCreate body) {
        final Optional<Campaign> campaign = campaignDao.readOptional(body.getCampaignId());
        if (campaign.isEmpty()) {
            throw new IllegalArgumentException("Reserve can not be created without an campaign");
        }
        final BotServiceReserve reserve = body.toEntity(campaign.get());
        final Person performer = Session.WHOAMI.get();
        checkThatUserCanEditReserves(performer, reserve);
        LOG.debug("User {} is trying to create reserve {}", performer, reserve);
        final BotServiceReserve createdReserve = botServiceReserveDao.create(reserve);
        return createdReserve.toView();
    }

    @PUT
    @NotNull
    @Path("/{" + RESERVE_ID + "}")
    @Access
    @Deprecated
    public DiBotServiceReserve updateReserve(@PathParam(RESERVE_ID) @NotNull final Long id,
                                             @NotNull final BotServiceReserveBody body) {
        final BotServiceReserve old = botServiceReserveDao.read(id);
        final Person performer = Session.WHOAMI.get();
        checkThatUserCanEditReserves(performer, old);
        if (body.isEmpty()) {
            throw new IllegalArgumentException("Empty update!");
        }
        final BotServiceReserve update = body.applyChangesFor(old);
        update.setId(id);
        final Campaign campaign = campaignDao.readWithDeleted(update.getCampaignId());
        if (campaign.getBigOrders().stream().noneMatch(o -> o.getBigOrderId().equals(update.getBigOrderId()))) {
            throw new IllegalArgumentException("Big order '" + update.getBigOrderId() + "' is not in the campaign");
        }
        botServiceReserveDao.update(update);
        if (!update.getSegments().equals(old.getSegments())) {
            botServiceReserveDao.updateSegments(id, update.getSegments());
        }

        return update.toView();
    }

    @DELETE
    @NotNull
    @Path("/{" + RESERVE_ID + "}")
    @Access
    @Deprecated
    public DiBotServiceReserve deleteReserve(@NotNull @PathParam(RESERVE_ID) final Long id) {
        final BotServiceReserve reserveToDelete = botServiceReserveDao.read(id);
        final Person performer = Session.WHOAMI.get();
        checkThatUserCanEditReserves(performer, reserveToDelete);
        botServiceReserveDao.delete(reserveToDelete);
        return reserveToDelete.toView();
    }

    public static void checkThatUserCanEditReserves(final Person person, final BotReserve reserve) {
        final Service service = reserve.getService();

        if (!isServiceAdmin(person, service)
                && !isUserProcessResponsible(person)) {
            throw new ForbiddenException("'" + person.getLogin() + "' has no access to edit reserves in service '" + service.getKey() + "'!");
        }
    }
}
