package com.tasteby.service;

import com.tasteby.domain.Restaurant;
import com.tasteby.domain.Review;
import com.tasteby.mapper.ReviewMapper;
import com.tasteby.util.IdGenerator;
import com.tasteby.util.JsonUtil;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.*;

@Service
public class ReviewService {

    private final ReviewMapper mapper;

    public ReviewService(ReviewMapper mapper) {
        this.mapper = mapper;
    }

    public List<Review> findByRestaurant(String restaurantId, int limit, int offset) {
        return mapper.findByRestaurant(restaurantId, limit, offset);
    }

    public Map<String, Object> getAvgRating(String restaurantId) {
        Map<String, Object> result = mapper.getAvgRating(restaurantId);
        return result != null ? JsonUtil.lowerKeys(result) : Map.of("avg_rating", 0.0, "review_count", 0);
    }

    @Transactional
    public Review create(String userId, String restaurantId, double rating, String reviewText, LocalDate visitedAt) {
        String id = IdGenerator.newId();
        String visitedStr = visitedAt != null ? visitedAt.toString() : null;
        mapper.insertReview(id, userId, restaurantId, rating, reviewText, visitedStr);
        return mapper.findById(id);
    }

    @Transactional   // #334 — 단일 SQL이지만 어노테이션 일관성
    public boolean update(String reviewId, String userId, Double rating, String reviewText, LocalDate visitedAt) {
        String visitedStr = visitedAt != null ? visitedAt.toString() : null;
        return mapper.updateReview(reviewId, userId, rating, reviewText, visitedStr) > 0;
    }

    @Transactional   // #334 — 단일 SQL이지만 어노테이션 일관성
    public boolean delete(String reviewId, String userId) {
        return mapper.deleteReview(reviewId, userId) > 0;
    }

    public List<Review> findByUser(String userId, int limit, int offset) {
        return mapper.findByUser(userId, limit, offset);
    }

    public boolean isFavorited(String userId, String restaurantId) {
        return mapper.countFavorite(userId, restaurantId) > 0;
    }

    @Transactional
    public boolean toggleFavorite(String userId, String restaurantId) {
        String existingId = mapper.findFavoriteId(userId, restaurantId);
        if (existingId != null) {
            mapper.deleteFavorite(userId, restaurantId);
            return false;
        }
        // #294 — 동시성 가드: 동시 INSERT 시 UNIQUE 충돌 → 한 쪽 500.
        // INSERT 시도 후 DuplicateKeyException은 "이미 추가됨"으로 간주 (토글 의도는 ON).
        try {
            mapper.insertFavorite(IdGenerator.newId(), userId, restaurantId);
        } catch (DuplicateKeyException ignored) {
            // 다른 트랜잭션이 먼저 INSERT 함 — 결과는 어쨌든 즐겨찾기 ON.
        }
        return true;
    }

    public List<Restaurant> getUserFavorites(String userId) {
        return mapper.getUserFavorites(userId);
    }
}
