package com.nonononoki.alovoa.rest;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nonononoki.alovoa.Tools;
import com.nonononoki.alovoa.entity.user.UserImage;
import com.nonononoki.alovoa.entity.user.UserMiscInfo;
import com.nonononoki.alovoa.model.*;
import com.nonononoki.alovoa.service.UserService;
import jakarta.mail.MessagingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Set;
import java.util.UUID;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private UserService userService;
    @Value("${app.audio.max-size}")
    private int audioMaxSize;
    @Value("${app.image.max-size}")
    private int mediaMaxSize;

    // simple post to test session
    @PostMapping("/post")
    public void post() {
    }

    // GDPR
    @PostMapping(value = "/delete-account")
    public void deleteAccount() throws MessagingException, IOException, AlovoaException {
        userService.deleteAccountRequest();
    }

    @PostMapping(value = "/delete-account-confirm", consumes = "application/json")
    public void deleteAccountConfirm(@RequestBody UserDeleteAccountDto dto) throws NoSuchAlgorithmException,
            MessagingException, IOException, AlovoaException {
        userService.deleteAccountConfirm(dto);
    }

    @GetMapping(value = "/userdata/{uuid}")
    public ResponseEntity<Resource> getUserdata(@PathVariable UUID uuid) throws JsonProcessingException,
            AlovoaException, NumberFormatException {
        return userService.getUserdata(uuid);
    }

    @PostMapping(value = "/onboarding", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
    public void onboarding(@RequestParam("file") MultipartFile file, @RequestParam("data") String dto)
            throws AlovoaException, IOException {
        byte[] bytes = file.getBytes();
        if (bytes.length > mediaMaxSize) {
            throw new AlovoaException(AlovoaException.MAX_MEDIA_SIZE_EXCEEDED);
        }
        userService.onboarding(bytes, objectMapper.readValue(dto, ProfileOnboardingDto.class));
    }

    @PostMapping(value = "/update/profile-picture", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
    public void updateProfilePicture(@RequestParam("file") MultipartFile file, @RequestParam("mime") String mimeType)
            throws AlovoaException, IOException {
        byte[] bytes = file.getBytes();
        if (bytes.length > mediaMaxSize) {
            throw new AlovoaException(AlovoaException.MAX_MEDIA_SIZE_EXCEEDED);
        }
        userService.updateProfilePicture(bytes, mimeType);
    }

    @PostMapping(value = "/update/verification-picture")
    public void updateVerificationPicture(@RequestParam("file") MultipartFile file, @RequestParam("mime") String mimeType)
            throws AlovoaException, IOException {
        byte[] bytes = file.getBytes();
        if (bytes.length > mediaMaxSize) {
            throw new AlovoaException(AlovoaException.MAX_MEDIA_SIZE_EXCEEDED);
        }
        userService.updateVerificationPicture(bytes, mimeType);
    }

    @PostMapping(value = "/update/verification-picture/upvote/{uuid}")
    public void upvoteVerificationPicture(@PathVariable UUID uuid) throws AlovoaException, IOException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException, NoSuchPaddingException,
            BadPaddingException, NoSuchAlgorithmException, InvalidKeyException {
        userService.upvoteVerificationPicture(uuid);
    }

    @PostMapping(value = "/update/verification-picture/downvote/{uuid}")
    public void downvoteVerificationPicture(@PathVariable UUID uuid) throws AlovoaException {
        userService.downvoteVerificationPicture(uuid);
    }

    @GetMapping(value = "/get/audio/{uuid}")
    public String getAudio(@PathVariable UUID uuid) throws NumberFormatException, AlovoaException {
        return userService.getAudio(uuid);
    }

    @PostMapping(value = "/delete/audio")
    public void deleteAudio() throws AlovoaException {
        userService.deleteAudio();
    }

    @PostMapping(value = "/update/audio/{mimeType}", consumes = "text/plain")
    public void updateAudio(@RequestParam("file") MultipartFile file, @RequestParam("mime") String mimeType)
            throws AlovoaException, UnsupportedAudioFileException, IOException {
        byte[] bytes = file.getBytes();
        if (bytes.length > audioMaxSize) {
            throw new AlovoaException(AlovoaException.MAX_MEDIA_SIZE_EXCEEDED);
        }
        userService.updateAudio(bytes, mimeType);
    }

    @PostMapping(value = "/update/description", consumes = "text/plain")
    public void updateDescription(@RequestBody(required = false) String description) throws AlovoaException {
        userService.updateDescription(description);
    }

    @PostMapping("/update/intention/{intention}")
    public void updateIntention(@PathVariable long intention) throws AlovoaException {
        userService.updateIntention(intention);
    }

    @PostMapping("/update/min-age/{minAge}")
    public void updateMinAge(@PathVariable int minAge) throws AlovoaException {
        userService.updateMinAge(minAge);
    }

    @PostMapping("/update/max-age/{maxAge}")
    public void updateMaxAge(@PathVariable int maxAge) throws AlovoaException {
        userService.updateMaxAge(maxAge);
    }

    @PostMapping("/update/preferedGender/{genderId}/{activated}")
    public void updatePreferedGenders(@PathVariable int genderId, @PathVariable String activated) throws AlovoaException {
        userService.updatePreferedGender(genderId, Tools.binaryStringToBoolean(activated));
    }

    @PostMapping("/update/misc-info/{infoValue}/{activated}")
    public Set<UserMiscInfo> updateMiscInfo(@PathVariable long infoValue, @PathVariable String activated) throws AlovoaException {
        return userService.updateUserMiscInfo(infoValue, Tools.binaryStringToBoolean(activated));
    }

    @PostMapping("/interest/add/{value}")
    public void addInterest(@PathVariable String value) throws AlovoaException {
        userService.addInterest(value);
    }

    @PostMapping("/interest/delete/{value}")
    public void deleteInterest(@PathVariable String value) throws AlovoaException {
        userService.deleteInterest(value);
    }

    @GetMapping(value = "/interest/autocomplete/{name}")
    public List<UserInterestDto> interestAutocomplete(@PathVariable String name) throws AlovoaException {
        return userService.getInterestAutocomplete(name);
    }

    @PostMapping("/show-zodiac/update/{showZodiac}")
    public void updateZodiac(@PathVariable int showZodiac) throws AlovoaException {
        userService.updateShowZodiac(showZodiac);
    }

    @PostMapping("/units/update/{units}")
    public void updateUnits(@PathVariable int units) throws AlovoaException {
        userService.updateUnits(units);
    }

    @PostMapping(value = "/image/add", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
    public List<UserImageDto> addImage(@RequestParam("file") MultipartFile file, @RequestParam("mime") String mimeType)
            throws AlovoaException, IOException {
        byte[] bytes = file.getBytes();
        if (bytes.length > mediaMaxSize) {
            throw new AlovoaException(AlovoaException.MAX_MEDIA_SIZE_EXCEEDED);
        }
        return userService.addImage(bytes, mimeType);
    }

    @PostMapping("/image/delete/{imageId}")
    public void deleteImage(@PathVariable long imageId) throws AlovoaException {
        userService.deleteImage(imageId);
    }

    @PostMapping(value = "/like/{uuid}")
    public void likeUser(@PathVariable UUID uuid) throws AlovoaException {
        userService.likeUser(uuid, null);
    }

    @PostMapping(value = "/like/{uuid}/{message}")
    public void likeUser(@PathVariable UUID uuid, @PathVariable String message) throws AlovoaException {
        userService.likeUser(uuid, message);
    }

    @PostMapping(value = "/hide/{uuid}")
    public void hideUser(@PathVariable UUID uuid) throws NumberFormatException, AlovoaException {
        userService.hideUser(uuid);
    }

    @PostMapping(value = "/block/{uuid}")
    public void blockUser(@PathVariable UUID uuid) throws NumberFormatException, AlovoaException {
        userService.blockUser(uuid);
    }

    @PostMapping(value = "/unblock/{uuid}")
    public void unblockUser(@PathVariable UUID uuid) throws NumberFormatException, AlovoaException {
        userService.unblockUser(uuid);
    }

    @PostMapping(value = "/report/{uuid}", consumes = "text/plain")
    public void reportUser(@PathVariable UUID uuid, @RequestBody String comment) throws NumberFormatException,
            AlovoaException {
        userService.reportUser(uuid, comment);
    }

    @PostMapping("/update/location/{latitude}/{longitude}")
    public void updateLocation(@PathVariable Double latitude, @PathVariable Double longitude) throws AlovoaException {
        userService.updateUserLocation(latitude, longitude);
    }

    @GetMapping(value = "/status/new-alert")
    public boolean newAlert() throws AlovoaException {
        return userService.hasNewAlert();
    }

    @GetMapping(value = "/status/new-alert/{lang}")
    public boolean newAlert2(@PathVariable String lang) throws AlovoaException {
        return userService.hasNewAlert(lang);
    }

    @GetMapping(value = "/status/new-message")
    public boolean newMessage() throws AlovoaException {
        return userService.hasNewMessage();
    }

}
