package com.sn.sowsysrestapi.api.controller;

import com.sn.sowsysrestapi.api.converter.ProfilePictureConverter;
import com.sn.sowsysrestapi.api.dto.ProfilePictureDTO;
import com.sn.sowsysrestapi.api.dto.input.ProfilePictureInput;
import com.sn.sowsysrestapi.domain.entity.ProfilePicture;
import com.sn.sowsysrestapi.domain.entity.User;
import com.sn.sowsysrestapi.domain.exception.EntityNotFoundException;
import com.sn.sowsysrestapi.domain.service.PictureStorageService;
import com.sn.sowsysrestapi.domain.service.ProfilePictureService;
import com.sn.sowsysrestapi.domain.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@RestController
@RequestMapping("/api/users/{userCode}/profile-picture")
public class ProfilePictureController {

    @Autowired
    private UserService userService;

    @Autowired
    private ProfilePictureConverter profilePictureConverter;

    @Autowired
    private ProfilePictureService profilePictureService;

    @Autowired
    private PictureStorageService pictureStorage;

    @GetMapping
    public ResponseEntity<InputStreamResource> fetchPicture(@PathVariable String userCode,
                                                            @RequestHeader(name = "accept") String acceptHeader)
        throws HttpMediaTypeNotAcceptableException {

        try {
            ProfilePicture profilePicture = profilePictureService.findOrFail(userCode);

            MediaType mediaTypePicture = MediaType.parseMediaType(profilePicture.getContentType());
            List<MediaType> acceptedMediaTypes = MediaType.parseMediaTypes(acceptHeader);

            verifyMediaTypeCompatibility(mediaTypePicture, acceptedMediaTypes);

            InputStream inputStream = pictureStorage.recover(profilePicture.getFileName());

            return ResponseEntity.ok()
                    .contentType(mediaTypePicture)
                    .body(new InputStreamResource(inputStream));

        } catch (EntityNotFoundException e) {
            return ResponseEntity.notFound().build();
        }

    }

    @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public ProfilePictureDTO search(@PathVariable String userCode) {

        ProfilePicture profilePicture = profilePictureService.findOrFail(userCode);

        return profilePictureConverter.toDto(profilePicture);

    }

    @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ProfilePictureDTO updatePicture(@PathVariable String userCode,
                                           @Valid ProfilePictureInput profilePictureInput) throws IOException {

        User user = userService.findOrFail(userCode);

        MultipartFile file = profilePictureInput.getFile();

        ProfilePicture picture = new ProfilePicture();
        picture.setUser(user);
        picture.setDescription(profilePictureInput.getDescription());
        picture.setContentType(file.getContentType());
        picture.setFileSize(file.getSize());
        picture.setFileName(file.getOriginalFilename());

        ProfilePicture savedPicture = profilePictureService.save(picture, file.getInputStream());

        return profilePictureConverter.toDto(savedPicture);

    }

    @DeleteMapping
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable String userCode) {
        profilePictureService.delete(userCode);
    }

    private void verifyMediaTypeCompatibility(MediaType pictureMediaType, List<MediaType> acceptedMediaTypes)
    throws HttpMediaTypeNotAcceptableException {

        boolean compatible = acceptedMediaTypes.stream()
                .anyMatch(acceptedMediaType -> acceptedMediaType.isCompatibleWith(pictureMediaType));

        if (!compatible) {
            throw new HttpMediaTypeNotAcceptableException(acceptedMediaTypes);
        }

    }


}
