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

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

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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import de.oaa.xxx.games.chastity.common.BaseLockRepository;
import de.oaa.xxx.user.UserService;

@RestController
@RequestMapping("/games/chastity/community/taskvote")
public class CommunityTaskVoteController {

	private final UserService userService;
	private final CommunityTaskVoteRepository taskVoteRepository;
	private final CommunityTaskVoteEntryRepository taskVoteEntryRepository;
	private final BaseLockRepository baseLockRepository;

	public CommunityTaskVoteController(UserService userService,
			CommunityTaskVoteRepository taskVoteRepository,
			CommunityTaskVoteEntryRepository taskVoteEntryRepository,
			BaseLockRepository baseLockRepository) {
		this.userService = userService;
		this.taskVoteRepository = taskVoteRepository;
		this.taskVoteEntryRepository = taskVoteEntryRepository;
		this.baseLockRepository = baseLockRepository;
	}

	@GetMapping("/{displayId}")
	public ResponseEntity<CommunityTaskVoteDisplayDTO> getVote(@PathVariable("displayId") UUID displayId, Principal principal) {
		UUID myId = userService.requireUser(principal).getUserId();
		
		var voteOpt = taskVoteRepository.findById(displayId);
		if (voteOpt.isEmpty() || !voteOpt.get().isActive()) {
			return ResponseEntity.noContent().build();
		}
		var vote = voteOpt.get();
		var lockOpt = baseLockRepository.findById(vote.getLockId());
		if (lockOpt.isEmpty()) {
			return ResponseEntity.noContent().build();
		}
		var lock = lockOpt.get();
		boolean isOwnLock = lock.getLockee().equals(myId);
		var entryList = new ArrayList<CommunityTaskVoteDisplayEntryDTO>();
		var tasks = lock.getTasks();
		var userVote = taskVoteEntryRepository.findByDisplayIdAndUserId(displayId, myId);
		for (int i = 0; i < tasks.size(); i++) {
			var task = tasks.get(i);
			boolean myVote = false;
			int votes = taskVoteEntryRepository.countByDisplayIdAndTaskIndex(displayId, i);
			if (userVote != null && userVote.getTaskIndex() == i) {
				myVote = true;
			}
			entryList.add(new CommunityTaskVoteDisplayEntryDTO(task.getTitle(), 
					task.getDescription(), task.getMinutes(), votes, myVote));
		}
		return ResponseEntity.ok(new CommunityTaskVoteDisplayDTO(displayId, voteOpt.get().getCreatedAt(), displayId, myId, isOwnLock, entryList));
	}


	@PostMapping("/{displayId}/vote/{taskIndex}")
	@Transactional
	public ResponseEntity<Void> castVote(@PathVariable("displayId") UUID displayId, @PathVariable("taskIndex") int taskIndex,
			Principal principal) {
		UUID myId = userService.requireUser(principal).getUserId();

		var voteOpt = taskVoteRepository.findById(displayId);
		if (voteOpt.isEmpty())
			return ResponseEntity.notFound().build();
		var vote = voteOpt.get();
		if (!vote.isActive() || vote.getExpiresAt().isBefore(LocalDateTime.now()))
			return ResponseEntity.status(409).build();

		var lockOpt = baseLockRepository.findById(vote.getLockId());
		if (lockOpt.isEmpty())
			return ResponseEntity.notFound().build();
		var lock = lockOpt.get();

		if (lock.getLockee().equals(myId))
			return ResponseEntity.status(403).build();

		if (lock.getTasks() == null || taskIndex < 0 || taskIndex >= lock.getTasks().size())
			return ResponseEntity.badRequest().build();

		if (taskVoteEntryRepository.existsByDisplayIdAndUserId(displayId, myId))
			return ResponseEntity.status(409).build();

		CommunityTaskVoteEntryEntity entry = new CommunityTaskVoteEntryEntity();
		entry.setDisplayId(displayId);
		entry.setUserId(myId);
		entry.setTaskIndex(taskIndex);
		taskVoteEntryRepository.save(entry);

		return ResponseEntity.noContent().build();
	}
}
