package de.oaa.xxx.vorlieben;

import de.oaa.xxx.social.entity.FriendshipEntity;
import de.oaa.xxx.social.repository.FriendshipRepository;
import de.oaa.xxx.user.Sichtbarkeit;
import de.oaa.xxx.user.UserEntity;
import de.oaa.xxx.user.UserRepository;
import de.oaa.xxx.user.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/vorlieben")
@Transactional
public class VorliebenController {

    private final VorliebeKategorieRepository kategorieRepository;
    private final VorliebeItemRepository itemRepository;
    private final UserVorliebeRepository userVorliebeRepository;
    private final UserService userService;
    private final UserRepository userRepository;
    private final FriendshipRepository friendshipRepository;

    public VorliebenController(VorliebeKategorieRepository kategorieRepository,
                                VorliebeItemRepository itemRepository,
                                UserVorliebeRepository userVorliebeRepository,
                                UserService userService,
                                UserRepository userRepository,
                                FriendshipRepository friendshipRepository) {
        this.kategorieRepository  = kategorieRepository;
        this.itemRepository       = itemRepository;
        this.userVorliebeRepository = userVorliebeRepository;
        this.userService          = userService;
        this.userRepository       = userRepository;
        this.friendshipRepository = friendshipRepository;
    }

    record ItemDto(UUID itemId, String name, int sortOrder) {}
    record KategorieWithItems(UUID kategorieId, String name, int sortOrder, List<ItemDto> items) {}

    /** Returns all categories with their items – used by the profile edit page. */
    @GetMapping("/items")
    public ResponseEntity<List<KategorieWithItems>> getItems() {
        List<VorliebeKategorieEntity> kategorien = kategorieRepository.findAllByOrderBySortOrderAscNameAsc();
        List<VorliebeItemEntity> allItems = itemRepository.findAllByOrderBySortOrderAscNameAsc();

        Map<UUID, List<VorliebeItemEntity>> byKategorie = allItems.stream()
                .collect(Collectors.groupingBy(VorliebeItemEntity::getKategorieId));

        List<KategorieWithItems> result = kategorien.stream()
                .map(k -> new KategorieWithItems(
                        k.getKategorieId(), k.getName(), k.getSortOrder(),
                        byKategorie.getOrDefault(k.getKategorieId(), List.of()).stream()
                                .map(i -> new ItemDto(i.getItemId(), i.getName(), i.getSortOrder()))
                                .toList()))
                .filter(k -> !k.items().isEmpty())
                .toList();
        return ResponseEntity.ok(result);
    }

    /** Returns the current user's ratings as a map of itemId → bewertung name. */
    @GetMapping("/me")
    public ResponseEntity<Map<String, String>> getMyVorlieben(Principal principal) {
        UUID userId = userService.requireUser(principal).getUserId();
        Map<String, String> result = userVorliebeRepository.findByUserId(userId).stream()
                .collect(Collectors.toMap(
                        uv -> uv.getItemId().toString(),
                        uv -> uv.getBewertung().name()));
        return ResponseEntity.ok(result);
    }

    /** Saves the current user's ratings. Value null or blank removes the rating. */
    @PutMapping("/me")
    public ResponseEntity<Void> saveMyVorlieben(@RequestBody Map<String, String> ratings, Principal principal) {
        UUID userId = userService.requireUser(principal).getUserId();
        for (var entry : ratings.entrySet()) {
            UUID itemId;
            try { itemId = UUID.fromString(entry.getKey()); }
            catch (IllegalArgumentException e) { continue; }

            String bewertungStr = entry.getValue();
            if (bewertungStr == null || bewertungStr.isBlank()) {
                userVorliebeRepository.findByUserIdAndItemId(userId, itemId)
                        .ifPresent(userVorliebeRepository::delete);
            } else {
                VorliebeBewertung bewertung;
                try { bewertung = VorliebeBewertung.valueOf(bewertungStr); }
                catch (IllegalArgumentException e) { continue; }

                UserVorliebeEntity uv = userVorliebeRepository.findByUserIdAndItemId(userId, itemId)
                        .orElseGet(() -> {
                            UserVorliebeEntity n = new UserVorliebeEntity();
                            n.setId(UUID.randomUUID());
                            n.setUserId(userId);
                            n.setItemId(itemId);
                            return n;
                        });
                uv.setBewertung(bewertung);
                userVorliebeRepository.save(uv);
            }
        }
        return ResponseEntity.ok().build();
    }

    /** Returns another user's ratings, respecting their privacy setting. */
    @GetMapping("/user/{userId}")
    public ResponseEntity<Map<String, Object>> getUserVorlieben(
            @PathVariable("userId") UUID userId, Principal principal) {
        UserEntity targetUser = userRepository.findById(userId).orElse(null);
        if (targetUser == null) return ResponseEntity.notFound().build();

        boolean isOwn    = false;
        boolean isFriend = false;
        if (principal != null) {
            UUID myId = userService.requireUser(principal).getUserId();
            isOwn = myId.equals(userId);
            if (!isOwn) {
                Optional<FriendshipEntity> f = friendshipRepository.findExisting(myId, userId);
                isFriend = f.isPresent() && f.get().getStatus() == FriendshipEntity.Status.ACCEPTED;
            }
        }

        Sichtbarkeit sv = targetUser.getSichtbarkeitVorlieben();
        if (sv == null) sv = Sichtbarkeit.ALLE;

        boolean canSee = isOwn
                || sv == Sichtbarkeit.ALLE
                || (sv == Sichtbarkeit.NUR_FREUNDE && isFriend);

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("sichtbarkeit", sv.name());
        result.put("canSee", canSee);

        if (canSee) {
            Map<String, String> ratingsMap = userVorliebeRepository.findByUserId(userId).stream()
                    .collect(Collectors.toMap(
                            uv -> uv.getItemId().toString(),
                            uv -> uv.getBewertung().name()));
            result.put("ratings", ratingsMap);
        }
        return ResponseEntity.ok(result);
    }
}
