package ru.yandex.canvas.controllers;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;

import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.document.AbstractXlsxStreamingView;

import ru.yandex.canvas.configs.auth.AuthorizeBy;
import ru.yandex.canvas.exceptions.CreativeNotFoundException;
import ru.yandex.canvas.model.CreativeDocument;
import ru.yandex.canvas.model.CreativeDocumentBatch;
import ru.yandex.canvas.service.AuthService;
import ru.yandex.canvas.service.CreativesService;
import ru.yandex.canvas.service.ExcelExportService;
import ru.yandex.canvas.service.ScreenshooterService;
import ru.yandex.canvas.service.screenshooters.CreativesScreenshooterHelperService;
import ru.yandex.direct.screenshooter.client.model.ScreenShooterScreenshot;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION;

/**
 * @author skirsanov
 */
@RestController
@RequestMapping(value = "/creatives")
public class CreativesController {
    private static final Collection<String> EXCLUDE_CREATIVE_DATA = Arrays.asList("items.data.bundle",
            "items.data.elements", "items.data.mediaSets", "items.data.options");

    private final CreativesService creativesService;
    private final AuthService authService;
    private final ScreenshooterService screenshooterService;
    private final CreativesScreenshooterHelperService screenshooterHelperService;

    public CreativesController(CreativesService creativesService, AuthService authService,
                               ScreenshooterService screenshooterService,
                               CreativesScreenshooterHelperService screenshooterHelperService) {
        this.creativesService = creativesService;
        this.authService = authService;
        this.screenshooterService = screenshooterService;
        this.screenshooterHelperService = screenshooterHelperService;
    }

    /**
     * curl -v "http://localhost:8080/creatives/1098045216?user_id=221776172&client_id=47934846" | jq .
     *
     * @param id
     * @return
     */
    @GetMapping(value = "{id}")
    public CreativeDocument getById(@PathVariable("id") long id) {
        return creativesService.get(id).orElseThrow(CreativeNotFoundException::new);
    }

    /**
     * curl -v "http://localhost:8080/creatives/1098045216/previewInfo?user_id=221776172&client_id=47934846" | jq .
     *
     * @param id
     * @return
     */
    @GetMapping(value = "{id}/previewInfo")
    public CreativePreviewInfo getPreviewInfoByIdOld(@PathVariable("id") long id) {
        return getPreviewInfoById(null, id);
    }

    @AuthorizeBy({AuthorizeBy.AuthType.TRUSTED_QUERY_STRING})
    @GetMapping(value = "{batch_id}/{id}/previewInfo")
    public CreativePreviewInfo getPreviewInfoById(@PathVariable("batch_id") String batchId,
                                                  @PathVariable("id") long id) {
        return creativesService
                .getCreativeInternalForPreview(id, batchId)
                .map(CreativePreviewInfo::fromCreativeDocument)
                .orElseThrow(CreativeNotFoundException::new);
    }

    @GetMapping(value = "getScreenshot/{id}")
    public ResponseEntity<byte[]> getScreenshot(@PathVariable("id") long id) {
        return getScreenshotOld(id, authService.getUserId());
    }

    @GetMapping(value = "{id}/getScreenshot")
    public ResponseEntity<byte[]> getScreenshotOld(@PathVariable("id") long id, @RequestParam("user_id") long userId) {

        /* Проверяем, что у юзера есть доступ к превью на данном клиенте, чтобы нельзя было
         * смотреть скриншоты чужих креативов.
         * TODO: временно! выключаем проверку прав, подробности в тикете DIRECT-117603
         */
        // authService.requirePermissionDifferentClient(clientId, Privileges.Permission.PREVIEW);

        var creative = creativesService.getCreativeWithClientIdOrThrow(id);

        ScreenShooterScreenshot screenshot = screenshooterHelperService.getScreenshot(creative.getCreative(),
                userId, creative.getClientId());
        return screenshooterService.prepareScreenshotForResponse(screenshot);
    }

    /**
     * Возвращает все креативы для данного клиента.
     */
    @GetMapping(produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE, "application/vnd.ms-excel"})
    public View excelExport(@RequestParam("client_id") long clientId) {

        List<CreativeDocumentBatch> batches = creativesService.getBatches(clientId, 0,
                0, // no limit
                emptyList(), EXCLUDE_CREATIVE_DATA, "date", true, emptySet()).getItems();

        return new AbstractXlsxStreamingView() {

            @Override
            protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request,
                                              HttpServletResponse response) throws Exception {
                response.setHeader(CONTENT_DISPOSITION, "attachment; filename=\"canvas_creatives.xlsx\"");

                ExcelExportService.fillCreativesWorkbook(workbook, batches);
            }
        };
    }

    /**
     * POJO to return non-sensible data for a CreativeUploadData preview
     */
    public static final class CreativePreviewInfo {
        private final String creativeURL;
        private final CreativePreviewInfoData data;

        public CreativePreviewInfo(String creativeURL, Integer width, Integer height) {
            this.creativeURL = creativeURL;
            data = new CreativePreviewInfoData(width, height);
        }

        public static CreativePreviewInfo fromCreativeDocument(CreativeDocument creative) {
            return new CreativePreviewInfo(
                    creative.getCreativeURL(),
                    creative.getData().getWidth(),
                    creative.getData().getHeight());
        }

        public String getCreativeURL() {
            return creativeURL;
        }

        public CreativePreviewInfoData getData() {
            return data;
        }

        public static final class CreativePreviewInfoData {
            @NotNull
            private final Integer width;

            @NotNull
            private final Integer height;

            public CreativePreviewInfoData(Integer width, Integer height) {
                this.width = width;
                this.height = height;
            }

            public Integer getWidth() {
                return width;
            }

            public Integer getHeight() {
                return height;
            }

        }
    }
}
