package ru.yandex.qe.dispenser.ws;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Comparator;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;

import com.opencsv.CSVWriter;
import io.swagger.annotations.Api;
import io.swagger.annotations.Authorization;
import ru.yandex.qe.dispenser.domain.BotCampaignGroup;
import ru.yandex.qe.dispenser.domain.Person;
import ru.yandex.qe.dispenser.domain.bot.BigOrder;
import ru.yandex.qe.dispenser.domain.dao.bot.settings.BotCampaignGroupDao;
import ru.yandex.qe.dispenser.domain.hierarchy.HierarchySupplier;
import ru.yandex.qe.dispenser.domain.hierarchy.Session;
import ru.yandex.qe.dispenser.domain.index.LongIndexBase;
import ru.yandex.qe.dispenser.swagger.DispenserSecurityDefinition;
import ru.yandex.qe.dispenser.swagger.SwaggerTags;
import ru.yandex.qe.dispenser.ws.aspect.ForbiddenException;
import ru.yandex.qe.dispenser.ws.quota.request.report.summary.ResourcePreorderSummaryFilter;
import ru.yandex.qe.dispenser.ws.quota.request.report.summary.ResourcePreorderSummaryReport;
import ru.yandex.qe.dispenser.ws.quota.request.workflow.ResourceWorkflow;

import static ru.yandex.qe.dispenser.ws.QuotaChangeRequestExportService.CONTENT_DISPOSITION_TEMPLATE;

@ParametersAreNonnullByDefault
@Path("/v1/resource-preorder-summary/export")
@Produces(ServiceBase.APPLICATION_JSON_UTF_8)
@org.springframework.stereotype.Service("quota-pre-order-summary-export")
@Api(tags = {SwaggerTags.DISPENSER_API}, authorizations = {@Authorization(value = DispenserSecurityDefinition.AUTHORIZATION_SCHEME_NAME)})
public class ResourcePreorderSummaryExportService {

    private final ResourcePreorderSummaryReport report;
    private final BotCampaignGroupDao campaignGroupDao;
    private final HierarchySupplier hierarchySupplier;

    @Inject
    public ResourcePreorderSummaryExportService(final ResourcePreorderSummaryReport report,
                                                final BotCampaignGroupDao campaignGroupDao,
                                                final HierarchySupplier hierarchySupplier) {
        this.report = report;
        this.campaignGroupDao = campaignGroupDao;
        this.hierarchySupplier = hierarchySupplier;
    }

    @NotNull
    @GET
    @Access
    @Produces(ServiceBase.TEXT_CSV_UTF_8)
    @Path("/csv")
    public Response exportRequestsToCsv(@QueryParam("deliveryOrder") Set<Long> deliveryOrderIds,
                                        @QueryParam("botCampaignGroupId") @Nullable Long botCampaignGroupId) {
        final Optional<BotCampaignGroup> activeGroup;
        if (botCampaignGroupId == null) {
            activeGroup = campaignGroupDao.getActiveGroups()
                    .stream()
                    .max(Comparator.comparing(LongIndexBase::getId));
        } else {
            activeGroup = campaignGroupDao.readOptional(botCampaignGroupId);
        }
        final Person performer = Session.WHOAMI.get();

        if (!ResourceWorkflow.isUserProcessResponsible(performer)) {
            throw new ForbiddenException("Only process responsible can view report");
        }

        if (!activeGroup.isPresent()) {
            throw new NotFoundException("No active campaign group");
        }
        final Set<Long> bigOrderIds = activeGroup.get().getBigOrders().stream()
                .map(BigOrder::getId)
                .collect(Collectors.toSet());
        if (deliveryOrderIds.isEmpty()) {
            deliveryOrderIds = bigOrderIds;
        }

        final ResourcePreorderSummaryFilter filter = new ResourcePreorderSummaryFilter(bigOrderIds, deliveryOrderIds);

        final StreamingOutput output = new StreamingOutput() {
            @Override
            public void write(final OutputStream outputStream) throws IOException, WebApplicationException {
                final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
                final CSVWriter csvWriter = new CSVWriter(writer);
                report.writeReport(csvWriter, filter, activeGroup.get());
                writer.close();
            }
        };

        return Response.ok(output).header(HttpHeaders.CONTENT_DISPOSITION, String.format(CONTENT_DISPOSITION_TEMPLATE, "requests.csv")).build();
    }
}
