HouseholdService.java

package com.hwhub.backend.application.service;

import com.hwhub.backend.application.service.notification.NotificationPublisher;
import com.hwhub.backend.domain.enums.ProgramType;
import com.hwhub.backend.domain.model.HouseholdMemberModel;
import com.hwhub.backend.domain.model.HouseholdModel;
import com.hwhub.backend.domain.model.UserModel;
import com.hwhub.backend.domain.repository.HouseholdMemberRepository;
import com.hwhub.backend.domain.repository.HouseholdRepository;
import com.hwhub.backend.presentation.rest.common.ResourceNotFoundException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class HouseholdService {

  private final HouseholdRepository householdRepository;
  private final HouseholdAuthorizationService householdAuthorizationService;
  private final HouseholdMemberService householdMemberService;
  private final UserService userService;
  private final HouseholdMemberRepository householdMemberRepository;
  private final NotificationPublisher notificationPublisher;

  @Transactional
  public void updateHouseholdName(Long householdId, Long userId, String name) {
    // 認可チェック
    householdAuthorizationService.assertUserBelongsToHousehold(householdId, userId);

    HouseholdModel model = householdRepository.findById(householdId);
    if (model == null) {
      throw new ResourceNotFoundException("Household not found. householdId=" + householdId);
    }

    model.changeName(name);
    householdRepository.update(model, userId, ProgramType.ONL_HLD.getCode());
  }

  @Transactional
  public HouseholdModel createHousehold(Long userId, String name) {

    // 世帯登録
    HouseholdModel model = HouseholdModel.create(name, userId);
    HouseholdModel inserted =
        householdRepository.insert(model, userId, ProgramType.ONL_HLD.getCode());

    // 自身をメンバーとして登録。ニックネーム初期値はユーザの表示名。
    UserModel userModel = userService.getProfile(userId);
    householdMemberService.createMember(
        inserted.getHouseholdId(), userId, userModel.getDisplayName(), userId);

    return inserted;
  }

  @Transactional
  public void deleteHousehold(Long householdId, Long userId) {
    HouseholdModel household = householdRepository.findById(householdId);
    if (household == null) {
      throw new ResourceNotFoundException("Household not found: " + householdId);
    }

    if (!household.isOwner(userId)) {
      throw new AccessDeniedException("Only the owner can delete the household.");
    }

    // 他の有効なメンバーがいる場合は削除不可(安全策)
    List<HouseholdMemberModel> activeMembers =
        householdMemberRepository.findActiveByHouseholdId(householdId);
    if (activeMembers.size() > 1) {
      throw new IllegalArgumentException(
          "Cannot delete household with other active members. Please remove them first.");
    }

    // メンバーを物理削除(全員)
    householdMemberRepository.deleteByHouseholdId(householdId);

    // バッチ削除対象タイマーとして updated_at を更新
    householdRepository.update(household, userId, ProgramType.ONL_HLD.getCode());
  }

  @Transactional
  public void transferOwnership(Long householdId, Long currentUserId, Long newOwnerUserId) {
    HouseholdModel household = householdRepository.findById(householdId);
    if (household == null) {
      throw new ResourceNotFoundException("Household not found: " + householdId);
    }

    if (!household.isOwner(currentUserId)) {
      throw new AccessDeniedException("Only the owner can transfer ownership.");
    }

    // 新しいオーナーが世帯に参加しているかチェック
    List<HouseholdMemberModel> activeMembers =
        householdMemberRepository.findActiveByHouseholdId(householdId);
    boolean isNewOwnerMember =
        activeMembers.stream().anyMatch(m -> m.getUserId().equals(newOwnerUserId));

    if (!isNewOwnerMember) {
      throw new IllegalArgumentException(
          "The new owner must be an active member of the household.");
    }

    household.changeOwner(newOwnerUserId);
    householdRepository.update(household, currentUserId, ProgramType.ONL_HLD.getCode());

    // 通知
    notificationPublisher.publishAssigned2Owner(
        householdId, currentUserId, newOwnerUserId, ProgramType.ONL_HLD.getCode());
  }
}