package de.oaa.xxx.games.bdsm.controller;

import java.security.Principal;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import de.oaa.xxx.games.bdsm.entity.BdsmEinladungEntity;
import de.oaa.xxx.games.bdsm.entity.BdsmEinladungEntity.Status;
import de.oaa.xxx.games.bdsm.repository.BdsmEinladungRepository;
import de.oaa.xxx.social.SystemMessageService;
import de.oaa.xxx.social.repository.FriendshipRepository;
import de.oaa.xxx.user.UserRepository;
import de.oaa.xxx.user.UserService;

@RestController
@RequestMapping("/bdsm/einladung")
@Transactional
public class BdsmEinladungController {

    private final BdsmEinladungRepository einladungRepository;
    private final UserRepository userRepository;
    private final FriendshipRepository friendshipRepository;
    private final SystemMessageService systemMessageService;
    private final UserService userService;

    public BdsmEinladungController(BdsmEinladungRepository einladungRepository,
                                   UserRepository userRepository,
                                   FriendshipRepository friendshipRepository,
                                   SystemMessageService systemMessageService,
                                   UserService userService) {
        this.einladungRepository = einladungRepository;
        this.userRepository = userRepository;
        this.friendshipRepository = friendshipRepository;
        this.systemMessageService = systemMessageService;
        this.userService = userService;
    }

    record EinladungRequest(UUID setupId, int slotIndex, UUID inviteeId) {}
    record AntwortRequest(boolean accepted, String mode) {} // mode: OWN_DEVICE | HOST_DEVICE
    record SpielerDatenRequest(String spielerDatenJson) {}

    private UUID currentUserId(Principal principal) {
        return userService.requireUser(principal).getUserId();
    }

    @PostMapping
    public ResponseEntity<Map<String, Object>> sendEinladung(@RequestBody EinladungRequest req, Principal principal) {
        UUID inviterId = currentUserId(principal);
        if (inviterId == null) return ResponseEntity.status(401).build();

        // Freundschaft prüfen
        var friendship = friendshipRepository.findExisting(inviterId, req.inviteeId());
        if (friendship.isEmpty() || friendship.get().getStatus() != de.oaa.xxx.social.entity.FriendshipEntity.Status.ACCEPTED) {
            return ResponseEntity.status(403).build();
        }

        if (req.setupId() == null) return ResponseEntity.badRequest().build();

        // Prüfen ob Person bereits aktiv eingeladen oder Teil des Spiels
        boolean alreadyInvited = einladungRepository.findBySetupId(req.setupId()).stream()
                .anyMatch(e -> req.inviteeId().equals(e.getInviteeId())
                        && (e.getStatus() == Status.PENDING
                                || e.getStatus() == Status.ACCEPTED_OWN
                                || e.getStatus() == Status.ACCEPTED_HOST));
        if (alreadyInvited) {
            return ResponseEntity.status(409).build();
        }

        // Alte Einladung für diesen Slot canceln
        einladungRepository.findBySetupId(req.setupId()).stream()
                .filter(e -> e.getSlotIndex() == req.slotIndex() && e.getStatus() == Status.PENDING)
                .forEach(e -> e.setStatus(Status.CANCELLED));

        BdsmEinladungEntity entity = new BdsmEinladungEntity();
        entity.setEinladungId(UUID.randomUUID());
        entity.setSetupId(req.setupId());
        entity.setInviterId(inviterId);
        entity.setInviteeId(req.inviteeId());
        entity.setSlotIndex(req.slotIndex());
        entity.setStatus(Status.PENDING);
        entity.setCreatedAt(LocalDateTime.now());
        einladungRepository.save(entity);

        systemMessageService.pushInvitationUpdate(req.inviteeId());

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("einladungId", entity.getEinladungId());
        return ResponseEntity.ok(result);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> cancelEinladung(@PathVariable("id") UUID id, Principal principal) {
        UUID userId = currentUserId(principal);
        if (userId == null) return ResponseEntity.status(401).build();
        BdsmEinladungEntity e = einladungRepository.findById(id).orElse(null);
        if (e == null) return ResponseEntity.notFound().build();
        if (!e.getInviterId().equals(userId)) return ResponseEntity.status(403).build();
        e.setStatus(Status.CANCELLED);
        systemMessageService.pushInvitationUpdate(e.getInviteeId());
        return ResponseEntity.accepted().build();
    }

    @GetMapping
    public ResponseEntity<List<Map<String, Object>>> getBySetupId(@RequestParam("setupId") UUID setupId, Principal principal) {
        UUID userId = currentUserId(principal);
        if (userId == null) return ResponseEntity.status(401).build();
        List<Map<String, Object>> list = einladungRepository.findBySetupId(setupId).stream()
                .map(this::toMap).toList();
        return ResponseEntity.ok(list);
    }

    @GetMapping("/meine-aktive")
    public ResponseEntity<Map<String, Object>> getAktive(Principal principal) {
        UUID userId = currentUserId(principal);
        if (userId == null) return ResponseEntity.status(401).build();
        return einladungRepository.findByInviteeIdAndStatus(userId, Status.ACCEPTED_OWN)
                .stream().findFirst()
                .map(e -> ResponseEntity.ok(toMap(e)))
                .orElse(ResponseEntity.noContent().build());
    }

    @GetMapping("/pending/count")
    public ResponseEntity<Integer> getPendingCount(Principal principal) {
        UUID userId = currentUserId(principal);
        if (userId == null) return ResponseEntity.status(401).build();
        return ResponseEntity.ok(einladungRepository.findByInviteeIdAndStatus(userId, Status.PENDING).size());
    }

    @GetMapping("/pending")
    public ResponseEntity<List<Map<String, Object>>> getPending(Principal principal) {
        UUID userId = currentUserId(principal);
        if (userId == null) return ResponseEntity.status(401).build();
        List<Map<String, Object>> list = einladungRepository.findByInviteeIdAndStatus(userId, Status.PENDING)
                .stream().map(e -> {
                    Map<String, Object> m = toMap(e);
                    userRepository.findById(e.getInviterId()).ifPresent(u -> {
                        m.put("inviterName", u.getName());
                        m.put("inviterAvatar", u.getProfilePicture() != null ? u.getProfilePicture() : "");
                    });
                    return m;
                }).toList();
        return ResponseEntity.ok(list);
    }

    @GetMapping("/sent")
    public ResponseEntity<List<Map<String, Object>>> getSent(Principal principal) {
        UUID userId = currentUserId(principal);
        if (userId == null) return ResponseEntity.status(401).build();
        List<Map<String, Object>> list = einladungRepository.findByInviterIdAndStatus(userId, Status.PENDING)
                .stream().map(e -> {
                    Map<String, Object> m = toMap(e);
                    userRepository.findById(e.getInviteeId()).ifPresent(u -> {
                        m.put("inviteeName", u.getName());
                        m.put("inviteeAvatar", u.getProfilePicture() != null ? u.getProfilePicture() : "");
                    });
                    return m;
                }).toList();
        return ResponseEntity.ok(list);
    }

    @GetMapping("/{id}")
    public ResponseEntity<Map<String, Object>> getById(@PathVariable("id") UUID id, Principal principal) {
        UUID userId = currentUserId(principal);
        if (userId == null) return ResponseEntity.status(401).build();
        BdsmEinladungEntity e = einladungRepository.findById(id).orElse(null);
        if (e == null) return ResponseEntity.notFound().build();
        if (!e.getInviteeId().equals(userId) && !e.getInviterId().equals(userId)) {
            return ResponseEntity.status(403).build();
        }
        Map<String, Object> m = toMap(e);
        userRepository.findById(e.getInviterId()).ifPresent(u -> {
            m.put("inviterName", u.getName());
            m.put("inviterAvatar", u.getProfilePicture() != null ? u.getProfilePicture() : "");
        });
        return ResponseEntity.ok(m);
    }

    @PutMapping("/{id}/spielerdaten")
    public ResponseEntity<Void> spielerDatenEinreichen(@PathVariable("id") UUID id, @RequestBody SpielerDatenRequest req, Principal principal) {
        UUID userId = currentUserId(principal);
        if (userId == null) return ResponseEntity.status(401).build();
        BdsmEinladungEntity e = einladungRepository.findById(id).orElse(null);
        if (e == null) return ResponseEntity.notFound().build();
        if (!e.getInviteeId().equals(userId)) return ResponseEntity.status(403).build();
        if (e.getStatus() != Status.ACCEPTED_OWN) return ResponseEntity.badRequest().build();
        e.setSpielerDatenJson(req.spielerDatenJson());
        e.setBereit(true);
        return ResponseEntity.accepted().build();
    }

    @PutMapping("/{id}/antwort")
    public ResponseEntity<Void> antwort(@PathVariable("id") UUID id, @RequestBody AntwortRequest req, Principal principal) {
        UUID userId = currentUserId(principal);
        if (userId == null) return ResponseEntity.status(401).build();
        BdsmEinladungEntity e = einladungRepository.findById(id).orElse(null);
        if (e == null) return ResponseEntity.notFound().build();
        if (!e.getInviteeId().equals(userId)) return ResponseEntity.status(403).build();
        if (e.getStatus() != Status.PENDING) return ResponseEntity.badRequest().build();
        if (!req.accepted()) {
            e.setStatus(Status.DECLINED);
        } else if ("OWN_DEVICE".equals(req.mode())) {
            e.setStatus(Status.ACCEPTED_OWN);
        } else {
            e.setStatus(Status.ACCEPTED_HOST);
        }
        return ResponseEntity.accepted().build();
    }

    private Map<String, Object> toMap(BdsmEinladungEntity e) {
        Map<String, Object> m = new LinkedHashMap<>();
        m.put("einladungId", e.getEinladungId());
        m.put("setupId", e.getSetupId());
        m.put("slotIndex", e.getSlotIndex());
        m.put("inviteeId", e.getInviteeId());
        m.put("inviterId", e.getInviterId());
        m.put("status", e.getStatus().name());
        m.put("sessionId", e.getSessionId());
        m.put("bereit", e.isBereit());
        m.put("spielerDatenJson", e.getSpielerDatenJson());
        userRepository.findById(e.getInviteeId()).ifPresent(u -> m.put("inviteeName", u.getName()));
        return m;
    }
}
