<?php

namespace App\Http\Controllers\Api\Customer;

use App\Http\Controllers\Controller;
use App\Models\DeliveryPartner;
use App\Models\Order;
use App\Models\Product;
use App\Models\Rating;
use App\Models\Vendor;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class RatingController extends Controller
{
    /**
     * POST /api/customer/orders/{order}/rate
     * Customer rates vendor(s) and/or delivery partner after delivery.
     * Body: { vendor_ratings: [{vendor_id, stars, comment?}], delivery_rating: {partner_id, stars, comment?} }
     */
    public function rate(Request $request, Order $order): JsonResponse
    {
        $this->authorizeOwn($order);

        abort_unless($order->status === 'delivered', 422, 'You can only rate delivered orders.');

        $request->validate([
            'vendor_ratings'              => 'nullable|array',
            'vendor_ratings.*.vendor_id'  => 'required|exists:vendors,id',
            'vendor_ratings.*.stars'      => 'required|integer|between:1,5',
            'vendor_ratings.*.comment'    => 'nullable|string|max:500',

            'delivery_rating'             => 'nullable|array',
            'delivery_rating.partner_id'  => 'required_with:delivery_rating|exists:delivery_partners,id',
            'delivery_rating.stars'       => 'required_with:delivery_rating|integer|between:1,5',
            'delivery_rating.comment'     => 'nullable|string|max:500',

            'product_ratings'             => 'nullable|array',
            'product_ratings.*.product_id'=> 'required|exists:products,id',
            'product_ratings.*.stars'     => 'required|integer|between:1,5',
            'product_ratings.*.comment'   => 'nullable|string|max:500',
        ]);

        $userId = Auth::guard('customer')->id();

        DB::transaction(function () use ($request, $order, $userId) {
            foreach ($request->input('vendor_ratings', []) as $vr) {
                // Customer must have actually bought from this vendor in this order
                if (! $order->items()->where('vendor_id', $vr['vendor_id'])->exists()) {
                    continue;
                }

                $rating = Rating::updateOrCreate(
                    [
                        'user_id'       => $userId,
                        'order_id'      => $order->id,
                        'rateable_type' => Vendor::class,
                        'rateable_id'   => $vr['vendor_id'],
                    ],
                    [
                        'stars'                => $vr['stars'],
                        'comment'              => $vr['comment'] ?? null,
                        'is_verified_purchase' => true,
                    ]
                );

                $this->refreshRateableAggregate(Vendor::class, $vr['vendor_id']);
            }

            foreach ($request->input('product_ratings', []) as $pr) {
                // Customer must have actually purchased this product in this order.
                if (! $order->items()->where('product_id', $pr['product_id'])->exists()) {
                    continue;
                }

                Rating::updateOrCreate(
                    [
                        'user_id'       => $userId,
                        'order_id'      => $order->id,
                        'rateable_type' => Product::class,
                        'rateable_id'   => $pr['product_id'],
                    ],
                    [
                        'stars'                => $pr['stars'],
                        'comment'              => $pr['comment'] ?? null,
                        'is_verified_purchase' => true,
                    ]
                );

                $this->refreshRateableAggregate(Product::class, $pr['product_id']);
            }

            if ($dr = $request->input('delivery_rating')) {
                // Must have actually been delivered by this partner
                if ($order->deliveryAssignments()->where('delivery_partner_id', $dr['partner_id'])->exists()) {
                    Rating::updateOrCreate(
                        [
                            'user_id'       => $userId,
                            'order_id'      => $order->id,
                            'rateable_type' => DeliveryPartner::class,
                            'rateable_id'   => $dr['partner_id'],
                        ],
                        [
                            'stars'                => $dr['stars'],
                            'comment'              => $dr['comment'] ?? null,
                            'is_verified_purchase' => true,
                        ]
                    );
                    $this->refreshRateableAggregate(DeliveryPartner::class, $dr['partner_id']);
                }
            }
        });

        return response()->json(['message' => 'Thanks for your feedback!']);
    }

    /**
     * Recompute average + count on the vendor/partner record.
     */
    private function refreshRateableAggregate(string $class, int $id): void
    {
        $stats = Rating::where('rateable_type', $class)
            ->where('rateable_id', $id)
            ->where('is_hidden', false)
            ->selectRaw('AVG(stars) AS avg, COUNT(*) AS cnt')
            ->first();

        $class::where('id', $id)->update([
            'rating_average' => round((float) $stats->avg, 2),
            'rating_count'   => (int) $stats->cnt,
        ]);
    }

    private function authorizeOwn(Order $order): void
    {
        abort_unless(
            $order->user_id === Auth::guard('customer')->id(),
            403,
            'You do not own this order.'
        );
    }
}
