<?php

namespace App\Http\Controllers\Api\User;

use App\Enums\BookingItemStatus;
use App\Enums\BookingStatus;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Api\Traits\ApiResponse;
use App\Http\Resources\ProductResource;
use App\Http\Resources\ReviewResource;
use App\Models\Product;
use Illuminate\Http\Request;
use OpenApi\Annotations as OA;

class ProductController extends Controller
{
    use ApiResponse;

    /**
     * @OA\Get(
     *     path="/api/user/products",
     *     summary="Get a list of products",
     *     tags={"Products"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\Parameter(
     *         name="type",
     *         in="query",
     *         description="Filter products by type",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Parameter(
     *         name="search",
     *         in="query",
     *         description="Search products by name or description",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Parameter(
     *         name="category_id",
     *         in="query",
     *         description="Filter products by category ID",
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Parameter(
     *         name="city_id",
     *         in="query",
     *         description="Filter products by city ID",
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Parameter(
     *         name="date",
     *         in="query",
     *         description="Filter products by availability date (YYYY-MM-DD)",
     *         @OA\Schema(type="string", format="date")
     *     ),
     *     @OA\Parameter(
     *         name="orderBy",
     *         in="query",
     *         description="Order products by a specific field (e.g., 'created_at', 'avg_rating', 'price')",
     *         @OA\Schema(type="string", enum={"created_at", "avg_rating"})
     *     ),
     *      @OA\Parameter(
     *         name="orderDirection",
     *         in="query",
     *         description="Order direction",
     *         @OA\Schema(type="string", enum={"asc", "desc"}, default="asc")
     *      ),
     *     @OA\Parameter(
     *         name="per_page",
     *         in="query",
     *         description="Number of products per page",
     *         @OA\Schema(type="integer", default=10)
     *     ),
     *     @OA\Parameter(
     *         name="page",
     *         in="query",
     *         description="Current page number",
     *         @OA\Schema(type="integer", default=1)
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Successful operation",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="message", type="string", example="Data retrieved successfully"),
     *             @OA\Property(property="data", type="array", @OA\Items(
     *                  oneOf={
     *                      @OA\Schema(ref="#/components/schemas/ServiceResource"),
     *                      @OA\Schema(ref="#/components/schemas/PackageResource")
     *                  }
     *              ))
     *         )
     *     )
     * )
     */
    public function index(Request $request)
    {
        $orderBy = $request->input('orderBy', 'created_at');
        $orderDirection = $request->input('orderDirection', 'asc');

        $productsQuery = Product::query()
            ->scopes(['available'])
            ->when($request->type, function ($query, $type) {
                $query->where('type', $type);
            })
            ->when($request->search, function ($query, $search) {
                $query->where(function ($q) use ($search) {
                    $q->where('name_en', 'like', "%{$search}%")
                        ->orWhere('name_ar', 'like', "%{$search}%")
                        ->orWhere('description_en', 'like', "%{$search}%")
                        ->orWhere('description_ar', 'like', "%{$search}%");
                });
            })
            ->when($request->category_id, function ($query, $categoryId) {
                $query->where('category_id', $categoryId);
            })
            ->when($request->city_id, function ($query, $cityId) {
                $query->whereHas('cities', function ($q) use ($cityId) {
                    $q->where('city_id', $cityId);
                });
            })
            ->when($request->date, function ($query, $date) {
                $query->whereDoesntHave('availabilities', function ($q) use ($date) {
                    $q->where('date', $date);
                })->whereDoesntHave('bookingItems', function ($q) use ($date) {
                    $q->where('service_date', $date);
                });
            });

        if ($orderBy === 'avg_rating') {
            $productsQuery->withAvg('reviews', 'rating')
                ->orderBy('reviews_avg_rating', $orderDirection);
        } else {
            $productsQuery->orderBy($orderBy, $orderDirection);
        }

        $products = $productsQuery->with(['media', 'category', 'availabilities'])
            ->paginate($request->get('per_page', 10), ['*'], 'page', $request->get('page', 1));

        return $this->successResponse(ProductResource::collection($products), __('messages.products_retrieved_successfully'));
    }

    /**
     * @OA\Get(
     *     path="/api/user/products/{product}",
     *     summary="Get a single product by ID",
     *     tags={"Products"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\Parameter(
     *         name="product",
     *         in="path",
     *         required=true,
     *         description="ID of the product to retrieve",
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Successful operation",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="message", type="string", example="Data retrieved successfully"),
     *             @OA\Property(property="data", type="object", oneOf={
     *                  @OA\Schema(ref="#/components/schemas/ServiceResource"),
     *                  @OA\Schema(ref="#/components/schemas/PackageResource")
     *              })
     *         )
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Product not found",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="success", type="boolean", example=false),
     *             @OA\Property(property="message", type="string", example="Product not found")
     *         )
     *     )
     * )
     */
    public function show(Product $product)
    {
        $product->load('availabilities', 'media', 'serviceProvider', 'category');
        return $this->successResponse(ProductResource::make($product), __('messages.product_retrieved_successfully'));
    }

    /**
     * @OA\Get(
     *     path="/api/user/products/{product}/availabilities",
     *     summary="Get a list of available dates for a product",
     *     tags={"Products"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\Parameter(
     *         name="product",
     *         in="path",
     *         required=true,
     *         description="ID of the product to retrieve availabilities for",
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Successful operation",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="message", type="string", example="Data retrieved successfully"),
     *             @OA\Property(property="data", type="array", @OA\Items(type="string", format="date", example="2023-12-31"))
     *         )
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Product not found",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="success", type="boolean", example=false),
     *             @OA\Property(property="message", type="string", example="Product not found")
     *         )
     *     )
     * )
     */
    public function availabilities(Product $product)
    {
        if (!$product || !$product->is_active) {
            return $this->errorResponse(__('Product not found'), 404);
        }
        $bookings = $product->bookingItems()
            ->where('service_date', '>=', now()->format('Y-m-d'))
            ->whereNot('status', BookingItemStatus::DECLINED)
            ->whereHas("booking", function ($query) {
                $query->whereNot('status', BookingStatus::CANCELED);
            })
            ->pluck('service_date')->map(function ($date) {
                return $date->format('Y-m-d');
            })->toArray();
        $availabilities = $product->availabilities()->where('date', '>=', now()->format('Y-m-d'))->pluck('date')->toArray();

        $allDates = array_unique(array_merge($bookings, $availabilities));
        sort($allDates);

        return $this->successResponse(array_values($allDates), __('messages.availabilities_retrieved_successfully'));
    }

    /**
     * @OA\Get(
     *     path="/api/user/products/{product}/check-availability",
     *     summary="Check availability for a specific date",
     *     tags={"Products"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\Parameter(
     *         name="product",
     *         in="path",
     *         required=true,
     *         description="ID of the product to check availability for",
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Parameter(
     *         name="date",
     *         in="query",
     *         required=true,
     *         description="Date to check availability for (YYYY-MM-DD)",
     *         @OA\Schema(type="string", format="date")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Successful operation",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="message", type="string", example="Date is available"),
     *             @OA\Property(property="data", type="object",
     *                 @OA\Property(property="available", type="boolean", example=true)
     *             )
     *         )
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Product not found",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="success", type="boolean", example=false),
     *             @OA\Property(property="message", type="string", example="Product not found")
     *         )
     *     ),
     *      @OA\Response(
     *         response=422,
     *         description="Validation error",
     *     )
     * )
     */
    public function checkAvailability(Request $request, Product $product)
    {
        $request->validate([
            'date' => 'required|date_format:Y-m-d|afterOrEqual:today',
        ]);

        $date = $request->input('date');

        $isBooked = $product->bookingItems()->where('service_date', $date)->exists();
        $isBlocked = $product->availabilities()->where('date', $date)->exists();

        if ($isBooked || $isBlocked) {
            return $this->successResponse(['available' => false], __('messages.date_is_not_available'));
        }

        return $this->successResponse(['available' => true], __('messages.date_is_available'));
    }

    /**
     * @OA\Get(
     *     path="/api/user/products/{product}/reviews",
     *     summary="Get a list of reviews for a product",
     *     tags={"Products"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\Parameter(
     *         name="product",
     *         in="path",
     *         required=true,
     *         description="ID of the product to retrieve reviews for",
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Successful operation",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="message", type="string", example="Data retrieved successfully"),
     *             @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/ReviewResource"))
     *         )
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Product not found",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="success", type="boolean", example=false),
     *             @OA\Property(property="message", type="string", example="Product not found")
     *         )
     *     )
     * )
     */
    public function reviews(Product $product)
    {
        $reviews = $product->reviews()->with('user')->paginate(10);

        return $this->successResponse(ReviewResource::collection($reviews), __('messages.reviews_fetched_successfully'));
    }
}
