package de.oaa.xxx.games.chastity.community;

import java.security.Principal;
import java.time.LocalDateTime;
import java.util.UUID;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import de.oaa.xxx.games.chastity.common.CodeCreator;
import de.oaa.xxx.user.UserRepository;
import de.oaa.xxx.user.UserService;

@RestController
@RequestMapping("/games/chastity/community/verification")
@Transactional
public class CommunityVerificationController {		

	private final CommunityVerificationRepository verificationRepository;
	private final CommunityVerificationVoteRepository verificationVoteRepository;
	private final UserRepository userRepository;
	private final UserService userService;

	public CommunityVerificationController(CommunityVerificationRepository verificationRepository,
			CommunityVerificationVoteRepository verificationVoteRepository,
			UserRepository userRepository,
			UserService userService) {
		this.verificationRepository = verificationRepository;
		this.verificationVoteRepository = verificationVoteRepository;
		this.userRepository = userRepository;
		this.userService = userService;
	}
	
	@GetMapping("/{displayId}")
	public ResponseEntity<CommunityVerificationDTO> get(@PathVariable UUID displayId, Principal principal) {
		var optional = verificationRepository.findById(displayId);
		if (optional.isEmpty()) {
			return ResponseEntity.noContent().build();
		}
		var entity = optional.get();

		boolean isOwnLock = false;
		Boolean myVote = null;
		if (principal != null) {
			var userOpt = userRepository.findByEmail(principal.getName());
			if (userOpt.isPresent()) {
				var myId = userOpt.get().getUserId();
				isOwnLock = myId.equals(entity.getLockeeId());
				if (!isOwnLock) {
					myVote = verificationVoteRepository
							.findByVerificationIdAndUserId(displayId, myId)
							.map(CommunityVerificationVoteEntity::isUpvote)
							.orElse(null);
				}
			}
		}

		var dto = entity.toVerification(isOwnLock, myVote);
		verificationVoteRepository.findAllByVerificationId(displayId).stream()
				.map(CommunityVerificationVoteEntity::toVerificationVote)
				.forEach(dto.votes()::add);
		return ResponseEntity.ok(dto);
	}

	@GetMapping("/new")
	public ResponseEntity<CommunityVerificationDTO> createVerification() {
		var verification = new CommunityVerificationEntity();
		verification.setDisplayId(UUID.randomUUID());
		verification.setCode(CodeCreator.createAlphanumeric(6));
		verification.setCreatedAt(LocalDateTime.now());
		verificationRepository.save(verification);
		return ResponseEntity.ok(verification.toVerification(true, null));
	}

	@PutMapping("/{displayId}")
	public ResponseEntity<Void> update(@PathVariable UUID displayId, @RequestBody CommunityVerificationDTO dto,
			Principal principal) {
		userService.requireUser(principal);
		var entity = verificationRepository.findById(displayId).orElse(null);
		if (entity == null) {
			return ResponseEntity.notFound().build();
		}
		if (entity.getCreatedAt().isBefore(LocalDateTime.now().minusHours(1))) {
			return ResponseEntity.status(HttpStatus.GONE).build();
		}
		if (dto.image() != null) {
			entity.setImage(dto.image());
		}
		verificationRepository.save(entity);
		return ResponseEntity.ok().build();
	}

	@PostMapping("/{verificationId}/vote/")
	public ResponseEntity<Void> addVote(@PathVariable UUID verificationId, @RequestBody CommunityVerificationVoteDTO dto,
			Principal principal) {
		var user = userService.requireUser(principal);
		if (!verificationRepository.existsById(verificationId)) return ResponseEntity.notFound().build();

		var vEntity = verificationRepository.findById(verificationId).orElse(null);
		if (vEntity == null) return ResponseEntity.notFound().build();
		if (user.getUserId().equals(vEntity.getLockeeId())) return ResponseEntity.status(403).build();
		if (verificationVoteRepository.findByVerificationIdAndUserId(verificationId, user.getUserId()).isPresent()) {
			return ResponseEntity.status(409).build();
		}
		var vote = new CommunityVerificationVoteEntity();
		vote.setVoteId(UUID.randomUUID());
		vote.setVerificationId(verificationId);
		vote.setUserId(user.getUserId());
		vote.setUpvote(dto.upvote());
		if (dto.upvote()) {
			vEntity.setCountUpvotes(vEntity.getCountUpvotes() + 1);
		} else {
			vEntity.setCountDownvotes(vEntity.getCountDownvotes() + 1);
		}
		verificationVoteRepository.save(vote);
		return ResponseEntity.accepted().build();
	}

}
