<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

use Shopware\CustomModels\ViisonPickwareERP\ItemProperty\ItemProperty;
use Shopware\CustomModels\ViisonPickwareERP\StockLedger\StockItem;
use Shopware\CustomModels\ViisonPickwareERP\StockLedger\StockItemPropertyValue;
use Shopware\CustomModels\ViisonPickwareERP\StockLedger\StockLedgerEntry;
use Shopware\Models\Article\Detail as ArticleDetail;
use Shopware\Plugins\ViisonCommon\Classes\ApiException;

class Shopware_Controllers_Api_ViisonPickwareMobileStockLedgerEntries extends Shopware_Controllers_Api_Rest
{
    /**
     * Updates the stock item with the given ID by updating and/or adding property values based on the request data.
     *
     * PUT /api/stockLedgerEntries/{id}/stockItems/{stockItems}
     */
    public function putStockItemsAction()
    {
        // Try to find the stock ledger entry and stock item
        $stockLedgerEntry = $this->findStockLedgerEntryFromRequestParams();
        $stockItemId = intval($this->Request()->getParam('stockItems'));
        $stockItem = $stockLedgerEntry->getStockItems()->filter(function (StockItem $item) use ($stockItemId) {
            return $item->getId() === $stockItemId;
        })->first();
        if (!$stockItem) {
            throw new ApiException('not_found/stock_leder_entry_item', 404);
        }

        $this->get('models')->beginTransaction();
        try {
            // Update the properties of the stock item
            $properties = $this->Request()->getParam('propertyValues');
            foreach ($properties as $propertyData) {
                $property = $stockItem->getPropertyValues()->filter(
                    function (StockItemPropertyValue $itemProperty) use ($propertyData) {
                        return $itemProperty->getId() === intval($propertyData['id']);
                    }
                )->first();
                if ($property) {
                    // Update the value
                    $property->setValue($propertyData['value']);
                } else {
                    // Create new property
                    $this->createStockItemPropertyValue(
                        $stockItem,
                        intval($propertyData['itemPropertyId']),
                        $propertyData['value']
                    );
                }
            }

            // Save changes
            $this->get('models')->flush($stockItem->getPropertyValues()->toArray());
            $this->get('models')->commit();
        } catch (Exception $e) {
            // Rollback changes
            $this->get('models')->rollBack();
            throw $e;
        }

        // Prepare response data
        $responseData = [
            'id' => $stockItem->getId(),
            'stockLedgerEntryId' => $stockLedgerEntry->getId(),
            'propertyValues' => $stockItem->getPropertyValues()->map(function (StockItemPropertyValue $property) {
                return [
                    'id' => $property->getId(),
                    'stockItemId' => $property->getStockItem()->getId(),
                    'itemProperty' => [
                        'id' => $property->getItemProperty()->getId(),
                        'name' => $property->getItemProperty()->getName(),
                    ],
                    'value' => $property->getValue(),
                ];
            })->toArray(),
        ];

        $this->View()->assign([
            'success' => true,
            'data' => $responseData,
        ]);
    }

    /**
     * @return StockLedgerEntry
     * @throws ApiException
     */
    protected function findStockLedgerEntryFromRequestParams()
    {
        $stockLedgerEntryId = $this->Request()->getParam('id');
        $stockLedgerEntry = $this->get('models')->find(StockLedgerEntry::class, $stockLedgerEntryId);
        if (!$stockLedgerEntry) {
            throw new ApiException('not_found/stock_leder_entry', 404);
        }

        return $stockLedgerEntry;
    }

    /**
     * @param StockItem $stockItem
     * @param int $itemPropertyId
     * @param string|null $value
     * @return StockItemPropertyValue
     * @throws ApiException
     */
    protected function createStockItemPropertyValue(StockItem $stockItem, $itemPropertyId, $value)
    {
        // Check for an existing property with the same type
        $conflictingPropertyValue = $stockItem->getPropertyValues()->filter(
            function (StockItemPropertyValue $itemProperty) use ($itemPropertyId) {
                return $itemProperty->getItemProperty()->getId() === $itemPropertyId;
            }
        )->first();
        if ($conflictingPropertyValue) {
            throw new ApiException('bad_request/conflicting_item_property', 400);
        }

        // Try to find the item property
        $itemProperty = $this->get('models')->find(ItemProperty::class, $itemPropertyId);
        if (!$itemProperty) {
            throw new ApiException('not_found/item_property', 404);
        }

        // Create new property
        $propertyValue = new StockItemPropertyValue($stockItem, $itemProperty);
        $propertyValue->setValue($value);
        $this->get('models')->persist($propertyValue);

        return $propertyValue;
    }
}
