<?php

namespace Database\Seeders;

use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Product;
use App\Models\Rating;
use App\Models\User;
use App\Models\Vendor;
use Illuminate\Database\Seeder;

/**
 * Gives each vendor a realistic body of reviews. Each review needs its own
 * delivered order (ratings are unique per user+order+vendor and order_id is
 * required), so this back-fills lightweight delivered orders + items, then
 * reconciles each vendor's rating_average / rating_count from actual ratings.
 */
class VendorReviewDemoSeeder extends Seeder
{
    private array $positive = [
        'Great service, highly recommended', 'Fast delivery to my doorstep', 'Excellent quality products',
        'Will definitely order again', 'Genuine products at fair prices', 'Best shop in Malakand',
        'Very satisfied with my order', 'Neatly packed and on time', 'Prompt and helpful response',
        'Exactly as described', 'Smooth experience overall', 'Reasonable prices and quick delivery',
    ];
    private array $neutral = [
        'Okay experience overall', 'Product was fine, delivery a bit slow', 'Average, could be improved',
        'Decent but packaging could be better',
    ];
    private array $negative = [
        'Delivery was later than expected', 'Not quite what I expected', 'Packaging needs improvement',
    ];

    public function run(): void
    {
        $customers = User::pluck('id')->all();
        if (empty($customers)) {
            $this->command?->warn('No customers to attribute reviews to — skipping.');
            return;
        }

        $seq = (int) Order::max('id') + 1000;
        $made = 0;

        foreach (Vendor::all() as $vendor) {
            $products = Product::where('vendor_id', $vendor->id)->get(['id', 'name_en', 'price', 'discount_price']);
            if ($products->isEmpty()) {
                continue;
            }

            $existing = Rating::where('rateable_type', Vendor::class)->where('rateable_id', $vendor->id)->count();
            $target   = random_int(8, 26);

            for ($i = $existing; $i < $target; $i++) {
                $uid       = $customers[array_rand($customers)];
                $createdAt = now()->subDays(random_int(2, 220))->subHours(random_int(0, 23));
                $product   = $products->random();
                $qty       = random_int(1, 3);
                $unit      = (float) ($product->discount_price ?? $product->price);
                $subtotal  = $unit * $qty;
                $commission = round($subtotal * $vendor->commission_rate / 100, 2);
                $seq++;

                $order = Order::create([
                    'order_number'       => 'MLK-' . $createdAt->format('Ymd') . '-R' . str_pad((string) $seq, 5, '0', STR_PAD_LEFT),
                    'user_id'            => $uid,
                    'address_id'         => \App\Models\Address::where('user_id', $uid)->value('id'),
                    'delivery_address'   => 'House ' . random_int(1, 99),
                    'delivery_locality'  => $vendor->locality,
                    'payment_method'     => 'cod',
                    'payment_status'     => 'paid',
                    'items_total'        => $subtotal,
                    'delivery_fee_total' => 100,
                    'grand_total'        => $subtotal + 100,
                    'status'             => 'delivered',
                    'delivered_at'       => $createdAt->copy()->addHours(random_int(1, 6)),
                    'created_at'         => $createdAt,
                    'updated_at'         => $createdAt,
                ]);

                OrderItem::create([
                    'order_id'          => $order->id,
                    'vendor_id'         => $vendor->id,
                    'product_id'        => $product->id,
                    'product_name'      => $product->name_en,
                    'vendor_name'       => $vendor->store_name,
                    'quantity'          => $qty,
                    'unit_price'        => $unit,
                    'subtotal'          => $subtotal,
                    'delivery_fee'      => 100,
                    'commission_rate'   => $vendor->commission_rate,
                    'commission_amount' => $commission,
                    'vendor_earning'    => round($subtotal - $commission, 2),
                    'status'            => 'delivered',
                    'created_at'        => $createdAt,
                    'updated_at'        => $createdAt,
                ]);

                $stars   = $this->weightedStars();
                $comment = $this->commentFor($stars);

                Rating::create([
                    'user_id'              => $uid,
                    'order_id'             => $order->id,
                    'rateable_type'        => Vendor::class,
                    'rateable_id'          => $vendor->id,
                    'stars'                => $stars,
                    'comment'              => $comment,
                    'is_verified_purchase' => true,
                    'created_at'           => $createdAt,
                    'updated_at'           => $createdAt,
                ]);
                $made++;
            }

            $agg = Rating::where('rateable_type', Vendor::class)->where('rateable_id', $vendor->id)
                ->selectRaw('AVG(stars) a, COUNT(*) c')->first();
            $vendor->update([
                'rating_average' => round((float) $agg->a, 1),
                'rating_count'   => (int) $agg->c,
            ]);
        }

        $this->command?->info("Seeded {$made} vendor reviews; vendor rating columns reconciled.");
    }

    private function weightedStars(): int
    {
        $r = random_int(1, 100);
        return $r <= 55 ? 5 : ($r <= 80 ? 4 : ($r <= 92 ? 3 : ($r <= 97 ? 2 : 1)));
    }

    private function commentFor(int $stars): ?string
    {
        if (random_int(0, 100) < 25) {
            return null; // some ratings have no written comment
        }
        $pool = $stars >= 4 ? $this->positive : ($stars === 3 ? $this->neutral : $this->negative);
        return $pool[array_rand($pool)];
    }
}
