<?php

namespace App\Services\Admin\Manage;

use App\Enums\PriceType;
use App\Enums\ProductStockQuality;
use App\Enums\Role;
use App\Models\ProductVariant;
use App\Models\Restock;
use App\Models\RestockItem;
use App\Services\Concerns\HasStockAdjustment;
use App\Services\Concerns\RegistersMedia;
use App\Services\NotificationService;
use App\Services\S3PresignedService;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

class RestockService
{
    use HasStockAdjustment, RegistersMedia;

    public function __construct(
        private S3PresignedService $s3Service,
    ) {}

    public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
    {
        $paginator = Restock::query()
            ->select(['id', 'created_by_id', 'total', 'notes', 'stock_type', 'created_at'])
            ->with([
                'createdBy:id',
                'createdBy.userProfile:id,user_id,full_name',
                'restockItems' => fn ($q) => $q
                    ->select(['id', 'restock_id', 'product_variant_id', 'quantity', 'unit_price', 'subtotal'])
                    ->orderByRaw('(SELECT name FROM product_variants WHERE product_variants.id = restock_items.product_variant_id)'),
                'restockItems.productVariant:id,product_id,name,stock,reject_stock,retail_stock',
                'restockItems.productVariant.product:id,name',
            ])
            ->when($search, function ($q) use ($search) {
                $q->whereHas('restockItems.productVariant.product', fn ($sq) => $sq->where('name', 'like', "%{$search}%"))
                    ->orWhere('notes', 'like', "%{$search}%");
            })
            ->orderBy($sort, $direction)
            ->paginate($perPage);

        $paginator->getCollection()->each(function (Restock $restock) {
            $restock->restockItems->each(function (RestockItem $item) {
                if (! $item->productVariant) {
                    return;
                }

                $media = $item->productVariant->getFirstMedia('images');
                $item->productVariant->photo_url = $media
                    ? $this->s3Service->getTemporaryUrl($media->getPath())
                    : null;
                $item->productVariant->photo_conversion_url = $media
                    ? $this->s3Service->getTemporaryUrl($media->getPath('thumb'))
                    : null;
            });
        });

        return $paginator;
    }

    public function store(array $data): Restock
    {
        return DB::transaction(function () use ($data) {
            $now = now();
            $total = 0;
            $stockType = $data['stock_type'] ?? ProductStockQuality::GOOD->value;

            $itemRows = $this->buildItemRows($data['items'], $stockType, $now, $total);

            $restock = Restock::create([
                'created_by_id' => auth()->id(),
                'total' => $total,
                'notes' => $data['notes'] ?? null,
                'stock_type' => $stockType,
            ]);

            foreach ($itemRows as &$row) {
                $row['restock_id'] = $restock->id;
            }
            DB::table('restock_items')->insert($itemRows);

            $this->applyStock($data['items'], $stockType, 1);
            $this->syncPhoto($restock, $data);

            NotificationService::notify(
                roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_TOKO],
                title: 'Restock Baru',
                body: 'Restock '.($stockType === ProductStockQuality::GOOD->value ? 'produk' : 'reject').' sebesar Rp '.number_format($total, 0, ',', '.').' berhasil dicatat oleh '.auth()->user()->full_name.'.',
                url: route('admin.manage.restocks.index'),
            );

            return $restock;
        });
    }

    public function update(Restock $restock, array $data): Restock
    {
        return DB::transaction(function () use ($restock, $data) {
            $restock->load('restockItems');

            $restock->restockItems->each(function (RestockItem $item) use ($restock) {
                $this->adjustVariantStock($item->product_variant_id, $item->quantity, -1, $restock->stock_type->value);
            });

            $restock->restockItems()->delete();

            $now = now();
            $total = 0;
            $stockType = $data['stock_type'] ?? $restock->stock_type->value;

            $itemRows = $this->buildItemRows($data['items'], $stockType, $now, $total);

            foreach ($itemRows as &$row) {
                $row['restock_id'] = $restock->id;
            }
            DB::table('restock_items')->insert($itemRows);

            $restock->update([
                'total' => $total,
                'notes' => $data['notes'] ?? null,
                'stock_type' => $stockType,
            ]);

            $this->applyStock($data['items'], $stockType, 1);
            $this->syncPhoto($restock, $data);

            return $restock;
        });
    }

    public function destroy(Restock $restock): bool
    {
        return DB::transaction(function () use ($restock) {
            $restock->load('restockItems');

            $restock->restockItems->each(function (RestockItem $item) use ($restock) {
                $this->adjustVariantStock($item->product_variant_id, $item->quantity, -1, $restock->stock_type->value);
            });

            $restock->restockItems()->delete();
            $restock->delete();

            return true;
        });
    }

    private function buildItemRows(array $items, string $stockType, $now, int &$total): array
    {
        $priceType = $stockType === ProductStockQuality::REJECT->value
            ? PriceType::REJECT
            : PriceType::CAPITAL;

        $variantIds = collect($items)->pluck('product_variant_id')->unique()->all();
        $prices = ProductVariant::query()
            ->whereKey($variantIds)
            ->with('productPrices:id,variant_id,type,price')
            ->get()
            ->mapWithKeys(function (ProductVariant $variant) use ($priceType) {
                $price = $variant->productPrices
                    ->first(fn ($p) => $p->type === $priceType);

                return [$variant->id => $price?->price ?? 0];
            });

        return collect($items)->map(function ($item) use ($now, $prices, &$total) {
            $quantity = (int) $item['quantity'];
            $unitPrice = (int) ($prices[$item['product_variant_id']] ?? 0);
            $itemSubtotal = $unitPrice * $quantity;
            $total += $itemSubtotal;

            return [
                'restock_id' => null,
                'user_id' => auth()->id(),
                'product_variant_id' => $item['product_variant_id'],
                'quantity' => $quantity,
                'unit_price' => $unitPrice,
                'subtotal' => $itemSubtotal,
                'created_at' => $now,
                'updated_at' => $now,
            ];
        })->toArray();
    }
}
