<?php

namespace App\Modules\Stock;

use Exception;
use Illuminate\Support\Facades\Event;
use App\Modules\Bookings\Build;

class StockItemsModified
{
    /**
     * The part that was updated.
     *
     * @var \App\Modules\Bookings\Part
     */
    protected $stock;

    /**
     * Subscribe to events.
     *
     * @param  mixed $events
     *
     * @return null
     */
    public function subscribe($events)
    {
        $events->listen('StockItemsModified', 'App\Modules\Stock\StockItemsModified@fire');
    }

    /**
     * Fire the event.
     *
     * @param  \App\Modules\Stock\Stock $stock
     * @param  array 					$oldItems
     *
     * @return bool
     */
    public function fire(Stock $stock, $old_items = [], $new_items = [])
    {
        $this->stock = $stock;
        $this->old_items = $old_items;
        $this->new_items = $new_items;

        $items_to_update = $this->getItemsToUpdate();

        // Create a transaction to update the existing quantity with the components modified
        foreach ($items_to_update as $stock_id => $quantity) {
            $this->createCustomTransaction($stock_id, $quantity * $stock->quantity);
        }

        // Create a transaction for each open build in progress using this item. 
        foreach (Build::query()->where('stock_id', $stock->id)->where('status', 'in_progress')->get() as $build) {
            foreach ($items_to_update as $stock_id => $quantity) {
                $this->createBuildTransaction($build, $stock_id, $quantity * $build->quantity);
            }
        }

        return true;
    }

    /**
     * @param  array $oldItems
     * @param  \App\Modules\Stock\Stock $stock
     *
     * @return array 
     */
    protected function getItemsToUpdate()
    {
        $items_to_update = [];

        $items = array_merge(array_keys($this->old_items), array_keys($this->new_items));
        foreach ($items as $id) {
            if (! isset($this->old_items[$id]) && isset($this->new_items[$id])) {
                // Item was added - subtract from stock
                $quantity = is_array($this->new_items[$id]) ? $this->new_items[$id]['quantity'] : $this->new_items[$id];
                $items_to_update[$id] = -1 * $quantity;
            } elseif (isset($this->old_items[$id]) && ! isset($this->new_items[$id])) {
                // Item was removed - add back to stock
                $quantity = is_array($this->old_items[$id]) ? $this->old_items[$id]['quantity'] : $this->old_items[$id];
                $items_to_update[$id] = $quantity;
            } elseif (isset($this->old_items[$id]) && isset($this->new_items[$id]) && $this->old_items[$id] != $this->new_items[$id]) {
                // Item quantity changed
                $old_quantity = is_array($this->old_items[$id]) ? $this->old_items[$id]['quantity'] : $this->old_items[$id];
                $new_quantity = is_array($this->new_items[$id]) ? $this->new_items[$id]['quantity'] : $this->new_items[$id];
                $items_to_update[$id] = $old_quantity - $new_quantity;
            }
        }

        return $items_to_update;
    }

    protected function createBuildTransaction(Build $build, $stock_id, $quantity)
    {
        $transaction = StockTransaction::create([
            'stock_id'     => $stock_id,
            'related_type' => $build->related_type,
            'related_id'   => $build->related_id,
            'quantity'     => $quantity,
        ]);

        if (! $transaction->exists) {
            throw new Exception('Failed to create stock transaction');
        }

        return true;
    }

    protected function createCustomTransaction($stock_id, $quantity)
    {
        $transaction = StockTransaction::create([
            'stock_id'     => $stock_id,
            'related_type' => 'custom',
            'reason'       => 'Build Components Modified',
            'quantity'     => $quantity,
        ]);

        if (! $transaction->exists) {
            throw new Exception('Failed to create stock transaction');
        }

        return true;
    }
}
