<?php

namespace App\Services\Master;

use App\Enums\OwnerVerificationAction;
use App\Enums\OwnerVerificationStatus;
use App\Enums\Permission;
use App\Enums\ProductStatus;
use App\Models\Category;
use App\Models\OwnerVerificationRequest;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\User;
use App\Services\Concerns\CachesQuery;
use App\Services\Concerns\RunsInTransaction;
use App\Services\Media\MediaService;
use App\Services\System\PushNotificationService;
use App\Support\Media\MediaPresenter;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Validation\ValidationException;

class ProductService
{
    use CachesQuery, RunsInTransaction;

    private const MAX_VARIANT_IMAGES = 5;

    public function __construct(
        private readonly MediaService $mediaService,
        private readonly PushNotificationService $pushNotificationService,
    ) {}

    public function paginateForIndex(array $tableQuery, string $status, string $categoryId = '', string $stockStatus = '', string $productId = ''): LengthAwarePaginator
    {
        $query = Product::query()
            ->with([
                'categories',
                'pendingOwnerVerificationRequest.submittedBy.profile',
                'variants' => fn ($query) => $query
                    ->with(['media', 'prices' => fn ($query) => $query->orderBy('type')])
                    ->orderBy('created_at')
                    ->when($tableQuery['search'] !== '', function ($query) use ($tableQuery): void {
                        $query->where('name', 'like', "%{$tableQuery['search']}%");
                    }),
            ])
            ->when(($tableQuery['search_id'] ?? '') !== '', function (Builder $query) use ($tableQuery): void {
                $query->where('products.id', $tableQuery['search_id']);
            })
            ->when(($tableQuery['search_id'] ?? '') === '' && $tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
                $search = $tableQuery['search'];
                $query->where(function (Builder $q) use ($search): void {
                    $q->where('products.name', 'like', "%{$search}%")
                        ->orWhereHas('variants', fn (Builder $q) => $q->where('name', 'like', "%{$search}%"));
                });
            })
            ->when($productId !== '', fn (Builder $query) => $query->where('products.id', $productId))
            ->when($status !== '', fn (Builder $query) => $query->where('status', $status))
            ->when($categoryId !== '', function (Builder $query) use ($categoryId): void {
                $query->whereHas('categories', fn (Builder $query) => $query->where('categories.id', $categoryId));
            })
            ->when($stockStatus === 'out_of_stock', function (Builder $query): void {
                $query->whereHas('variants', fn (Builder $variantQuery) => $variantQuery->where('stock', '<=', 0));
            })
            ->when($stockStatus === 'low_stock', function (Builder $query): void {
                $query->whereHas('variants', fn (Builder $variantQuery) => $variantQuery->where('stock', '>', 0)->where('stock', '<', ProductVariant::minStock()));
            });

        $this->applySorting($query, $tableQuery['sort'], $tableQuery['direction']);

        return $query
            ->paginate(25)
            ->withQueryString()
            ->through(function (Product $product) {
                $product->variants->each(function (ProductVariant $variant): void {
                    $variant->setAttribute(
                        'images',
                        MediaPresenter::collection($variant, 'images'),
                    );
                });

                $pendingRequest = $product->pendingOwnerVerificationRequest;

                // Also check for pending retail stock transfer on variants
                if ($pendingRequest === null) {
                    $pendingRequest = OwnerVerificationRequest::query()
                        ->where('subject_type', ProductVariant::class)
                        ->whereIn('subject_id', $product->variants->pluck('id'))
                        ->where('action', OwnerVerificationAction::RETAIL_STOCK_TRANSFER)
                        ->pending()
                        ->latest()
                        ->first();
                }

                $product->setAttribute('has_pending_request', $pendingRequest !== null);
                $product->setAttribute('pending_request_id', $pendingRequest?->id);
                $product->setAttribute('pending_request_action', $pendingRequest?->action->value);
                $product->setAttribute('pending_request_action_label', $pendingRequest?->action->label());
                $product->setAttribute('pending_request_submitted_by_name', $pendingRequest?->submittedBy?->profile?->full_name ?? $pendingRequest?->submittedBy?->username);
                $product->setAttribute(
                    'display_status',
                    $pendingRequest?->pendingToggleStatus() ?? $product->status->value,
                );

                return $product;
            });
    }

    public function findForEdit(Product $product): Product
    {
        $product->load([
            'categories',
            'variants' => fn ($query) => $query
                ->with(['media', 'prices'])
                ->orderBy('created_at'),
        ]);

        $product->variants->each(function (ProductVariant $variant): void {
            $variant->setAttribute('images', MediaPresenter::collection($variant, 'images'));
        });

        return $product;
    }

    public function create(array $validated, User $user): void
    {
        $isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
        $isDraft = ($validated['status'] ?? '') === ProductStatus::DRAFT->value;

        $product = $this->runInTransaction(
            function () use ($validated, $user, $isOwner, $isDraft): Product {
                $product = Product::create([
                    'name' => $validated['name'],
                    'description' => $validated['description'] ?? null,
                    'status' => $isDraft ? ProductStatus::DRAFT : ($isOwner ? ProductStatus::ACTIVE : ProductStatus::INACTIVE),
                ]);

                $product->categories()->sync($validated['category_ids'] ?? []);

                foreach ($validated['variants'] as $index => $variantData) {
                    $variant = $product->variants()->create([
                        'name' => $variantData['name'],
                        'stock' => $variantData['stock'],
                        'retail_stock' => $variantData['retail_stock'],
                    ]);

                    $this->syncVariantImages($variant, $variantData, $index);

                    if (! empty($variantData['prices'])) {
                        foreach ($variantData['prices'] as $type => $priceValue) {
                            $variant->prices()->create([
                                'type' => $type,
                                'price' => $priceValue,
                            ]);
                        }
                    }
                }

                if (! $isOwner && ! $isDraft) {
                    OwnerVerificationRequest::create([
                        'action' => OwnerVerificationAction::CREATE,
                        'status' => OwnerVerificationStatus::PENDING,
                        'subject_type' => Product::class,
                        'subject_id' => $product->id,
                        'submitted_by_id' => $user->id,
                        'payload' => [
                            'old' => null,
                            'new' => $this->snapshotProduct($product->fresh(['categories', 'variants'])),
                        ],
                    ]);
                }

                return $product;
            },
            'Gagal membuat produk',
        );

        if ($isDraft) {
            $this->notifyOwner(
                'Simpan Draft Produk',
                "Produk '{$validated['name']}' disimpan sebagai draft oleh {$user->profile?->full_name}.",
                route('admin.master.products.index'),
            );

            return;
        }

        if ($isOwner) {
            $this->cacheForgetByPattern('master:products:*');

            $this->notifyOwner(
                'Tambah Produk',
                "Produk '{$validated['name']}' telah ditambahkan oleh {$user->profile?->full_name}.",
                route('admin.master.products.index', ['search_id' => $product->id]),
            );
        }

        if (! $isOwner) {
            $this->notifyForPendingRequest(
                $user,
                'Tambah Produk',
                "Pengajuan tambah produk '{$validated['name']}' oleh {$user->profile?->full_name} menunggu verifikasi owner.",
                route('admin.master.products.index', ['search_id' => $product->id]),
                (string) $product->id,
            );
        }
    }

    public function update(Product $product, array $validated, User $user): void
    {
        $isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
        $isDraft = $product->status === ProductStatus::DRAFT;
        $changingToActive = ($validated['status'] ?? '') === ProductStatus::ACTIVE->value;
        $canEditDirectly = $isOwner || ($isDraft && ! $changingToActive);

        $this->runInTransaction(
            function () use ($validated, $product, $user, $canEditDirectly): void {

                if ($canEditDirectly) {
                    $payload = $this->enrichPayload($this->buildPayloadFromValidated($validated));
                    $this->applyPayloadToProduct($product, $payload);

                    foreach ($validated['variants'] as $index => $variantData) {
                        if (! empty($variantData['id'])) {
                            $variant = $product->variants()->find($variantData['id']);
                            if ($variant) {
                                $this->syncVariantImages($variant, $variantData, $index);
                                if (! empty($variantData['prices'])) {
                                    foreach ($variantData['prices'] as $type => $priceValue) {
                                        $variant->prices()->updateOrCreate(
                                            ['type' => $type],
                                            ['price' => $priceValue]
                                        );
                                    }
                                }
                            }
                        } else {
                            $variant = $product->variants()->create([
                                'name' => $variantData['name'],
                                'stock' => $variantData['stock'],
                                'retail_stock' => $variantData['retail_stock'],
                            ]);
                            $this->syncVariantImages($variant, $variantData, $index);
                            if (! empty($variantData['prices'])) {
                                foreach ($variantData['prices'] as $type => $priceValue) {
                                    $variant->prices()->create([
                                        'type' => $type,
                                        'price' => $priceValue,
                                    ]);
                                }
                            }
                        }
                    }
                } else {
                    $verificationRequest = OwnerVerificationRequest::create([
                        'action' => OwnerVerificationAction::UPDATE,
                        'status' => OwnerVerificationStatus::PENDING,
                        'subject_type' => Product::class,
                        'subject_id' => $product->id,
                        'submitted_by_id' => $user->id,
                        'payload' => [
                            'old' => $this->snapshotProduct($product),
                            'new' => $this->enrichPayload($this->buildPayloadFromValidated($validated)),
                        ],
                    ]);

                    foreach ($validated['variants'] as $index => $variantData) {
                        $isNewVariant = empty($variantData['id']);
                        $this->syncRequestVariantImages($verificationRequest, $variantData, $index, required: $isNewVariant);
                    }
                }
            },
            'Gagal memperbarui produk',
        );

        if ($canEditDirectly) {
            $this->cacheForgetByPattern('master:products:*');
            $this->cacheForgetByPattern('prices:*');
            $this->cacheForget('homepage:page_data');

            $actionLabel = $isDraft && $changingToActive
                ? 'Publikasi Draft Produk'
                : 'Ubah Produk';

            $this->notifyOwner(
                $actionLabel,
                "Produk '{$product->name}' telah diperbarui oleh {$user->profile?->full_name}.",
                route('admin.master.products.index', ['search_id' => $product->id]),
            );

            return;
        }

        $this->cacheForgetByPattern('master:products:*');
        $this->cacheForgetByPattern('prices:*');
        $this->cacheForget('homepage:page_data');

        if ($isOwner) {
            $this->notifyOwner(
                'Ubah Produk',
                "Produk '{$product->name}' telah diperbarui oleh {$user->profile?->full_name}.",
                route('admin.master.products.index', ['search_id' => $product->id]),
            );
        }

        if (! $isOwner) {
            $changedVariants = [];
            foreach ($validated['variants'] as $variantData) {
                if (! empty($variantData['id'])) {
                    $originalVariant = $product->variants->firstWhere('id', $variantData['id']);
                    if ($originalVariant) {
                        $isChanged = false;
                        if ($originalVariant->name !== $variantData['name']) {
                            $isChanged = true;
                        }
                        if (rtrim(rtrim(number_format((float) $originalVariant->stock, 4, '.', ''), '0'), '.') !== rtrim(rtrim(number_format((float) $variantData['stock'], 4, '.', ''), '0'), '.')) {
                            $isChanged = true;
                        }
                        if (rtrim(rtrim(number_format((float) $originalVariant->retail_stock, 4, '.', ''), '0'), '.') !== rtrim(rtrim(number_format((float) $variantData['retail_stock'], 4, '.', ''), '0'), '.')) {
                            $isChanged = true;
                        }
                        if (! empty($variantData['prices'])) {
                            foreach ($variantData['prices'] as $type => $priceValue) {
                                $originalPrice = $originalVariant->prices->firstWhere('type', $type);
                                if (! $originalPrice || $originalPrice->price !== (int) $priceValue) {
                                    $isChanged = true;
                                    break;
                                }
                            }
                        }

                        if ($isChanged) {
                            $changedVariants[] = $variantData['name'];
                        }
                    }
                } else {
                    $changedVariants[] = $variantData['name'];
                }
            }

            if (! empty($changedVariants)) {
                $variantsStr = implode(', ', $changedVariants);
                $this->notifyForPendingRequest(
                    $user,
                    'Ubah Varian Produk',
                    "Pengajuan ubah varian '{$variantsStr}' pada produk '{$product->name}' oleh {$user->profile?->full_name} menunggu verifikasi owner.",
                    route('admin.master.products.index', ['search_id' => $product->id]),
                    (string) $product->id,
                );
            } else {
                $this->notifyForPendingRequest(
                    $user,
                    'Ubah Produk',
                    "Pengajuan ubah produk '{$product->name}' oleh {$user->profile?->full_name} menunggu verifikasi owner.",
                    route('admin.master.products.index', ['search_id' => $product->id]),
                    (string) $product->id,
                );
            }
        }
    }

    public function delete(Product $product, User $user): void
    {
        $isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);

        if ($isOwner) {
            $name = $product->name;
            $this->applyDeleteSubject($product);
            $this->cacheForgetByPattern('master:products:*');
            $this->cacheForgetByPattern('prices:*');
            $this->cacheForget('homepage:page_data');

            $this->notifyOwner(
                'Hapus Produk',
                "Produk '{$name}' telah dihapus oleh {$user->profile?->full_name}.",
                route('admin.master.products.index'),
            );

            return;
        }

        $this->runInTransaction(
            function () use ($product, $user): void {
                OwnerVerificationRequest::create([
                    'action' => OwnerVerificationAction::DELETE,
                    'status' => OwnerVerificationStatus::PENDING,
                    'subject_type' => Product::class,
                    'subject_id' => $product->id,
                    'submitted_by_id' => $user->id,
                    'payload' => [
                        'old' => $this->snapshotProduct($product),
                        'new' => null,
                    ],
                ]);
            },
            'Gagal mengajukan penghapusan produk',
        );

        $this->notifyForPendingRequest(
            $user,
            'Hapus Produk',
            "Pengajuan hapus produk '{$product->name}' oleh {$user->profile?->full_name} menunggu verifikasi owner.",
            route('admin.master.products.index', ['search_id' => $product->id]),
            (string) $product->id,
        );
    }

    public function toggleStatus(Product $product, array $validated, User $user): void
    {
        $isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
        $newStatus = ProductStatus::tryFrom($validated['status'] ?? '');

        if ($isOwner) {
            $product->update([
                'status' => $newStatus,
            ]);

            $this->cacheForgetByPattern('master:products:*');
            $this->cacheForget('homepage:page_data');

            $statusLabel = $newStatus?->label() ?? 'unknown';

            $this->notifyOwner(
                'Ubah Status Produk',
                "Status produk '{$product->name}' telah diubah menjadi {$statusLabel} oleh {$user->profile?->full_name}.",
                route('admin.master.products.index', ['search_id' => $product->id]),
            );

            return;
        }

        $this->runInTransaction(
            function () use ($product, $user, $newStatus): void {
                OwnerVerificationRequest::create([
                    'action' => OwnerVerificationAction::TOGGLE_STATUS,
                    'status' => OwnerVerificationStatus::PENDING,
                    'subject_type' => Product::class,
                    'subject_id' => $product->id,
                    'submitted_by_id' => $user->id,
                    'payload' => [
                        'old' => [
                            'name' => $product->name,
                            'status' => $product->status->value,
                        ],
                        'new' => [
                            'name' => $product->name,
                            'status' => $newStatus->value,
                        ],
                    ],
                ]);
            },
            'Gagal mengajukan perubahan status produk',
        );

        $statusLabel = $newStatus?->label() ?? 'unknown';

        $this->notifyForPendingRequest(
            $user,
            'Ubah Status Produk',
            "Pengajuan ubah status produk '{$product->name}' menjadi {$statusLabel} oleh {$user->profile?->full_name} menunggu verifikasi owner.",
            route('admin.master.products.index', ['search_id' => $product->id]),
            (string) $product->id,
        );
    }

    public function applyVerificationRequest(OwnerVerificationRequest $verificationRequest): void
    {
        match ($verificationRequest->action) {
            OwnerVerificationAction::CREATE => $this->applyCreate($verificationRequest),
            OwnerVerificationAction::UPDATE => $this->applyUpdate($verificationRequest),
            OwnerVerificationAction::DELETE => $this->applyDelete($verificationRequest),
            OwnerVerificationAction::TOGGLE_STATUS => $this->applyToggleStatus($verificationRequest),
            default => throw ValidationException::withMessages([
                'action' => 'Aksi verifikasi produk tidak didukung.',
            ]),
        };

        $this->cacheForgetByPattern('master:products:*');
        $this->cacheForgetByPattern('prices:*');
    }

    public function rejectVerificationRequest(OwnerVerificationRequest $verificationRequest): void
    {
        match ($verificationRequest->action) {
            OwnerVerificationAction::CREATE => $this->rejectCreate($verificationRequest),
            OwnerVerificationAction::UPDATE => $this->rollbackUpdate($verificationRequest),
            OwnerVerificationAction::DELETE, OwnerVerificationAction::TOGGLE_STATUS => null,
            default => throw ValidationException::withMessages([
                'action' => 'Aksi verifikasi produk tidak didukung.',
            ]),
        };

        $this->cacheForgetByPattern('master:products:*');
        $this->cacheForgetByPattern('prices:*');
        $this->cacheForget('homepage:page_data');
    }

    public function clearVerificationRequestMedia(OwnerVerificationRequest $verificationRequest): void
    {
        $verificationRequest->load('media');

        $newPayload = $this->payloadNew($verificationRequest);

        foreach ($newPayload['variants'] ?? [] as $index => $_variant) {
            $verificationRequest->clearMediaCollection($verificationRequest->variantImageCollection((int) $index));
        }
    }

    public function applyCreate(OwnerVerificationRequest $verificationRequest): void
    {
        $product = $verificationRequest->subject;

        if (! $product instanceof Product) {
            throw ValidationException::withMessages([
                'product' => 'Produk tidak ditemukan.',
            ]);
        }

        $product->update([
            'status' => ProductStatus::ACTIVE,
        ]);
    }

    public function applyUpdate(OwnerVerificationRequest $verificationRequest): void
    {
        $product = $verificationRequest->subject;

        if (! $product instanceof Product) {
            throw ValidationException::withMessages([
                'product' => 'Produk tidak ditemukan.',
            ]);
        }

        $this->applyPayloadToProduct($product, $this->payloadNew($verificationRequest), $verificationRequest);
    }

    private function applyPayloadToProduct(
        Product $product,
        array $payload,
        ?OwnerVerificationRequest $verificationRequest = null,
    ): void {
        $product->update([
            'name' => $payload['name'],
            'description' => $payload['description'] ?? null,
        ]);

        if (array_key_exists('status', $payload)) {
            $status = ProductStatus::tryFrom($payload['status']);
            if ($status !== null) {
                $product->update([
                    'status' => $status,
                ]);
            }
        }

        $product->categories()->sync($payload['category_ids'] ?? []);

        $submittedVariantIds = collect($payload['variants'] ?? [])
            ->pluck('id')
            ->filter()
            ->map(fn ($id) => (int) $id)
            ->all();

        $product->variants()
            ->whereNotIn('id', $submittedVariantIds)
            ->get()
            ->each(function (ProductVariant $variant): void {
                $variant->delete();
            });

        foreach ($payload['variants'] ?? [] as $index => $variantData) {
            if (! empty($variantData['id'])) {
                $variant = $product->variants()->findOrFail($variantData['id']);
                $variant->update([
                    'name' => $variantData['name'],
                    'stock' => $variantData['stock'],
                    'retail_stock' => $variantData['retail_stock'],
                ]);

                if ($verificationRequest !== null) {
                    $this->applyVariantImageChanges($verificationRequest, $variant, $variantData, (int) $index);
                }

                if (! empty($variantData['prices'])) {
                    foreach ($variantData['prices'] as $type => $priceValue) {
                        $variant->prices()->updateOrCreate(
                            ['type' => $type],
                            ['price' => $priceValue]
                        );
                    }
                }

                continue;
            }

            $variant = $product->variants()->create([
                'name' => $variantData['name'],
                'stock' => $variantData['stock'],
                'retail_stock' => $variantData['retail_stock'],
            ]);

            if ($verificationRequest !== null) {
                $this->copyRequestVariantImages($verificationRequest, (int) $index, $variant);
            }

            if (! empty($variantData['prices'])) {
                foreach ($variantData['prices'] as $type => $priceValue) {
                    $variant->prices()->create([
                        'type' => $type,
                        'price' => $priceValue,
                    ]);
                }
            }
        }
    }

    public function applyDelete(OwnerVerificationRequest $verificationRequest): void
    {
        $product = $verificationRequest->subject;

        if (! $product instanceof Product) {
            throw ValidationException::withMessages([
                'product' => 'Produk tidak ditemukan.',
            ]);
        }

        $this->applyDeleteSubject($product);
    }

    private function applyDeleteSubject(Product $product): void
    {
        $this->runInTransaction(
            function () use ($product): void {
                $product->variants()->delete();
                $product->categories()->detach();
                $product->delete();
            },
            'Gagal menghapus produk',
        );
    }

    public function applyToggleStatus(OwnerVerificationRequest $verificationRequest): void
    {
        $product = $verificationRequest->subject;

        if (! $product instanceof Product) {
            throw ValidationException::withMessages([
                'product' => 'Produk tidak ditemukan.',
            ]);
        }

        $newPayload = $this->payloadNew($verificationRequest);

        $status = ProductStatus::tryFrom($newPayload['status'] ?? '');

        $product->update([
            'status' => $status ?? ProductStatus::INACTIVE,
        ]);
    }

    private function notifyOwner(string $typeLabel, string $body, string $url): void
    {
        $this->pushNotificationService->sendToRoles(
            "📦 {$typeLabel}",
            $body,
            ['owner', 'developer'],
            $url,
        );
    }

    private function notifyForPendingRequest(User $user, string $typeLabel, string $body, string $submitterUrl, ?string $search = null): void
    {
        $ownerUrl = route('admin.master.products.index');
        if ($search !== null) {
            $ownerUrl = route('admin.master.products.index', ['search_id' => $search]);
        }

        $this->pushNotificationService->sendToRoles(
            "📦 {$typeLabel} Menunggu Persetujuan Owner",
            $body,
            ['owner', 'developer'],
            $ownerUrl,
        );

        $this->pushNotificationService->sendToUser(
            '📤 Pengajuan Terkirim',
            $body,
            $user->id,
            $submitterUrl,
        );
    }

    private function rejectCreate(OwnerVerificationRequest $verificationRequest): void
    {
        $product = $verificationRequest->subject;

        if (! $product instanceof Product) {
            return;
        }

        $this->runInTransaction(
            function () use ($product): void {
                $product->variants()->delete();
                $product->categories()->detach();
                $product->delete();
            },
            'Gagal menolak produk',
        );
    }

    private function rollbackUpdate(OwnerVerificationRequest $verificationRequest): void
    {
        $product = $verificationRequest->subject;

        if (! $product instanceof Product) {
            throw ValidationException::withMessages([
                'product' => 'Produk tidak ditemukan.',
            ]);
        }

        $oldPayload = $this->payloadOld($verificationRequest);

        if ($oldPayload === []) {
            return;
        }

        $this->applyPayloadToProduct($product, $oldPayload);
    }

    private function payloadOld(OwnerVerificationRequest $verificationRequest): array
    {
        $payload = $verificationRequest->payload ?? [];

        if (array_key_exists('old', $payload)) {
            return is_array($payload['old']) ? $payload['old'] : [];
        }

        return [];
    }

    private function payloadNew(OwnerVerificationRequest $verificationRequest): array
    {
        $payload = $verificationRequest->payload ?? [];

        if (array_key_exists('new', $payload)) {
            return is_array($payload['new']) ? $payload['new'] : [];
        }

        return $payload;
    }

    private function snapshotProduct(Product $product): array
    {
        $product->load(['categories', 'variants.prices']);

        return $this->enrichPayload([
            'name' => $product->name,
            'description' => $product->description,
            'category_ids' => $product->categories->pluck('id')->all(),
            'status' => $product->status->value,
            'variants' => $product->variants
                ->map(fn (ProductVariant $variant) => [
                    'id' => $variant->id,
                    'name' => $variant->name,
                    'stock' => $variant->stock,
                    'retail_stock' => $variant->retail_stock,
                    'prices' => $variant->prices
                        ->mapWithKeys(fn ($price) => [$price->type->value => $price->price])
                        ->all(),
                ])
                ->all(),
        ]);
    }

    private function enrichPayload(array $data): array
    {
        $categoryIds = $data['category_ids'] ?? [];

        $data['category_names'] = $categoryIds === []
            ? []
            : Category::query()->whereIn('id', $categoryIds)->pluck('name')->all();

        return $data;
    }

    private function buildPayloadFromValidated(array $validated): array
    {
        return [
            'name' => $validated['name'],
            'description' => $validated['description'] ?? null,
            'status' => $validated['status'] ?? ProductStatus::ACTIVE->value,
            'category_ids' => $validated['category_ids'] ?? [],
            'variants' => collect($validated['variants'] ?? [])
                ->map(fn (array $variantData) => [
                    'id' => $variantData['id'] ?? null,
                    'name' => $variantData['name'],
                    'stock' => $variantData['stock'],
                    'retail_stock' => $variantData['retail_stock'],
                    'prices' => $variantData['prices'] ?? [],
                    'remove_media_ids' => $variantData['remove_media_ids'] ?? [],
                ])
                ->all(),
        ];
    }

    private function syncVariantImages(
        ProductVariant $variant,
        array $variantData,
        int $index,
    ): void {
        $this->mediaService->syncCollection(
            $variant,
            'images',
            $variantData['images'] ?? null,
            $variantData['remove_media_ids'] ?? null,
            self::MAX_VARIANT_IMAGES,
            required: true,
            errorKey: "variants.{$index}.s3_keys",
            s3Keys: $variantData['s3_keys'] ?? null,
        );
    }

    private function syncRequestVariantImages(
        OwnerVerificationRequest $verificationRequest,
        array $variantData,
        int $index,
        bool $required = true,
    ): void {
        $collection = $verificationRequest->variantImageCollection($index);

        $this->mediaService->syncCollection(
            $verificationRequest,
            $collection,
            $variantData['images'] ?? null,
            $variantData['remove_media_ids'] ?? null,
            self::MAX_VARIANT_IMAGES,
            required: $required,
            errorKey: "variants.{$index}.s3_keys",
            s3Keys: $variantData['s3_keys'] ?? null,
        );
    }

    private function applyVariantImageChanges(
        OwnerVerificationRequest $verificationRequest,
        ProductVariant $variant,
        array $variantData,
        int $index,
    ): void {
        $removeIds = $variantData['remove_media_ids'] ?? [];

        if ($removeIds !== []) {
            $variant->getMedia('images')
                ->whereIn('id', $removeIds)
                ->each->delete();
        }

        $this->copyRequestVariantImages($verificationRequest, $index, $variant);
    }

    private function copyRequestVariantImages(OwnerVerificationRequest $verificationRequest, int $index, ProductVariant $variant): void
    {
        $verificationRequest->getMedia($verificationRequest->variantImageCollection($index))
            ->each(fn ($media) => $media->copy($variant, 'images'));
    }

    private function applySorting(Builder $query, string $sort, string $direction): void
    {
        if (in_array($sort, ['name', 'slug', 'status'], true)) {
            $query->orderBy($sort, $direction);

            return;
        }

        $query->latest();
    }
}
