package com.infoclinika.pdx.controller;

import com.infoclinika.pdx.domain.sample.SampleType;
import com.infoclinika.pdx.projection.BaseStatistics;
import com.infoclinika.pdx.projection.PrimarySiteStatistics;
import com.infoclinika.pdx.projection.SensitivitySummary;
import com.infoclinika.pdx.service.FileParser;
import com.infoclinika.pdx.service.ParsedFile;
import com.infoclinika.pdx.service.sensitivity.SensitivityService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Map;

import static com.google.common.collect.Lists.newArrayList;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
import static org.springframework.util.MimeTypeUtils.TEXT_PLAIN_VALUE;

/**
 * Handles requests to work with sensitivity data.
 */
@RestController
@RequestMapping("/api/sensitivity")
public class SensitivityController {
    private static final String TAB_SEPARATED_VALUES = "text/tab-separated-values";
    private static final List<String> AVAILABLE_MIME_TYPES = newArrayList(TEXT_PLAIN_VALUE, TAB_SEPARATED_VALUES);

    private static final String FILE_PARAM = "file";
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final SensitivityService sensitivityService;
    private final FileParser fileParser;

    /**
     * Constructor to provide required services.
     */
    @Autowired
    public SensitivityController(SensitivityService sensitivityService, FileParser fileParser) {
        this.sensitivityService = sensitivityService;
        this.fileParser = fileParser;
    }

    /**
     * Returns summary for example Sensitivity results.
     */
    @GetMapping("/data")
    @ResponseStatus(HttpStatus.OK)
    public SensitivitySummary getExampleDataSummary() {
        logger.debug("Request to /api/sensitivity/data");
        return sensitivityService.getSummary();
    }

    /**
     * Returns Sensitivity data from provided file.
     *
     * @param file file to parse
     */
    @PostMapping("/data/custom")
    @ResponseStatus(HttpStatus.OK)
    public SensitivitySummary getCustomDataSummary(@RequestParam(FILE_PARAM)
                                                           MultipartFile file) {
        logger.debug("Request to /api/sensitivity/data/custom");

        final String contentType = file.getContentType();
        if (!AVAILABLE_MIME_TYPES.contains(contentType)) {
            throw new IllegalArgumentException(String.format("Incorrect content type: '%s'. Expected '%s'",
                                                             contentType, AVAILABLE_MIME_TYPES));
        }

        final ParsedFile parsedFile = fileParser.parseFile(file);
        return sensitivityService.getSummary(parsedFile);
    }

    /**
     * Returns statistics for Sensitivity data.
     */
    @GetMapping("/statistics")
    @ResponseStatus(HttpStatus.OK)
    public Map<SampleType, List<BaseStatistics>> getStatistics() {
        logger.debug("Request to /api/sensitivity/statistics");
        final List<PrimarySiteStatistics> statistics = sensitivityService.getStatistics();
        return statistics.stream()
                         .collect(groupingBy(PrimarySiteStatistics::getType,
                                             mapping(item -> new BaseStatistics(item.getName(), item.getCount()),
                                                     toList())));
    }
}
