<?php

namespace App\Http\Controllers\Api;

use App\Events\ReviewCreated;
use App\Events\ReviewDeleted;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreReviewRequest;
use App\Http\Requests\UpdateReviewRequest;
use App\Models\Product;
use App\Models\ProductReview;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ProductReviewController extends Controller
{
    /**
     * Get paginated reviews for a product.
     */
    public function index(Request $request, $productId): JsonResponse
    {
        $product = Product::findOrFail($productId);

        $perPage = $request->get('per_page', 10);
        $reviews = $product->approvedReviews()
            ->with(['user:id,name'])
            ->orderBy('created_at', 'desc')
            ->paginate($perPage);

        return response()->json([
            'success' => true,
            'data' => $reviews->items(),
            'meta' => [
                'current_page' => $reviews->currentPage(),
                'last_page' => $reviews->lastPage(),
                'per_page' => $reviews->perPage(),
                'total' => $reviews->total(),
            ],
        ]);
    }

    /**
     * Create a new review.
     */
    public function store(StoreReviewRequest $request, $productId): JsonResponse
    {
        $product = Product::findOrFail($productId);
        $user = auth()->user();

        // Check rate limiting (1 review per product per user per X days)
        if ($user) {
            $rateLimitDays = config('reviews.rate_limit_days', 30);
            $recentReview = ProductReview::where('product_id', $productId)
                ->where('user_id', $user->id)
                ->where('created_at', '>=', Carbon::now()->subDays($rateLimitDays))
                ->first();

            if ($recentReview) {
                return response()->json([
                    'success' => false,
                    'message' => "You have already reviewed this product. Please wait {$rateLimitDays} days before submitting another review.",
                ], 429);
            }
        } else {
            // For guest reviews, check by IP address
            $rateLimitDays = config('reviews.rate_limit_days', 30);
            $ipAddress = $request->ip();
            $recentReview = ProductReview::where('product_id', $productId)
                ->where('ip_address', $ipAddress)
                ->where('created_at', '>=', Carbon::now()->subDays($rateLimitDays))
                ->first();

            if ($recentReview) {
                return response()->json([
                    'success' => false,
                    'message' => "You have already reviewed this product. Please wait {$rateLimitDays} days before submitting another review.",
                ], 429);
            }
        }

        // Determine if review should be auto-approved
        $isApproved = !config('reviews.require_approval', true);

        try {
            DB::beginTransaction();

            $review = ProductReview::create([
                'product_id' => $productId,
                'user_id' => $user?->id,
                'order_id' => $request->input('order_id'),
                'rating' => $request->input('rating'),
                'title' => $request->input('title'),
                'body' => $request->input('body'),
                'is_approved' => $isApproved,
                'ip_address' => $request->ip(),
                'user_agent' => $request->userAgent(),
            ]);

            // If auto-approved, recalculate rating immediately
            if ($isApproved) {
                $product->recalculateRating();
            }

            DB::commit();

            // Fire event
            event(new ReviewCreated($review));

            return response()->json([
                'success' => true,
                'message' => $isApproved 
                    ? 'Review submitted successfully.' 
                    : 'Review submitted successfully. It will be visible after admin approval.',
                'data' => $review->load('user:id,name'),
            ], 201);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to create review: ' . $e->getMessage());

            return response()->json([
                'success' => false,
                'message' => 'Failed to submit review. Please try again.',
            ], 500);
        }
    }

    /**
     * Update a review.
     */
    public function update(UpdateReviewRequest $request, $id): JsonResponse
    {
        $review = ProductReview::findOrFail($id);

        try {
            DB::beginTransaction();

            $review->update([
                'rating' => $request->input('rating'),
                'title' => $request->input('title'),
                'body' => $request->input('body'),
            ]);

            // Recalculate rating if review is approved
            if ($review->is_approved) {
                $review->product->recalculateRating();
            }

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Review updated successfully.',
                'data' => $review->load('user:id,name'),
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to update review: ' . $e->getMessage());

            return response()->json([
                'success' => false,
                'message' => 'Failed to update review. Please try again.',
            ], 500);
        }
    }

    /**
     * Delete a review.
     */
    public function destroy($id): JsonResponse
    {
        $review = ProductReview::findOrFail($id);
        $user = auth()->user();

        // Check authorization
        if (!$user || (!$review->isAuthor($user) && !$user->isAdmin() && !$user->isStaff())) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized to delete this review.',
            ], 403);
        }

        try {
            DB::beginTransaction();

            $productId = $review->product_id;
            $review->delete();

            // Recalculate rating
            $product = Product::find($productId);
            if ($product) {
                $product->recalculateRating();
            }

            DB::commit();

            // Fire event
            event(new ReviewDeleted($review));

            return response()->json([
                'success' => true,
                'message' => 'Review deleted successfully.',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to delete review: ' . $e->getMessage());

            return response()->json([
                'success' => false,
                'message' => 'Failed to delete review. Please try again.',
            ], 500);
        }
    }

    /**
     * Mark a review as helpful.
     */
    public function markHelpful(Request $request, $id): JsonResponse
    {
        $review = ProductReview::approved()->findOrFail($id);

        $review->markAsHelpful();

        return response()->json([
            'success' => true,
            'message' => 'Review marked as helpful.',
            'data' => [
                'helpful_count' => $review->helpful_count,
            ],
        ]);
    }
}
