<?php

declare(strict_types=1);

namespace App\Business\Purchase;

use App\Business\Purchase\Enums\PurchaseOrderStatus;
use App\Models\DberpProduct;
use App\Models\DberpPurchaseOrderItem;
use App\Models\DberpPurchasePriceReferenceSnapshot;
use Illuminate\Database\Eloquent\Builder;

final class PurchasePriceReferenceService
{
    public function refreshForProduct(int $productId, ?int $supplierId = null): void
    {
        $this->refreshSnapshot(productId: $productId, supplierId: null, scopeType: 'product');

        if ($supplierId !== null) {
            $this->refreshSnapshot(productId: $productId, supplierId: $supplierId, scopeType: 'supplier_product');
        }
    }

    /**
     * @return array<string, mixed>
     */
    public function getContext(int $productId, ?int $supplierId = null): array
    {
        $this->refreshForProduct($productId, $supplierId);

        $productSnapshot = DberpPurchasePriceReferenceSnapshot::query()
            ->where('scope_key', $this->buildScopeKey('product', $productId, null))
            ->first();

        $supplierSnapshot = $supplierId !== null
            ? DberpPurchasePriceReferenceSnapshot::query()
                ->where('scope_key', $this->buildScopeKey('supplier_product', $productId, $supplierId))
                ->first()
            : null;

        $product = DberpProduct::query()->find($productId);

        return [
            'product_snapshot' => $this->mapSnapshot($productSnapshot),
            'supplier_snapshot' => $this->mapSnapshot($supplierSnapshot),
            'product_cost_price' => $product?->cost_price !== null ? (string) $product->cost_price : null,
        ];
    }

    private function refreshSnapshot(int $productId, ?int $supplierId, string $scopeType): void
    {
        /** @var DberpPurchaseOrderItem|null $item */
        $item = DberpPurchaseOrderItem::query()
            ->select('dberp_purchase_order_items.*')
            ->join('dberp_purchase_orders as purchase_orders', 'purchase_orders.id', '=', 'dberp_purchase_order_items.order_id')
            ->where('dberp_purchase_order_items.product_id', $productId)
            ->when($supplierId !== null, function (Builder $query) use ($supplierId): Builder {
                return $query->where('purchase_orders.supplier_id', $supplierId);
            })
            ->whereIn('purchase_orders.status', [
                PurchaseOrderStatus::Confirmed->value,
                PurchaseOrderStatus::PartiallyReceived->value,
                PurchaseOrderStatus::FullyReceived->value,
                PurchaseOrderStatus::Closed->value,
            ])
            ->with([
                'order.receipts' => fn ($query) => $query
                    ->where('status', 'effective')
                    ->orderBy('effective_at')
                    ->orderBy('id'),
            ])
            ->orderByDesc('purchase_orders.business_time')
            ->orderByDesc('dberp_purchase_order_items.id')
            ->first();

        $earliestReceipt = $item?->order?->receipts?->first();
        $latestTransactionDate = $item?->order?->business_time?->toDateString();
        $latestReceiptDate = $earliestReceipt?->effective_at?->toDateString();

        $leadTimeDays = null;

        if ($item?->order?->business_time !== null && $earliestReceipt?->effective_at !== null) {
            $leadTimeDays = $item->order->business_time->startOfDay()->diffInDays($earliestReceipt->effective_at->startOfDay());
        }

        DberpPurchasePriceReferenceSnapshot::query()->updateOrCreate(
            ['scope_key' => $this->buildScopeKey($scopeType, $productId, $supplierId)],
            [
                'scope_type' => $scopeType,
                'product_id' => $productId,
                'supplier_id' => $supplierId,
                'latest_transaction_unit_price' => $item?->unit_price,
                'latest_transaction_date' => $latestTransactionDate,
                'latest_receipt_date' => $latestReceiptDate,
                'latest_lead_time_days' => $leadTimeDays,
                'latest_purchase_order_id' => $item?->order_id,
                'latest_purchase_order_item_id' => $item?->id,
                'refreshed_at' => now(),
            ],
        );
    }

    /**
     * @return array<string, mixed>|null
     */
    private function mapSnapshot(?DberpPurchasePriceReferenceSnapshot $snapshot): ?array
    {
        if ($snapshot === null) {
            return null;
        }

        return [
            'scope_type' => $snapshot->scope_type,
            'product_id' => $snapshot->product_id,
            'supplier_id' => $snapshot->supplier_id,
            'latest_transaction_unit_price' => $snapshot->latest_transaction_unit_price !== null ? (string) $snapshot->latest_transaction_unit_price : null,
            'latest_transaction_date' => $snapshot->getRawOriginal('latest_transaction_date') ?: null,
            'latest_receipt_date' => $snapshot->getRawOriginal('latest_receipt_date') ?: null,
            'latest_lead_time_days' => $snapshot->latest_lead_time_days,
            'latest_purchase_order_id' => $snapshot->latest_purchase_order_id,
            'latest_purchase_order_item_id' => $snapshot->latest_purchase_order_item_id,
        ];
    }

    private function buildScopeKey(string $scopeType, int $productId, ?int $supplierId): string
    {
        return $scopeType === 'supplier_product'
            ? 'supplier_product:'.$supplierId.':'.$productId
            : 'product:'.$productId;
    }
}