<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\BalanceLog;
use App\Models\District;
use App\Models\Division;
use App\Models\GeneralSetting;
use App\Models\IncomeHistory;
use App\Models\PdCategory;
use App\Models\PdOrder;
use App\Models\Product;
use App\Models\ProductImage;
use App\Models\Upazila;
use App\Models\User;
use App\Models\VendorOrder;
use App\Models\VendorProduct;
use App\Models\VendorProductImage;
use App\Models\VendorProfile;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;

class VendorShipAdminController extends Controller
{
    public function vendors(Request $request)
    {
        $status = strtolower((string) $request->query('status', 'pending'));
        $allowed = ['pending', 'approved', 'rejected', 'all'];
        if (!in_array($status, $allowed, true)) {
            $status = 'pending';
        }

        $q = trim((string) $request->query('q', ''));

        $base = VendorProfile::query()->with('user');

        if ($status !== 'all') {
            $base->where('status', $status);
        }

        if ($q !== '') {
            $base->where(function ($query) use ($q) {
                $query->where('vendor_name', 'like', "%{$q}%")
                    ->orWhere('address', 'like', "%{$q}%")
                    ->orWhereHas('user', function ($uq) use ($q) {
                        $uq->where('name', 'like', "%{$q}%")
                            ->orWhere('mobile', 'like', "%{$q}%")
                            ->orWhere('referral_code', 'like', "%{$q}%");
                    });
            });
        }

        $vendors = $base->orderByDesc('id')->paginate(20)->withQueryString();

        $counts = VendorProfile::selectRaw("
            COUNT(*) as total,
            SUM(CASE WHEN status='pending' THEN 1 ELSE 0 END) as pending,
            SUM(CASE WHEN status='approved' THEN 1 ELSE 0 END) as approved,
            SUM(CASE WHEN status='rejected' THEN 1 ELSE 0 END) as rejected
        ")->first();

        $serviceCharge = max(0, (float) (GeneralSetting::first()?->vendor_service_charge ?? 0));

        return view('admin.vendor_ship.vendors', compact('vendors', 'counts', 'status', 'q', 'serviceCharge'));
    }

    public function vendorsShow(VendorProfile $vendorProfile)
    {
        $vendorProfile->load([
            'user',
            'orders' => function ($q) {
                $q->latest()->limit(10);
            },
            'products' => function ($q) {
                $q->with('category')->latest()->limit(10);
            },
        ]);

        $base = VendorOrder::where('vendor_profile_id', $vendorProfile->id);

        $todayStart = Carbon::today();
        $todayEnd = Carbon::today()->endOfDay();
        $yesterdayStart = Carbon::yesterday()->startOfDay();
        $yesterdayEnd = Carbon::yesterday()->endOfDay();
        $last7Start = Carbon::now()->subDays(6)->startOfDay();
        $last30Start = Carbon::now()->subDays(29)->startOfDay();

        $summary = [
            'today' => (clone $base)->whereBetween('created_at', [$todayStart, $todayEnd])->count(),
            'yesterday' => (clone $base)->whereBetween('created_at', [$yesterdayStart, $yesterdayEnd])->count(),
            'last7' => (clone $base)->where('created_at', '>=', $last7Start)->count(),
            'last30' => (clone $base)->where('created_at', '>=', $last30Start)->count(),
            'total' => (clone $base)->count(),
        ];

        $statusCounts = VendorOrder::where('vendor_profile_id', $vendorProfile->id)
            ->selectRaw("
                SUM(CASE WHEN status='pending' THEN 1 ELSE 0 END) as pending,
                SUM(CASE WHEN status='processing' THEN 1 ELSE 0 END) as processing,
                SUM(CASE WHEN status='delivered' THEN 1 ELSE 0 END) as delivered,
                SUM(CASE WHEN status='cancelled' THEN 1 ELSE 0 END) as cancelled
            ")->first();

        $serviceCharge = max(0, (float) (GeneralSetting::first()?->vendor_service_charge ?? 0));

        return view('admin.vendor_ship.show', compact('vendorProfile', 'summary', 'statusCounts', 'serviceCharge'));
    }

    public function vendorsApprove(VendorProfile $vendorProfile)
    {
        $admin = auth('admin')->user();

        $vendorProfile->status = 'approved';
        $vendorProfile->admin_note = null;
        $vendorProfile->reviewed_by = $admin?->id;
        $vendorProfile->reviewed_at = now();
        $vendorProfile->save();

        return back()->with('success', 'Vendor approved successfully.');
    }

    public function vendorsReject(Request $request, VendorProfile $vendorProfile)
    {
        $admin = auth('admin')->user();
        $note = trim((string) $request->input('admin_note', ''));

        $vendorProfile->status = 'rejected';
        $vendorProfile->admin_note = $note !== '' ? $note : null;
        $vendorProfile->reviewed_by = $admin?->id;
        $vendorProfile->reviewed_at = now();
        $vendorProfile->save();

        return back()->with('success', 'Vendor rejected.');
    }

    public function products(Request $request)
    {
        $status = strtolower((string) $request->query('status', 'pending'));
        $allowed = ['pending', 'approved', 'rejected', 'all'];
        if (!in_array($status, $allowed, true)) {
            $status = 'pending';
        }

        $q = trim((string) $request->query('q', ''));

        $base = VendorProduct::with(['vendorProfile.user', 'category']);

        if ($status !== 'all') {
            $base->where('status', $status);
        }

        if ($q !== '') {
            $base->where(function ($query) use ($q) {
                $query->where('title', 'like', "%{$q}%")
                    ->orWhereHas('vendorProfile', function ($vq) use ($q) {
                        $vq->where('vendor_name', 'like', "%{$q}%")
                            ->orWhereHas('user', function ($uq) use ($q) {
                                $uq->where('name', 'like', "%{$q}%")
                                    ->orWhere('mobile', 'like', "%{$q}%")
                                    ->orWhere('referral_code', 'like', "%{$q}%");
                            });
                    });
            });
        }

        $products = $base->orderByDesc('id')->paginate(20)->withQueryString();

        $counts = VendorProduct::selectRaw("
            COUNT(*) as total,
            SUM(CASE WHEN status='pending' THEN 1 ELSE 0 END) as pending,
            SUM(CASE WHEN status='approved' THEN 1 ELSE 0 END) as approved,
            SUM(CASE WHEN status='rejected' THEN 1 ELSE 0 END) as rejected
        ")->first();

        return view('admin.vendor_ship.products', compact('products', 'counts', 'status', 'q'));
    }

    public function productsEdit(VendorProduct $vendorProduct)
    {
        $vendorProduct->load(['vendorProfile.user', 'images', 'category']);
        $categories = PdCategory::active()->orderBy('name')->get();
        $statuses = ['pending', 'approved', 'rejected'];

        return view('admin.vendor_ship.product_edit', compact('vendorProduct', 'categories', 'statuses'));
    }

    public function productsUpdate(Request $request, VendorProduct $vendorProduct)
    {
        $data = $request->validate([
            'title' => ['required', 'string', 'max:191'],
            'description' => ['nullable', 'string'],
            'pd_category_id' => ['required', 'exists:pd_categories,id'],
            'status' => ['required', 'in:pending,approved,rejected'],
            'admin_price' => ['required', 'numeric', 'min:0'],
            'seller_price' => ['required', 'numeric', 'min:0', 'gte:admin_price'],
            'admin_note' => ['nullable', 'string', 'max:500'],
            'main_image' => ['nullable', 'file', 'mimes:jpg,jpeg,png,webp', 'max:5120'],
            'category_images' => ['nullable', 'array'],
            'category_images.*' => ['nullable', 'file', 'mimes:jpg,jpeg,png,webp', 'max:5120'],
            'remove_gallery_ids' => ['nullable', 'array'],
            'remove_gallery_ids.*' => ['integer'],
        ]);

        DB::beginTransaction();
        try {
            $vp = VendorProduct::with('images')->lockForUpdate()->findOrFail($vendorProduct->id);

            $removeIds = array_map('intval', $data['remove_gallery_ids'] ?? []);
            if (count($removeIds)) {
                $removeImages = $vp->images()->whereIn('id', $removeIds)->get();
                foreach ($removeImages as $img) {
                    $this->deleteImageIfExists($img->image_path);
                    $img->delete();
                }
            }

            $mainImagePath = $vp->main_image;
            if ($request->hasFile('main_image')) {
                $this->deleteImageIfExists($mainImagePath);
                $mainImagePath = $this->uploadImage($request->file('main_image'), false);
            }

            if ($request->hasFile('category_images')) {
                $sort = (int) ($vp->images()->max('sort_order') ?? 0) + 1;
                foreach ($request->file('category_images') as $image) {
                    $path = $this->uploadImage($image, true);
                    VendorProductImage::create([
                        'vendor_product_id' => $vp->id,
                        'image_path' => $path,
                        'sort_order' => $sort++,
                    ]);
                }
            }

            $vp->update([
                'pd_category_id' => (int) $data['pd_category_id'],
                'title' => $data['title'],
                'description' => $data['description'] ?? null,
                'admin_price' => $data['admin_price'],
                'seller_price' => $data['seller_price'],
                'status' => $data['status'],
                'admin_note' => $data['admin_note'] ?? null,
                'main_image' => $mainImagePath,
            ]);

            $this->syncProductFromVendor($vp);

            DB::commit();
        } catch (\Throwable $e) {
            DB::rollBack();
            return back()->withErrors(['error' => $e->getMessage()])->withInput();
        }

        return redirect()->route('admin.vendor-ship.products')->with('success', 'Vendor product updated.');
    }

    public function productsApprove(VendorProduct $vendorProduct)
    {
        $vendorProduct->status = 'approved';
        $vendorProduct->admin_note = null;
        $vendorProduct->save();

        $this->syncProductFromVendor($vendorProduct);

        return back()->with('success', 'Vendor product approved.');
    }

    public function productsReject(Request $request, VendorProduct $vendorProduct)
    {
        $note = trim((string) $request->input('admin_note', ''));

        $vendorProduct->status = 'rejected';
        $vendorProduct->admin_note = $note !== '' ? $note : null;
        $vendorProduct->save();

        Product::where('vendor_product_id', $vendorProduct->id)->update(['status' => 0]);

        return back()->with('success', 'Vendor product rejected.');
    }

    public function productsDestroy(VendorProduct $vendorProduct)
    {
        DB::beginTransaction();
        try {
            $vendorProduct->load('images');

            $synced = Product::where('vendor_product_id', $vendorProduct->id)->first();
            if ($synced) {
                ProductImage::where('product_id', $synced->id)->delete();
                $synced->delete();
            }

            $this->deleteImageIfExists($vendorProduct->main_image);
            foreach ($vendorProduct->images as $img) {
                $this->deleteImageIfExists($img->image_path);
            }

            $vendorProduct->delete();

            DB::commit();
        } catch (\Throwable $e) {
            DB::rollBack();
            return back()->withErrors(['error' => $e->getMessage()]);
        }

        return back()->with('success', 'Vendor product deleted.');
    }

    public function orders(Request $request)
    {
        $status = strtolower((string) $request->query('status', 'all'));
        $allowed = ['all', 'pending', 'processing', 'delivered', 'cancelled'];
        if (!in_array($status, $allowed, true)) {
            $status = 'all';
        }

        $q = trim((string) $request->query('q', ''));

        $base = VendorOrder::with(['vendorProfile.user']);

        if ($q !== '') {
            $base->whereHas('vendorProfile', function ($vq) use ($q) {
                $vq->where('vendor_name', 'like', "%{$q}%")
                    ->orWhereHas('user', function ($uq) use ($q) {
                        $uq->where('name', 'like', "%{$q}%")
                            ->orWhere('mobile', 'like', "%{$q}%")
                            ->orWhere('referral_code', 'like', "%{$q}%");
                    });
            });
        }

        $counts = (clone $base)->selectRaw("
            COUNT(*) as total,
            SUM(CASE WHEN status='pending' THEN 1 ELSE 0 END) as pending,
            SUM(CASE WHEN status='processing' THEN 1 ELSE 0 END) as processing,
            SUM(CASE WHEN status='delivered' THEN 1 ELSE 0 END) as delivered,
            SUM(CASE WHEN status='cancelled' THEN 1 ELSE 0 END) as cancelled
        ")->first();

        if ($status !== 'all') {
            $base->where('status', $status);
        }

        $orders = $base->latest()->paginate(20)->withQueryString();

        $vendorSummary = collect();
        if ($q !== '') {
            $vendorSummary = VendorProfile::query()
                ->where(function ($vq) use ($q) {
                    $vq->where('vendor_name', 'like', "%{$q}%")
                        ->orWhereHas('user', function ($uq) use ($q) {
                            $uq->where('name', 'like', "%{$q}%")
                                ->orWhere('mobile', 'like', "%{$q}%")
                                ->orWhere('referral_code', 'like', "%{$q}%");
                        });
                })
                ->with('user')
                ->withCount('orders')
                ->orderByDesc('orders_count')
                ->limit(50)
                ->get();
        }

        return view('admin.vendor_ship.orders', compact('orders', 'counts', 'status', 'q', 'vendorSummary'));
    }

    public function ordersEdit(VendorOrder $vendorOrder)
    {
        $vendorOrder->load(['pdOrder', 'vendorProfile']);
        $vendors = VendorProfile::orderBy('vendor_name')->get();

        return view('admin.vendor_ship.order_edit', compact('vendorOrder', 'vendors'));
    }

    public function ordersUpdate(Request $request, VendorOrder $vendorOrder)
    {
        $data = $request->validate([
            'vendor_profile_id' => ['required', 'exists:vendor_profiles,id'],
            'status' => ['required', 'in:pending,processing,delivered,cancelled'],
            'qty' => ['required', 'integer', 'min:1'],
            'admin_price' => ['required', 'numeric', 'min:0'],
            'reseller_price' => ['required', 'numeric', 'min:0'],
            'sale_price' => ['required', 'numeric', 'min:0'],
            'size' => ['nullable', 'string', 'max:100'],
            'color' => ['nullable', 'string', 'max:100'],
            'customer_name' => ['nullable', 'string', 'max:191'],
            'customer_phone' => ['nullable', 'string', 'max:30'],
            'alt_phone' => ['nullable', 'string', 'max:30'],
            'address' => ['nullable', 'string', 'max:500'],
            'division' => ['nullable', 'string', 'max:100'],
            'district' => ['nullable', 'string', 'max:100'],
            'thana' => ['nullable', 'string', 'max:100'],
            'tracking_link' => ['nullable', 'url', 'max:1200'],
            'cancel_reason' => ['nullable', 'string', 'max:1000'],
            'admin_action_note' => ['nullable', 'string', 'max:1000'],
        ]);

        if ($data['sale_price'] < $data['admin_price']) {
            return back()->withErrors(['error' => 'Sale price cannot be lower than Admin Price.'])->withInput();
        }

        if ($data['status'] === 'cancelled' && empty(trim((string) ($data['cancel_reason'] ?? '')))) {
            return back()->withErrors(['error' => 'Cancel reason is required for cancelled status.'])->withInput();
        }

        try {
            DB::transaction(function () use ($vendorOrder, $data) {
                $vendorOrder = VendorOrder::with('pdOrder.product')->lockForUpdate()->findOrFail($vendorOrder->id);
                $pdOrder = PdOrder::lockForUpdate()->findOrFail($vendorOrder->pd_order_id);

                $oldPdStatus = (string) ($pdOrder->status ?? '');
                $wasCompleted = $oldPdStatus === 'completed';
                $oldEarnTotal = round((float) $pdOrder->earn_total, 2);

                $qty = (int) $data['qty'];
                $adminPrice = round((float) $data['admin_price'], 2);
                $resellerPrice = round((float) $data['reseller_price'], 2);
                $salePrice = round((float) $data['sale_price'], 2);

                $wholesaleTotal = round($adminPrice * $qty, 2);
                $perEarn = max(0, round($salePrice - $adminPrice, 2));
                $earnTotal = round($perEarn * $qty, 2);
                $grandTotal = round($salePrice * $qty, 2);

                $pdOrder->fill([
                    'qty' => $qty,
                    'admin_price' => $adminPrice,
                    'reseller_price' => $resellerPrice,
                    'sale_price' => $salePrice,
                    'wholesale_total' => $wholesaleTotal,
                    'earn_total' => $earnTotal,
                    'grand_total' => $grandTotal,
                    'size' => $data['size'] ?? $pdOrder->size,
                    'color' => $data['color'] ?? $pdOrder->color,
                    'customer_name' => $data['customer_name'] ?? $pdOrder->customer_name,
                    'customer_phone' => $data['customer_phone'] ?? $pdOrder->customer_phone,
                    'alt_phone' => $data['alt_phone'] ?? $pdOrder->alt_phone,
                    'address' => $data['address'] ?? $pdOrder->address,
                    'division' => $data['division'] ?? $pdOrder->division,
                    'district' => $data['district'] ?? $pdOrder->district,
                    'thana' => $data['thana'] ?? $pdOrder->thana,
                ]);
                $pdOrder->save();

                if ($wasCompleted && $this->hasProfitCreditLog($pdOrder)) {
                    $delta = round($earnTotal - $oldEarnTotal, 2);
                    if (abs($delta) > 0.00001) {
                        $user = User::lockForUpdate()->findOrFail($pdOrder->user_id);
                        $beforeBalance = (float) ($user->balance ?? 0);
                        $afterBalance = round($beforeBalance + $delta, 2);

                        if ($afterBalance < 0) {
                            throw new \RuntimeException('Edit would make user balance negative. Update aborted.');
                        }

                        $user->balance = $afterBalance;
                        $user->save();

                        BalanceLog::create([
                            'user_id' => $user->id,
                            'amount' => $delta,
                        ]);

                        IncomeHistory::create([
                            'user_id' => $user->id,
                            'source' => 'pd_order_adjustment',
                            'amount' => $delta,
                            'description' => 'Order #' . $pdOrder->id . ' profit adjusted. Old: ' .
                                number_format($oldEarnTotal, 2) . ', New: ' . number_format($earnTotal, 2) .
                                ', Delta: ' . ($delta >= 0 ? '+' : '') . number_format($delta, 2) . '.',
                        ]);
                    }
                }

                $newVendorStatus = (string) $data['status'];
                $newPdStatus = match ($newVendorStatus) {
                    'delivered' => 'completed',
                    'cancelled' => 'rejected',
                    default => $newVendorStatus,
                };

                if ($newPdStatus !== $oldPdStatus) {
                    if ($oldPdStatus === 'completed' && $this->hasProfitCreditLog($pdOrder)) {
                        $user = User::lockForUpdate()->findOrFail($pdOrder->user_id);
                        $beforeBalance = (float) ($user->balance ?? 0);
                        $afterBalance = round($beforeBalance - $earnTotal, 2);

                        if ($afterBalance < 0) {
                            throw new \RuntimeException('Balance cannot go negative when reversing profit.');
                        }

                        $user->balance = $afterBalance;
                        $user->save();

                        BalanceLog::create([
                            'user_id' => $user->id,
                            'amount' => -1 * $earnTotal,
                        ]);

                        IncomeHistory::create([
                            'user_id' => $user->id,
                            'source' => 'pd_order_reverse',
                            'amount' => -1 * $earnTotal,
                            'description' => 'Order #' . $pdOrder->id . ' moved out of completed. Profit reversed: ' . number_format($earnTotal, 2) . '.',
                        ]);
                    }

                    if ($newPdStatus === 'completed' && !$this->hasProfitCreditLog($pdOrder)) {
                        $user = User::lockForUpdate()->findOrFail($pdOrder->user_id);
                        $credit = (float) $earnTotal;
                        if ($credit > 0) {
                            $user->balance = (float) ($user->balance ?? 0) + $credit;
                            $user->save();

                            BalanceLog::create([
                                'user_id' => $user->id,
                                'amount' => $credit,
                            ]);

                            $title = optional($pdOrder->product)->title ?? 'Unknown Product';
                            IncomeHistory::create([
                                'user_id' => $user->id,
                                'source' => 'pd_order',
                                'amount' => $credit,
                                'description' => 'Order #' . $pdOrder->id . ' ("' . $title . '") completed. Income added: ' . number_format($credit, 2) . '.',
                            ]);
                        }
                    }

                    $pdOrder->status = $newPdStatus;
                    $pdOrder->save();
                }

                $vendorOrder->vendor_profile_id = (int) $data['vendor_profile_id'];
                $vendorOrder->status = $newVendorStatus;
                $vendorOrder->tracking_link = $data['tracking_link'] ?? null;
                $vendorOrder->total_amount = $grandTotal;

                if ($newVendorStatus === 'cancelled') {
                    $vendorOrder->cancel_reason = trim((string) ($data['cancel_reason'] ?? ''));
                    $vendorOrder->cancellation_requested_at = null;
                    $vendorOrder->cancellation_response = 'approved';
                } else {
                    $vendorOrder->cancel_reason = $data['cancel_reason'] ?? null;
                    $vendorOrder->cancellation_requested_at = null;
                    $vendorOrder->cancellation_response = null;
                }

                $adminNote = trim((string) ($data['admin_action_note'] ?? ''));
                if ($adminNote !== '') {
                    $vendorOrder->admin_action_note = $adminNote;
                }

                if ($vendorOrder->isDirty(['status', 'vendor_profile_id', 'admin_action_note'])) {
                    $vendorOrder->admin_action_at = now();
                }

                $vendorOrder->save();
            });
        } catch (\Throwable $e) {
            return back()->withErrors(['error' => $e->getMessage()])->withInput();
        }

        return back()->with('success', 'Vendor order updated.');
    }

    public function locationDivisions()
    {
        return response()->json(
            Division::orderBy('name')->get(['id', 'name'])
        );
    }

    public function locationDistricts($divisionId)
    {
        return response()->json(
            District::active()
                ->where('division_id', $divisionId)
                ->orderBy('name')
                ->get(['id', 'name'])
        );
    }

    public function locationUpazilas($districtId)
    {
        return response()->json(
            Upazila::active()
                ->where('district_id', $districtId)
                ->orderBy('name')
                ->get(['id', 'name'])
        );
    }

    private function syncProductFromVendor(VendorProduct $vendorProduct): void
    {
        $vendorProduct->loadMissing(['images', 'vendorProfile']);

        $product = Product::firstOrNew(['vendor_product_id' => $vendorProduct->id]);
        if (!$product->exists) {
            $product->slug = $this->uniqueSlug($vendorProduct->title);
        } elseif (!$product->slug) {
            $product->slug = $this->uniqueSlug($vendorProduct->title, $product->id);
        }

        $product->category_id = $vendorProduct->pd_category_id;
        $product->title = $vendorProduct->title;
        $product->description = $vendorProduct->description;
        $product->admin_price = $vendorProduct->admin_price;
        $product->reseller_price = $vendorProduct->seller_price;
        if (!$product->hasConfiguredDeliveryCharges()) {
            $product->delivery_charge = Product::defaultDeliveryChargeForZone(Product::DELIVERY_ZONE_OUT_DHAKA);
            $product->delivery_charge_dhaka_city = Product::defaultDeliveryChargeForZone(Product::DELIVERY_ZONE_DHAKA_CITY);
            $product->delivery_charge_sub_dhaka = Product::defaultDeliveryChargeForZone(Product::DELIVERY_ZONE_SUB_DHAKA);
            $product->delivery_charge_outside_dhaka = Product::defaultDeliveryChargeForZone(Product::DELIVERY_ZONE_OUT_DHAKA);
        } else {
            $legacyDeliveryCharge = round((float) ($product->delivery_charge ?? 0), 2);
            $product->delivery_charge_dhaka_city = $product->delivery_charge_dhaka_city ?? $legacyDeliveryCharge;
            $product->delivery_charge_sub_dhaka = $product->delivery_charge_sub_dhaka ?? $legacyDeliveryCharge;
            $product->delivery_charge_outside_dhaka = $product->delivery_charge_outside_dhaka ?? $legacyDeliveryCharge;
        }
        $product->size = $vendorProduct->sizes_text ?: $vendorProduct->size;
        $product->banner_photo = $vendorProduct->main_image ? ltrim((string) $vendorProduct->main_image, '/') : null;
        $product->status = $vendorProduct->status === 'approved' ? 1 : 0;
        $product->vendor_profile_id = $vendorProduct->vendor_profile_id;
        $product->vendor_product_id = $vendorProduct->id;
        $product->save();

        ProductImage::where('product_id', $product->id)->delete();
        $sort = 0;
        foreach ($vendorProduct->images as $img) {
            ProductImage::create([
                'product_id' => $product->id,
                'photo' => $img->image_path ? ltrim((string) $img->image_path, '/') : null,
                'sort_order' => $sort++,
            ]);
        }
    }

    private function uniqueSlug(string $title, ?int $ignoreId = null): string
    {
        $base = Str::slug($title);
        if ($base === '') {
            $base = 'vendor-product';
        }

        $slug = $base;
        $i = 1;
        while (Product::where('slug', $slug)
            ->when($ignoreId, fn($q) => $q->where('id', '!=', $ignoreId))
            ->exists()
        ) {
            $slug = $base . '-' . $i++;
        }

        return $slug;
    }

    private function hasProfitCreditLog(PdOrder $order): bool
    {
        return IncomeHistory::query()
            ->where('user_id', $order->user_id)
            ->where('source', 'pd_order')
            ->where('description', 'like', 'Order #' . $order->id . ' %')
            ->exists();
    }

    private function uploadImage($file, bool $gallery): string
    {
        $folder = $gallery ? 'images/vendor-ship/products/gallery' : 'images/vendor-ship/products';
        $dir = public_path($folder);
        if (!is_dir($dir)) {
            File::makeDirectory($dir, 0755, true);
        }

        $ext = strtolower($file->getClientOriginalExtension() ?: 'jpg');
        $filename = now()->format('Ymd_His') . '_' . Str::random(8) . '.' . $ext;
        $file->move($dir, $filename);
        optimize_uploaded_image($dir . DIRECTORY_SEPARATOR . $filename);
        $this->mirrorToWebRootIfNeeded($dir . DIRECTORY_SEPARATOR . $filename, $folder . '/' . $filename);

        return '/' . trim($folder, '/') . '/' . $filename;
    }

    private function deleteImageIfExists(?string $path): void
    {
        if (!$path) {
            return;
        }

        $full = public_path(ltrim($path, '/'));
        if (is_file($full)) {
            @unlink($full);
        }

        $docRoot = rtrim($this->detectWebRoot(), '/\\');
        $webAbs = $docRoot . '/' . ltrim($path, '/');
        if (is_file($webAbs) && realpath($webAbs) !== realpath($full)) {
            @unlink($webAbs);
        }
    }

    private function mirrorToWebRootIfNeeded(string $sourceAbsPath, string $relativeTargetPath): void
    {
        if (!is_file($sourceAbsPath)) {
            return;
        }

        $webRoot = rtrim($this->detectWebRoot(), '/\\');
        $targetAbs = $webRoot . '/' . ltrim($relativeTargetPath, '/');
        if (is_file($targetAbs)) {
            return;
        }

        if (!is_dir(dirname($targetAbs))) {
            @mkdir(dirname($targetAbs), 0755, true);
        }
        @copy($sourceAbsPath, $targetAbs);
    }

    private function detectWebRoot(): string
    {
        $candidates = [
            isset($_SERVER['SCRIPT_FILENAME']) ? realpath(dirname((string) $_SERVER['SCRIPT_FILENAME'])) : null,
            realpath($_SERVER['DOCUMENT_ROOT'] ?? '') ?: null,
            is_dir(public_path()) ? public_path() : null,
            is_dir(base_path()) ? base_path() : null,
        ];

        foreach (array_filter($candidates) as $root) {
            if (is_dir($root) && is_writable($root)) {
                return rtrim($root, '/\\');
            }
        }

        return rtrim(public_path(), '/\\');
    }
}
