<?php
declare(strict_types=1);

namespace Autogedal\StockLog\Observer;

use Autogedal\StockLog\Model\StockLogger;
use Autogedal\StockLog\Model\StockSourceContext;
use Magento\Authorization\Model\UserContextInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\User\Model\UserFactory;

/**
 * Catches stock changes that go through the ORM (admin manual edits, order placement).
 * Cron-based changes go through SetDataToLegacyStockItem and are handled by the plugin.
 */
class StockItemSaveAfter implements ObserverInterface
{
    private StockLogger $stockLogger;
    private ResourceConnection $resource;
    private UserContextInterface $userContext;
    private UserFactory $userFactory;

    public function __construct(
        StockLogger $stockLogger,
        ResourceConnection $resource,
        UserContextInterface $userContext,
        UserFactory $userFactory
    ) {
        $this->stockLogger   = $stockLogger;
        $this->resource      = $resource;
        $this->userContext   = $userContext;
        $this->userFactory   = $userFactory;
    }

    public function execute(Observer $observer): void
    {
        /** @var \Magento\CatalogInventory\Model\Stock\Item $item */
        $item = $observer->getEvent()->getItem();

        $qtyBefore     = (float)($item->getOrigData('qty') ?? 0);
        $qtyAfter      = (float)$item->getQty();
        $inStockBefore = (int)($item->getOrigData('is_in_stock') ?? 0);
        $inStockAfter  = (int)$item->getIsInStock();

        if ($qtyBefore === $qtyAfter && $inStockBefore === $inStockAfter) {
            return;
        }

        $productId = (int)$item->getProductId();
        if (!$productId) {
            return;
        }

        $sku = $this->getSkuByProductId($productId);
        if ($sku === null) {
            return;
        }

        $source        = StockSourceContext::getInstance()->getSource();
        $adminUserId   = null;
        $adminUsername = null;

        if ($this->userContext->getUserType() === UserContextInterface::USER_TYPE_ADMIN
            && $this->userContext->getUserId()
        ) {
            $adminUserId = (int)$this->userContext->getUserId();
            $adminUser   = $this->userFactory->create()->load($adminUserId);
            $adminUsername = $adminUser->getUserName() ?: null;
            if ($source === 'unknown') {
                $source = 'admin_manual';
            }
        }

        $this->stockLogger->log(
            $sku,
            $qtyBefore,
            $qtyAfter,
            $inStockBefore,
            $inStockAfter,
            $adminUserId,
            $adminUsername,
            $source
        );
    }

    private function getSkuByProductId(int $productId): ?string
    {
        $connection = $this->resource->getConnection();
        $result = $connection->fetchOne(
            $connection->select()
                ->from($this->resource->getTableName('catalog_product_entity'), ['sku'])
                ->where('entity_id = ?', $productId)
        );
        return $result ?: null;
    }
}
