<?php

namespace App\Services;

use App\Helpers\UrlHelper;
use App\Models\Review;
use App\Models\Property;
use App\Models\User;
use Illuminate\Validation\ValidationException;

class ReviewService
{
    /**
     * Create a new review
     */
    public function createReview(array $data, User $reviewer): Review
    {
        // Validate that reviewer is a tenant
        if ($reviewer->role_type !== 2) { // 2=tenant
            throw ValidationException::withMessages([
                'permission' => ['Only tenants can write reviews.'],
            ]);
        }

        // Check if property exists
        $property = Property::find($data['property_id']);
        if (!$property) {
            throw ValidationException::withMessages([
                'property_id' => ['Property not found.'],
            ]);
        }

        // Check if user has already reviewed this property
        $existingReview = Review::where('property_id', $data['property_id'])
            ->where('reviewer_id', $reviewer->id)
            ->first();

        if ($existingReview) {
            throw ValidationException::withMessages([
                'property_id' => ['You have already reviewed this property.'],
            ]);
        }

        // Validate rating
        if (!in_array($data['rating'], [1, 2, 3, 4, 5])) {
            throw ValidationException::withMessages([
                'rating' => ['Rating must be between 1 and 5.'],
            ]);
        }

        return Review::create([
            'property_id' => $data['property_id'],
            'reviewer_id' => $reviewer->id,
            'rating' => $data['rating'],
            'comment' => $data['comment'] ?? null,
        ]);
    }

    /**
     * Update a review
     */
    public function updateReview(int $reviewId, array $data, User $reviewer): ?Review
    {
        $review = Review::find($reviewId);
        
        if (!$review) {
            return null;
        }

        // Check if user owns this review
        if ($review->reviewer_id !== $reviewer->id) {
            throw ValidationException::withMessages([
                'permission' => ['You can only update your own reviews.'],
            ]);
        }

        // Validate rating if provided
        if (isset($data['rating']) && !in_array($data['rating'], [1, 2, 3, 4, 5])) {
            throw ValidationException::withMessages([
                'rating' => ['Rating must be between 1 and 5.'],
            ]);
        }

        $review->update($data);
        return $review->fresh();
    }

    /**
     * Delete a review
     */
    public function deleteReview(int $reviewId, User $user): bool
    {
        $review = Review::find($reviewId);
        
        if (!$review) {
            return false;
        }

        // Check if user owns this review or is admin
        if ($review->reviewer_id !== $user->id && !$user->hasRole('admin')) {
            throw ValidationException::withMessages([
                'permission' => ['You can only delete your own reviews.'],
            ]);
        }

        return $review->delete();
    }

    /**
     * Get reviews for a property
     */
    public function getPropertyReviews(int $propertyId, array $filters = [], int $perPage = 15): array
    {
        $query = Review::forProperty($propertyId)->with(['reviewer', 'property']);

        // Apply filters
        if (isset($filters['rating'])) {
            $query->withRating($filters['rating']);
        }

        if (isset($filters['recent']) && $filters['recent']) {
            $query->recent($filters['limit'] ?? 10);
        }

        $reviews = $query->paginate($perPage);

        // Format the reviews for response
        $formattedReviews = [];
        foreach ($reviews->items() as $review) {
            $formattedReviews[] = $this->formatReviewForResponse($review);
        }

        return [
            'data' => $formattedReviews,
            'pagination' => [
                'current_page' => $reviews->currentPage(),
                'per_page' => $reviews->perPage(),
                'total' => $reviews->total(),
                'last_page' => $reviews->lastPage(),
                'from' => $reviews->firstItem(),
                'to' => $reviews->lastItem(),
            ],
            'summary' => [
                'average_rating' => Review::forProperty($propertyId)->avg('rating'),
                'total_reviews' => Review::forProperty($propertyId)->count(),
                'rating_breakdown' => $this->getRatingBreakdown($propertyId),
            ]
        ];
    }

    /**
     * Get user's reviews
     */
    public function getUserReviews(int $userId, array $filters = [], int $perPage = 15): array
    {
        $query = Review::byReviewer($userId)->with(['property']);

        // Apply filters
        if (isset($filters['recent']) && $filters['recent']) {
            $query->recent($filters['limit'] ?? 10);
        }

        $reviews = $query->paginate($perPage);

        // Format the reviews for response
        $formattedReviews = [];
        foreach ($reviews->items() as $review) {
            $formattedReviews[] = $this->formatReviewForResponse($review);
        }

        return [
            'data' => $formattedReviews,
            'pagination' => [
                'current_page' => $reviews->currentPage(),
                'per_page' => $reviews->perPage(),
                'total' => $reviews->total(),
                'last_page' => $reviews->lastPage(),
                'from' => $reviews->firstItem(),
                'to' => $reviews->lastItem(),
            ]
        ];
    }

    /**
     * Get rating breakdown for a property
     */
    private function getRatingBreakdown(int $propertyId): array
    {
        $breakdown = [];
        for ($rating = 1; $rating <= 5; $rating++) {
            $count = Review::forProperty($propertyId)->withRating($rating)->count();
            $breakdown[$rating] = $count;
        }
        return $breakdown;
    }

    /**
     * Get review statistics
     */
    public function getReviewStatistics(int $propertyId): array
    {
        $reviews = Review::forProperty($propertyId);
        
        // Format recent reviews
        $recentReviews = $reviews->recent(5)->get();
        $formattedRecentReviews = [];
        foreach ($recentReviews as $review) {
            $formattedRecentReviews[] = $this->formatReviewForResponse($review);
        }
        
        return [
            'total_reviews' => $reviews->count(),
            'average_rating' => round($reviews->avg('rating') ?? 0, 2),
            'rating_breakdown' => $this->getRatingBreakdown($propertyId),
            'recent_reviews' => $formattedRecentReviews,
        ];
    }

    /**
     * Format review for API response
     */
    public function formatReviewForResponse(Review $review): array
    {
        return [
            'id' => $review->id,
            'property_id' => $review->property_id,
            'reviewer' => [
                'id' => $review->reviewer->id,
                'name' => $review->reviewer->name,
                'profile_photo' => UrlHelper::toFullUrl($review->reviewer->profile_photo),
            ],
            'rating' => $review->rating,
            'comment' => $review->comment,
            'created_at' => $review->created_at,
            'updated_at' => $review->updated_at,
        ];
    }
}
