PresetService.java

package com.oliwier.listmebackend.domain.service;

import com.oliwier.listmebackend.domain.model.*;
import com.oliwier.listmebackend.domain.repository.*;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;
import java.util.UUID;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class PresetService {

    private final PresetRepository presetRepository;
    private final PresetItemRepository presetItemRepository;
    private final ShoppingListRepository listRepository;
    private final ItemRepository itemRepository;
    private final ListDeviceRepository listDeviceRepository;

    public List<Preset> getForUser(User user) {
        return presetRepository.findForUser(user.getId());
    }

    public List<PresetItem> getItems(UUID presetId) {
        return presetItemRepository.findByPresetIdOrderByPosition(presetId);
    }

    @Transactional
    public Preset createFromList(User user, Device device, UUID fromListId, String name, String emoji) {
        // Access check: user owns the list OR device is a participant
        ShoppingList list = listRepository.findById(fromListId)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "List not found"));
        boolean ownsIt = list.getUser() != null && list.getUser().getId().equals(user.getId());
        boolean isParticipant = listDeviceRepository.existsByListIdAndDeviceId(fromListId, device.getId());
        if (!ownsIt && !isParticipant) {
            throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Not a participant of this list");
        }

        Preset preset = new Preset();
        preset.setName(name);
        preset.setEmoji(emoji != null && !emoji.isBlank() ? emoji : list.getEmoji());
        preset.setCreatedByDevice(device);
        preset.setUser(user);

        List<Item> items = itemRepository.findByListIdAndDeletedAtIsNullOrderByPosition(fromListId);
        for (int i = 0; i < items.size(); i++) {
            Item src = items.get(i);
            PresetItem pi = new PresetItem();
            pi.setPreset(preset);
            pi.setName(src.getName());
            pi.setQuantity(src.getQuantity());
            pi.setQuantityUnit(src.getQuantityUnit());
            pi.setPrice(src.getPrice());
            pi.setImageUrl(src.getImageUrl());
            pi.setPosition(i);
            preset.getItems().add(pi);
        }

        return presetRepository.save(preset);
    }

    @Transactional
    public void delete(User user, UUID presetId) {
        Preset preset = presetRepository.findById(presetId)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Preset not found"));
        if (preset.getUser() == null) {
            throw new ResponseStatusException(HttpStatus.FORBIDDEN, "System presets cannot be deleted");
        }
        if (!preset.getUser().getId().equals(user.getId())) {
            throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Not your preset");
        }
        presetRepository.delete(preset);
    }
}