package com.tasteby.controller;

import com.tasteby.domain.Restaurant;
import com.tasteby.domain.Review;
import com.tasteby.security.AuthUtil;
import com.tasteby.service.ReviewService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class ReviewController {

    private final ReviewService reviewService;

    public ReviewController(ReviewService reviewService) {
        this.reviewService = reviewService;
    }

    @GetMapping("/restaurants/{restaurantId}/reviews")
    public Map<String, Object> listRestaurantReviews(
            @PathVariable String restaurantId,
            @RequestParam(defaultValue = "20") int limit,
            @RequestParam(defaultValue = "0") int offset) {
        var reviews = reviewService.findByRestaurant(restaurantId, limit, offset);
        var stats = reviewService.getAvgRating(restaurantId);
        return Map.of("reviews", reviews, "avg_rating", stats.get("avg_rating"),
                "review_count", stats.get("review_count"));
    }

    @PostMapping("/restaurants/{restaurantId}/reviews")
    @ResponseStatus(HttpStatus.CREATED)
    public Review createReview(
            @PathVariable String restaurantId,
            @RequestBody Map<String, Object> body) {
        String userId = AuthUtil.getUserId();
        double rating = requireRating(body.get("rating"));
        String text = (String) body.get("review_text");
        LocalDate visitedAt = body.get("visited_at") != null
                ? LocalDate.parse((String) body.get("visited_at")) : null;
        return reviewService.create(userId, restaurantId, rating, text, visitedAt);
    }

    @PutMapping("/reviews/{reviewId}")
    public Map<String, Object> updateReview(
            @PathVariable String reviewId,
            @RequestBody Map<String, Object> body) {
        String userId = AuthUtil.getUserId();
        Double rating = body.get("rating") != null ? requireRating(body.get("rating")) : null;
        String text = (String) body.get("review_text");
        LocalDate visitedAt = body.get("visited_at") != null
                ? LocalDate.parse((String) body.get("visited_at")) : null;
        if (!reviewService.update(reviewId, userId, rating, text, visitedAt)) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Review not found or not yours");
        }
        return Map.of("ok", true);
    }

    @DeleteMapping("/reviews/{reviewId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteReview(@PathVariable String reviewId) {
        String userId = AuthUtil.getUserId();
        if (!reviewService.delete(reviewId, userId)) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Review not found or not yours");
        }
    }

    @GetMapping("/users/me/reviews")
    public List<Review> myReviews(
            @RequestParam(defaultValue = "20") int limit,
            @RequestParam(defaultValue = "0") int offset) {
        return reviewService.findByUser(AuthUtil.getUserId(), limit, offset);
    }

    // Favorites
    @GetMapping("/restaurants/{restaurantId}/favorite")
    public Map<String, Object> favoriteStatus(@PathVariable String restaurantId) {
        return Map.of("favorited", reviewService.isFavorited(AuthUtil.getUserId(), restaurantId));
    }

    @PostMapping("/restaurants/{restaurantId}/favorite")
    public Map<String, Object> toggleFavorite(@PathVariable String restaurantId) {
        boolean result = reviewService.toggleFavorite(AuthUtil.getUserId(), restaurantId);
        return Map.of("favorited", result);
    }

    @GetMapping("/users/me/favorites")
    public List<Restaurant> myFavorites() {
        return reviewService.getUserFavorites(AuthUtil.getUserId());
    }

    /**
     * #294 — rating 검증: null/비숫자/범위 외 입력은 400.
     */
    private static double requireRating(Object raw) {
        if (!(raw instanceof Number n)) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "rating은 숫자여야 합니다");
        }
        double v = n.doubleValue();
        if (v < 0.0 || v > 5.0 || Double.isNaN(v)) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "rating은 0.0 ~ 5.0 범위여야 합니다");
        }
        return v;
    }
}
