<?php

declare(strict_types=1);

namespace App\Services;

use App\Contracts\Repositories\BookingRepositoryInterface;
use App\Contracts\Repositories\ReviewRepositoryInterface;
use App\Contracts\Services\NotificationServiceInterface;
use App\Contracts\Services\ReviewServiceInterface;
use App\DataTransferObjects\ReviewData;
use App\Models\Review;

final class ReviewService implements ReviewServiceInterface
{
    public function __construct(
        private readonly ReviewRepositoryInterface $reviewRepository,
        private readonly BookingRepositoryInterface $bookingRepository,
        private readonly NotificationServiceInterface $notificationService
    ) {}

    public function createReview(ReviewData $data): Review
    {
        // Validate booking exists and is eligible for review
        $booking = $this->bookingRepository->findById($data->bookingId);

        if (! $booking) {
            throw new \Exception('Booking not found.');
        }

        // Verify guest owns the booking
        if ($booking->guest_id !== $data->guestId) {
            throw new \Exception('You are not authorized to review this booking.');
        }

        // Check if booking can be reviewed
        if (! $booking->canBeReviewed()) {
            throw new \Exception('This booking cannot be reviewed yet or has already been reviewed.');
        }

        // Verify property matches
        if ($booking->property_id !== $data->propertyId) {
            throw new \Exception('Property mismatch.');
        }

        // Create review
        $review = $this->reviewRepository->create([
            'property_id' => $data->propertyId,
            'guest_id' => $data->guestId,
            'booking_id' => $data->bookingId,
            'rating' => $data->rating,
            'cleanliness_rating' => $data->cleanlinessRating,
            'accuracy_rating' => $data->accuracyRating,
            'communication_rating' => $data->communicationRating,
            'location_rating' => $data->locationRating,
            'value_rating' => $data->valueRating,
            'title' => $data->title,
            'comment' => $data->comment,
            'status' => 'pending',
        ]);

        // Send notification to property owner
        $this->notificationService->reviewPosted($review);

        return $review;
    }

    public function addOwnerResponse(int $reviewId, int $ownerId, string $response): bool
    {
        $review = $this->reviewRepository->findById($reviewId);

        if (! $review) {
            throw new \Exception('Review not found.');
        }

        // Verify owner owns the property
        if ($review->property->owner_id !== $ownerId) {
            throw new \Exception('You are not authorized to respond to this review.');
        }

        // Check if already responded
        if ($review->hasOwnerResponse()) {
            throw new \Exception('You have already responded to this review.');
        }

        return $this->reviewRepository->addOwnerResponse($reviewId, $response);
    }

    public function canReview(int $bookingId, int $guestId): bool
    {
        $booking = $this->bookingRepository->findById($bookingId);

        if (! $booking) {
            return false;
        }

        return $booking->guest_id === $guestId && $booking->canBeReviewed();
    }
}
