<?php

namespace App\Services\Manage;

use App\Enums\OwnerVerificationAction;
use App\Enums\OwnerVerificationStatus;
use App\Enums\Permission;
use App\Models\OwnerVerificationRequest;
use App\Models\Purchase;
use App\Models\PurchaseItem;
use App\Models\RawMaterial;
use App\Models\RawMaterialPrice;
use App\Models\Supplier;
use App\Models\User;
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\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;

class PurchaseService
{
    private const MAX_PHOTOS = 1;

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

    public function paginateForIndex(array $tableQuery): LengthAwarePaginator
    {
        $query = Purchase::query()
            ->with([
                'supplier:id,name',
                'createdBy.profile',
                'pendingOwnerVerificationRequest',
                'items.rawMaterialPrice.rawMaterial:id,name,unit',
                'media',
            ])
            ->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
                $search = $tableQuery['search'];
                $query->where(function (Builder $query) use ($search): void {
                    $query->where('notes', 'like', "%{$search}%")
                        ->orWhereHas('supplier', fn (Builder $query) => $query->where('name', 'like', "%{$search}%"))
                        ->orWhereHas('items.rawMaterialPrice', function (Builder $query) use ($search): void {
                            $query->where('variant', 'like', "%{$search}%")
                                ->orWhereHas('rawMaterial', fn (Builder $query) => $query->where('name', 'like', "%{$search}%"));
                        });
                });
            });

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

        return $query
            ->paginate(25)
            ->withQueryString()
            ->through(function (Purchase $purchase) {
                $purchase->setAttribute(
                    'photos',
                    MediaPresenter::first($purchase, 'photos'),
                );

                $pendingRequest = $purchase->pendingOwnerVerificationRequest;

                $purchase->setAttribute('has_pending_request', $pendingRequest !== null);
                $purchase->setAttribute('pending_request_id', $pendingRequest?->id);
                $purchase->setAttribute('pending_request_action', $pendingRequest?->action->value);
                $purchase->setAttribute('pending_request_action_label', $pendingRequest?->action->label());

                $purchase->items->each(fn (PurchaseItem $item) => $this->breakItemCircularReference($item));

                return $purchase;
            });
    }

    public function supplierOptions(): array
    {
        return Supplier::query()
            ->orderBy('name')
            ->get(['id', 'name'])
            ->map(fn (Supplier $supplier) => [
                'value' => $supplier->id,
                'label' => $supplier->name,
            ])
            ->all();
    }

    public function catalogItems(?Purchase $purchase = null, ?User $user = null): Collection
    {
        $purchasePriceIds = $purchase
            ? $purchase->items()->pluck('raw_material_price_id')->all()
            : ($user ? $this->draftItemsQuery($user)->pluck('raw_material_price_id')->all() : []);

        return RawMaterial::query()
            ->with([
                'prices' => fn ($query) => $query
                    ->orderBy('created_at')
                    ->with('media'),
            ])
            ->where(function (Builder $query) use ($purchasePriceIds): void {
                $query->active();

                if ($purchasePriceIds !== []) {
                    $query->orWhereHas(
                        'prices',
                        fn (Builder $query) => $query->whereIn('id', $purchasePriceIds),
                    );
                }
            })
            ->orderBy('name')
            ->get()
            ->each(function (RawMaterial $rawMaterial): void {
                $rawMaterial->prices->each(function (RawMaterialPrice $price) use ($rawMaterial): void {
                    $price->setAttribute('images', MediaPresenter::collection($price, 'images'));
                    $price->setAttribute('unit_abbreviation', $rawMaterial->unit->abbreviation());
                    $price->unsetRelation('rawMaterial');
                });
            });
    }

    public function findForEdit(Purchase $purchase): Purchase
    {
        $purchase->load([
            'items.rawMaterialPrice.rawMaterial:id,name,unit',
            'media',
        ]);

        $purchase->setAttribute(
            'photos',
            MediaPresenter::first($purchase, 'photos'),
        );

        $purchase->items->each(function (PurchaseItem $item): void {
            $price = $item->rawMaterialPrice;

            if ($price) {
                $price->setAttribute('images', MediaPresenter::collection($price, 'images'));
            }

            $this->breakItemCircularReference($item);
        });

        return $purchase;
    }

    public function draftItemsForUser(User $user): array
    {
        return $this->draftItemsQuery($user)
            ->with([
                'rawMaterialPrice.rawMaterial:id,name,unit',
                'rawMaterialPrice.media',
            ])
            ->get()
            ->map(function (PurchaseItem $item) {
                $result = $this->presentDraftItem($item);
                $this->breakItemCircularReference($item);

                return $result;
            })
            ->values()
            ->all();
    }

    public function syncDraftItem(array $validated, User $user): array
    {
        $price = RawMaterialPrice::query()
            ->with('rawMaterial:id,name,unit')
            ->findOrFail($validated['raw_material_price_id']);

        $quantity = (float) $validated['quantity'];
        $unitPrice = (int) $price->price;
        $subtotal = (int) round($quantity * $unitPrice);

        $item = PurchaseItem::query()->updateOrCreate(
            [
                'user_id' => $user->id,
                'raw_material_price_id' => $price->id,
                'purchase_id' => null,
            ],
            [
                'quantity' => $quantity,
                'unit_price' => $unitPrice,
                'subtotal' => $subtotal,
            ],
        );

        $item->load([
            'rawMaterialPrice.rawMaterial:id,name,unit',
            'rawMaterialPrice.media',
        ]);

        $result = $this->presentDraftItem($item);
        $this->breakItemCircularReference($item);

        return $result;
    }

    public function createVariantAndDraft(array $validated, User $user): array
    {
        $rawMaterial = RawMaterial::query()->findOrFail($validated['raw_material_id']);

        $price = RawMaterialPrice::create([
            'raw_material_id' => $rawMaterial->id,
            'variant' => $validated['variant'],
            'price' => (int) $validated['price'],
            'stock' => (float) ($validated['stock'] ?? 0),
        ]);

        if (! empty($validated['photos'])) {
            $this->mediaService->syncCollection(
                $price,
                'images',
                $validated['photos'],
                null,
                5,
                required: false,
                errorKey: 'photos',
            );
        }

        $price->setAttribute('images', MediaPresenter::collection($price, 'images'));

        return [
            'id' => $price->id,
            'variant' => $price->variant,
            'price' => $price->price,
            'price_formatted' => $price->price_formatted,
            'price_input' => $price->price_input,
            'stock' => $price->stock,
            'stock_formatted' => $price->stock_formatted,
            'stock_input' => $price->stock_input,
            'images' => $price->images,
        ];
    }

    public function removeDraftItem(User $user, RawMaterialPrice $rawMaterialPrice): void
    {
        PurchaseItem::query()
            ->whereNull('purchase_id')
            ->where('user_id', $user->id)
            ->where('raw_material_price_id', $rawMaterialPrice->id)
            ->delete();
    }

    public function create(array $validated, User $user): Purchase
    {
        $isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);

        try {
            $purchase = DB::transaction(function () use ($validated, $user, $isOwner): Purchase {

                $draftItems = $this->draftItemsQuery($user)
                    ->lockForUpdate()
                    ->get();

                if ($draftItems->isEmpty()) {
                    throw ValidationException::withMessages([
                        'items' => 'Tambahkan minimal satu bahan baku ke keranjang.',
                    ]);
                }

                $subtotal = $draftItems->sum('subtotal');
                $discount = (int) ($validated['discount'] ?? 0);
                $shippingCost = (int) ($validated['shipping_cost'] ?? 0);
                $total = max($subtotal - $discount + $shippingCost, 0);

                $purchase = Purchase::create([
                    'supplier_id' => $validated['supplier_id'],
                    'created_by_id' => $user->id,
                    'subtotal' => $subtotal,
                    'discount' => $discount,
                    'shipping_cost' => $shippingCost,
                    'total' => $total,
                    'notes' => $validated['notes'] ?? null,
                ]);

                foreach ($draftItems as $item) {
                    $item->update([
                        'purchase_id' => $purchase->id,
                    ]);
                }

                $this->syncPhotos($purchase, $validated);

                $purchase->load(['supplier', 'items.rawMaterialPrice.rawMaterial:id,name']);

                if ($isOwner) {
                    foreach ($purchase->items as $item) {
                        $this->incrementStock($item);
                    }
                } else {
                    OwnerVerificationRequest::create([
                        'action' => OwnerVerificationAction::CREATE,
                        'status' => OwnerVerificationStatus::PENDING,
                        'subject_type' => Purchase::class,
                        'subject_id' => $purchase->id,
                        'submitted_by_id' => $user->id,
                        'payload' => [
                            'old' => null,
                            'new' => $this->snapshotPurchase($purchase),
                        ],
                    ]);
                }

                return $purchase;
            });
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Throwable $e) {
            Log::error('Gagal membuat pembelian: '.$e->getMessage(), [
                'trace' => $e->getTraceAsString(),
            ]);

            throw ValidationException::withMessages([
                'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
            ]);
        }

        if (! $isOwner) {
            $this->notifyForPendingRequest(
                $user,
                'Tambah Belanja',
                "Pengajuan belanja dari supplier {$purchase->supplier->name} senilai {$purchase->total_formatted} menunggu verifikasi owner.",
                route('admin.manage.purchases.index', ['search' => $purchase->supplier->name]),
                $purchase->supplier->name,
            );
        }

        return $purchase;
    }

    public function update(Purchase $purchase, array $validated, User $user): void
    {
        $isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
        $purchase->load(['supplier', 'items.rawMaterialPrice.rawMaterial:id,name']);

        try {
            DB::transaction(function () use ($purchase, $validated, $user, $isOwner): void {
                if ($isOwner) {
                    $payload = $this->buildPayloadFromValidated($validated);
                    $this->applyPayloadToPurchase($purchase, $payload);

                    if (($validated['photos'] ?? null) !== null || ($validated['remove_media_ids'] ?? []) !== []) {
                        $this->syncPhotos($purchase, $validated);
                    }
                } else {
                    $verificationRequest = OwnerVerificationRequest::create([
                        'action' => OwnerVerificationAction::UPDATE,
                        'status' => OwnerVerificationStatus::PENDING,
                        'subject_type' => Purchase::class,
                        'subject_id' => $purchase->id,
                        'submitted_by_id' => $user->id,
                        'payload' => [
                            'old' => $this->snapshotPurchase($purchase),
                            'new' => $this->buildPayloadFromValidated($validated),
                        ],
                    ]);

                    if (($validated['photos'] ?? null) !== null || ($validated['remove_media_ids'] ?? []) !== []) {
                        $this->syncRequestPhotos($verificationRequest, $validated);
                    }
                }
            });
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Throwable $e) {
            Log::error('Gagal memperbarui pembelian: '.$e->getMessage(), [
                'trace' => $e->getTraceAsString(),
            ]);

            throw ValidationException::withMessages([
                'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
            ]);
        }

        if (! $isOwner) {
            $purchase->load('supplier');

            $this->notifyForPendingRequest(
                $user,
                'Ubah Belanja',
                "Pengajuan ubah belanja dari supplier {$purchase->supplier->name} menunggu verifikasi owner.",
                route('admin.manage.purchases.index', ['search' => $purchase->supplier->name]),
                $purchase->supplier->name,
            );
        }
    }

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

        if ($isOwner) {
            $this->executeDelete($purchase);

            return;
        }

        $purchase->load(['supplier', 'items.rawMaterialPrice.rawMaterial:id,name']);

        try {
            OwnerVerificationRequest::create([
                'action' => OwnerVerificationAction::DELETE,
                'status' => OwnerVerificationStatus::PENDING,
                'subject_type' => Purchase::class,
                'subject_id' => $purchase->id,
                'submitted_by_id' => $user->id,
                'payload' => [
                    'old' => $this->snapshotPurchase($purchase),
                    'new' => null,
                ],
            ]);
        } catch (\Throwable $e) {
            Log::error('Gagal mengajukan penghapusan belanja: '.$e->getMessage(), [
                'trace' => $e->getTraceAsString(),
            ]);

            throw ValidationException::withMessages([
                'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
            ]);
        }

        $purchase->load('supplier');

        $this->notifyForPendingRequest(
            $user,
            'Hapus Belanja',
            "Pengajuan hapus belanja dari supplier {$purchase->supplier->name} menunggu verifikasi owner.",
            route('admin.manage.purchases.index', ['search' => $purchase->supplier->name]),
            $purchase->supplier->name,
        );
    }

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

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

    public function clearVerificationRequestMedia(OwnerVerificationRequest $verificationRequest): void
    {
        $verificationRequest->clearMediaCollection('photos');
    }

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

        if (! $purchase instanceof Purchase) {
            throw ValidationException::withMessages([
                'purchase' => 'Belanja tidak ditemukan.',
            ]);
        }

        $purchase->load('items');

        foreach ($purchase->items as $item) {
            $this->incrementStock($item);
        }
    }

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

        if (! $purchase instanceof Purchase) {
            throw ValidationException::withMessages([
                'purchase' => 'Belanja tidak ditemukan.',
            ]);
        }

        $this->applyPayloadToPurchase($purchase, $this->payloadNew($verificationRequest), $verificationRequest);
    }

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

        if (! $purchase instanceof Purchase) {
            throw ValidationException::withMessages([
                'purchase' => 'Belanja tidak ditemukan.',
            ]);
        }

        $this->executeDelete($purchase);
    }

    private function buildLineItems(array $items): array
    {
        return collect($items)
            ->map(function (array $itemData, int $index) {
                $price = RawMaterialPrice::query()->find($itemData['raw_material_price_id']);

                if ($price === null) {
                    throw ValidationException::withMessages([
                        "items.{$index}.raw_material_price_id" => 'Bahan baku tidak ditemukan.',
                    ]);
                }

                $quantity = (float) $itemData['quantity'];
                $unitPrice = (int) $price->price;
                $subtotal = (int) round($quantity * $unitPrice);

                return [
                    'raw_material_price_id' => $price->id,
                    'quantity' => $quantity,
                    'unit_price' => $unitPrice,
                    'subtotal' => $subtotal,
                ];
            })
            ->all();
    }

    private function syncPhotos(Purchase $purchase, array $validated): void
    {
        $this->mediaService->syncCollection(
            $purchase,
            'photos',
            $validated['photos'] ?? null,
            $validated['remove_media_ids'] ?? null,
            self::MAX_PHOTOS,
            required: false,
            errorKey: 'photos',
        );
    }

    private function draftItemsQuery(User $user): Builder
    {
        return PurchaseItem::query()
            ->whereNull('purchase_id')
            ->where('user_id', $user->id);
    }

    private function presentDraftItem(PurchaseItem $item): array
    {
        $price = $item->rawMaterialPrice;
        $rawMaterial = $price?->rawMaterial;

        return [
            'raw_material_price_id' => $item->raw_material_price_id,
            'raw_material_name' => $rawMaterial?->name ?? '',
            'variant' => $price?->variant ?? '',
            'unit_abbreviation' => $rawMaterial?->unit?->abbreviation() ?? '',
            'quantity' => $item->quantity_input,
            'unit_price' => $item->unit_price,
            'images' => $price ? MediaPresenter::collection($price, 'images') : [],
        ];
    }

    private function incrementStock(PurchaseItem $item): void
    {
        RawMaterialPrice::query()
            ->whereKey($item->raw_material_price_id)
            ->increment('stock', $item->quantity);
    }

    private function decrementStock(PurchaseItem $item): void
    {
        RawMaterialPrice::query()
            ->whereKey($item->raw_material_price_id)
            ->decrement('stock', $item->quantity);
    }

    private function notifyForPendingRequest(User $user, string $typeLabel, string $body, string $submitterUrl, ?string $search = null): void
    {
        $ownerUrl = route('admin.manage.purchases.index');
        if ($search !== null) {
            $ownerUrl = route('admin.manage.purchases.index', ['search' => $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
    {
        $purchase = $verificationRequest->subject;

        if (! $purchase instanceof Purchase) {
            return;
        }

        DB::transaction(function () use ($purchase): void {
            $purchase->clearMediaCollection('photos');
            $purchase->items()->delete();
            $purchase->delete();
        });
    }

    private function executeDelete(Purchase $purchase): void
    {
        DB::transaction(function () use ($purchase): void {
            $purchase->load('items');

            foreach ($purchase->items as $item) {
                $this->decrementStock($item);
            }

            $purchase->clearMediaCollection('photos');
            $purchase->items()->delete();
            $purchase->delete();
        });
    }

    private function applyPayloadToPurchase(
        Purchase $purchase,
        array $payload,
        ?OwnerVerificationRequest $verificationRequest = null,
    ): void {
        DB::transaction(function () use ($purchase, $payload, $verificationRequest): void {
            $purchase->load('items');

            foreach ($purchase->items as $item) {
                $this->decrementStock($item);
            }

            $purchase->items()->delete();

            foreach ($payload['items'] ?? [] as $itemData) {
                $purchaseItem = $purchase->items()->create([
                    'raw_material_price_id' => $itemData['raw_material_price_id'],
                    'quantity' => $itemData['quantity'],
                    'unit_price' => $itemData['unit_price'],
                    'subtotal' => $itemData['subtotal'],
                ]);
                $this->incrementStock($purchaseItem);
            }

            $purchase->update([
                'supplier_id' => $payload['supplier_id'],
                'subtotal' => $payload['subtotal'],
                'discount' => $payload['discount'],
                'shipping_cost' => $payload['shipping_cost'],
                'total' => $payload['total'],
                'notes' => $payload['notes'] ?? null,
            ]);

            if ($verificationRequest !== null) {
                $this->applyRequestPhotos($verificationRequest, $purchase, $payload);
            }
        });
    }

    private function snapshotPurchase(Purchase $purchase): array
    {
        $purchase->load([
            'supplier:id,name',
            'items.rawMaterialPrice.rawMaterial:id,name',
        ]);

        return [
            'supplier_id' => $purchase->supplier_id,
            'supplier_name' => $purchase->supplier?->name,
            'subtotal' => $purchase->subtotal,
            'discount' => $purchase->discount,
            'shipping_cost' => $purchase->shipping_cost,
            'total' => $purchase->total,
            'notes' => $purchase->notes,
            'items' => $purchase->items
                ->map(fn (PurchaseItem $item) => [
                    'raw_material_price_id' => $item->raw_material_price_id,
                    'raw_material_name' => $item->rawMaterialPrice?->rawMaterial?->name,
                    'variant' => $item->rawMaterialPrice?->variant,
                    'quantity' => (float) $item->quantity,
                    'unit_price' => $item->unit_price,
                    'subtotal' => $item->subtotal,
                ])
                ->all(),
            'has_photos' => $purchase->hasMedia('photos'),
        ];
    }

    private function buildPayloadFromValidated(array $validated): array
    {
        $lineItems = $this->enrichLineItems($this->buildLineItems($validated['items']));
        $subtotal = array_sum(array_column($lineItems, 'subtotal'));
        $discount = (int) ($validated['discount'] ?? 0);
        $shippingCost = (int) ($validated['shipping_cost'] ?? 0);
        $total = max($subtotal - $discount + $shippingCost, 0);
        $supplier = Supplier::query()->find($validated['supplier_id']);

        return [
            'supplier_id' => (int) $validated['supplier_id'],
            'supplier_name' => $supplier?->name,
            'subtotal' => $subtotal,
            'discount' => $discount,
            'shipping_cost' => $shippingCost,
            'total' => $total,
            'notes' => $validated['notes'] ?? null,
            'items' => $lineItems,
            'remove_media_ids' => $validated['remove_media_ids'] ?? [],
        ];
    }

    private function enrichLineItems(array $lineItems): array
    {
        $prices = RawMaterialPrice::query()
            ->with('rawMaterial:id,name')
            ->whereIn('id', array_column($lineItems, 'raw_material_price_id'))
            ->get()
            ->keyBy('id');

        return collect($lineItems)
            ->map(function (array $item) use ($prices) {
                $price = $prices->get($item['raw_material_price_id']);

                return array_merge($item, [
                    'raw_material_name' => $price?->rawMaterial?->name,
                    'variant' => $price?->variant,
                ]);
            })
            ->all();
    }

    private function syncRequestPhotos(OwnerVerificationRequest $verificationRequest, array $validated): void
    {
        $this->mediaService->syncCollection(
            $verificationRequest,
            'photos',
            $validated['photos'] ?? null,
            $validated['remove_media_ids'] ?? null,
            self::MAX_PHOTOS,
            required: false,
            errorKey: 'photos',
        );
    }

    private function applyRequestPhotos(
        OwnerVerificationRequest $verificationRequest,
        Purchase $purchase,
        array $payload,
    ): void {
        if ($verificationRequest->hasMedia('photos')) {
            $purchase->clearMediaCollection('photos');

            foreach ($verificationRequest->getMedia('photos') as $media) {
                $media->copy($purchase, 'photos');
            }

            return;
        }

        foreach ($payload['remove_media_ids'] ?? [] as $mediaId) {
            $purchase->deleteMedia((int) $mediaId);
        }
    }

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

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

        return is_array($payload) ? $payload : [];
    }

    private function breakItemCircularReference(PurchaseItem $item): void
    {
        $price = $item->rawMaterialPrice;

        if ($price) {
            $rawMaterial = $price->rawMaterial;

            $item->setAttribute('variant', $price->variant);

            if ($rawMaterial) {
                $unitAbbreviation = $rawMaterial->unit->abbreviation();
                $price->setAttribute('unit_abbreviation', $unitAbbreviation);
                $item->setAttribute('unit_abbreviation', $unitAbbreviation);
                $item->setAttribute('raw_material_id', $rawMaterial->id);
                $item->setAttribute('raw_material_name', $rawMaterial->name);
                $item->setAttribute('raw_material_unit_label', $rawMaterial->unit->label());
            }

            $price->unsetRelation('rawMaterial');
        }

        $item->unsetRelation('rawMaterialPrice');
    }

    private function applySorting(Builder $query, string $sort, string $direction): void
    {
        if (in_array($sort, ['created_at', 'total', 'discount', 'subtotal'], true)) {
            $query->orderBy($sort, $direction);

            return;
        }

        $query->latest();
    }
}
