package ru.yandex.canvas.controllers.html5;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import ru.yandex.canvas.configs.auth.AuthorizeBy;
import ru.yandex.canvas.model.direct.CreativeInfo;
import ru.yandex.canvas.model.direct.CreativeUploadData;
import ru.yandex.canvas.model.direct.Privileges;
import ru.yandex.canvas.service.AuthService;
import ru.yandex.canvas.service.html5.Html5CreativesService;

import static ru.yandex.canvas.configs.auth.AuthorizeBy.AuthType.DIRECT_TOKEN;

@RestController
@RequestMapping(path = "/html5/direct")
@Validated
public class Html5DirectController {

    private AuthService authService;
    private Html5CreativesService html5CreativesService;

    public Html5DirectController(AuthService authService,
                                 Html5CreativesService html5CreativesService) {
        this.authService = authService;
        this.html5CreativesService = html5CreativesService;
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class UploadRequest {

        @JsonProperty("batches")
        @NotEmpty(message = "No one batch specified for upload")
        @Valid
        private List<BatchSpec> batches;

        public List<BatchSpec> getBatches() {
            return batches;
        }

        public UploadRequest() {
            batches = new ArrayList<>();
        }

        public static class BatchSpec {
            @JsonProperty("id")
            @NotEmpty(message = "Empty id for batch")
            private String id;

            @JsonProperty("creative_ids")
            @NotEmpty(message = "Empty list of creativeIds for upload")
            private List<Long> creativeIds;

            public BatchSpec() {
                creativeIds = new ArrayList<>();
            }

            public void setId(String id) {
                this.id = id;
            }

            public String getId() {
                return id;
            }

            public List<Long> getCreativeIds() {
                return creativeIds;
            }
        }
    }

    @AuthorizeBy({DIRECT_TOKEN})
    @GetMapping(path = "creatives")
    public List<CreativeInfo> getCreatives(
            @RequestParam("client_id") Long clientId,
            @RequestParam(name = "ids")
            @Valid @Pattern(regexp = "(\\d+\\s*,\\s*)*\\s*\\d+\\s*") String ids)
    {
        List<Long> parsedIds = Stream.of(ids.split(",\\s*"))
                .map(Long::parseLong)
                .collect(Collectors.toList());

        Map<Long, CreativeUploadData> creatives = html5CreativesService.getCreatives(parsedIds, clientId);

        List<CreativeInfo> answer = new ArrayList<>();

        for (Long id : parsedIds) {
            CreativeInfo creativeInfo = new CreativeInfo().setCreativeId(id);

            if (creatives.containsKey(id)) {
                creativeInfo
                        .setOk(true)
                        .setMessage(null)
                        .setCreative(creatives.get(id));
            } else {
                creativeInfo.setOk(false).setMessage("Not found");
            }

            answer.add(creativeInfo);
        }

        return answer;
    }

    @PostMapping(path = "creatives")
    public List<Long> uploadHtml5(
            @Valid @RequestBody UploadRequest uploadRequest,
            @RequestParam("client_id") Long clientId
    ) {
        authService.requirePermission(Privileges.Permission.CREATIVE_CREATE);

        return upload(uploadRequest, clientId, authService.getUserId());
    }

    /**
     * Ручка создания креатива в Директе с авторизацией по мастер-токену
     */
    @AuthorizeBy({DIRECT_TOKEN})
    @PostMapping(path = "/internal-creatives")
    public List<Long> internalUploadHtml5(
            @Valid @RequestBody UploadRequest uploadRequest,
            @RequestParam("client_id") Long clientId,
            @RequestParam("user_id") Long userId
    ) {
        return upload(uploadRequest, clientId, userId);
    }

    private List<Long> upload(UploadRequest uploadRequest, Long clientId, Long userId) {
        Map<String, List<Long>> batchId2Creatives = uploadRequest.getBatches().stream()
                .collect(Collectors.toMap(UploadRequest.BatchSpec::getId, UploadRequest.BatchSpec::getCreativeIds));

        return html5CreativesService.uploadHtml5ToDirect(batchId2Creatives, clientId, userId);
    }
}
