<?php

namespace App\Controllers;

use App\Models\InventoryItemModel;
use App\Models\InventoryTransactionModel;
use Config\Lookups;

/**
 * Inventory module — built for real from a user-supplied mockup
 * (previously a disabled "Soon" nav item). The mockup's "Stock Value
 * Trend" line chart implied history this app didn't keep at the time —
 * now real, via the inventory_transactions ledger (Phase 5), so the
 * chart shows actual daily net stock-value movement rather than a
 * fabricated series. "Pending Orders" would need a purchase-order
 * workflow that still doesn't exist — that stat stays dropped rather
 * than faked; "Value by Category" (computable from current stock) fills
 * its place instead.
 */
class InventoryController extends BaseController
{
    public function index()
    {
        $items = new InventoryItemModel();

        return view('inventory/index', [
            'pageTitle'    => 'Inventory',
            'pageSubtitle' => 'Track stock, monitor levels and manage supplies.',
            'items'        => $items->orderBy('name')->findAll(),
            'lowStock'     => (new InventoryItemModel())->lowStock(),
            'valueByCategory' => (new InventoryItemModel())->valueByCategory(),
            'valueTrend'   => (new InventoryTransactionModel())->dailyNetValueTrend(30),
            'stats'        => [
                'totalItems'    => (new InventoryItemModel())->countAllResults(),
                'lowStockCount' => (new InventoryItemModel())->countLowStock(),
                'totalValue'    => (new InventoryItemModel())->totalValue(),
                'categories'    => (new InventoryItemModel())->countCategories(),
            ],
            'lookups' => new Lookups(),
        ]);
    }

    public function show(int $id)
    {
        $item = (new InventoryItemModel())->find($id);

        if ($item === null) {
            return redirect()->to('inventory')->with('error', 'Item not found.');
        }

        return view('inventory/show', [
            'pageTitle' => $item->name,
            'item'      => $item,
            'stockValue' => money_multiply($item->unit_cost, (int) $item->quantity_in_stock),
            'transactions' => (new InventoryTransactionModel())->forItem($id),
            'lookups'   => new Lookups(),
        ]);
    }

    /** A delivery arriving — increases stock, logged against the ledger. */
    public function receiveStock(int $id)
    {
        $items = new InventoryItemModel();
        $item  = $items->find($id);

        if ($item === null) {
            return redirect()->to('inventory')->with('error', 'Item not found.');
        }

        $quantity = (int) $this->request->getPost('quantity');

        if ($quantity <= 0) {
            return redirect()->to('inventory/' . $id)->with('error', 'Enter a quantity greater than zero.');
        }

        $reference = $this->request->getPost('reference') ?: null;
        $items->receiveStock($id, $quantity, $reference, $this->currentUserId());

        $this->logActivity('inventory', "Received {$quantity} {$item->unit} of \"{$item->name}\"" . ($reference ? " ({$reference})" : '') . '.');

        return redirect()->to('inventory/' . $id)->with('success', 'Stock received.');
    }

    /** Stock going out (used, not sold) — decreases stock, clamped at zero, logged against the ledger. */
    public function consumeStock(int $id)
    {
        $items = new InventoryItemModel();
        $item  = $items->find($id);

        if ($item === null) {
            return redirect()->to('inventory')->with('error', 'Item not found.');
        }

        $quantity = (int) $this->request->getPost('quantity');

        if ($quantity <= 0) {
            return redirect()->to('inventory/' . $id)->with('error', 'Enter a quantity greater than zero.');
        }

        $reference = $this->request->getPost('reference') ?: null;
        $items->consumeStock($id, $quantity, $reference, $this->currentUserId());

        $this->logActivity('inventory', "Logged {$quantity} {$item->unit} of \"{$item->name}\" consumed" . ($reference ? " ({$reference})" : '') . '.');

        return redirect()->to('inventory/' . $id)->with('success', 'Consumption logged.');
    }

    /** A manual correction (stock count, damage, etc.) to an exact new quantity. */
    public function adjustStock(int $id)
    {
        $items = new InventoryItemModel();
        $item  = $items->find($id);

        if ($item === null) {
            return redirect()->to('inventory')->with('error', 'Item not found.');
        }

        $newQuantity = $this->request->getPost('new_quantity');

        if ($newQuantity === null || $newQuantity === '' || (int) $newQuantity < 0) {
            return redirect()->to('inventory/' . $id)->with('error', 'Enter a valid new quantity.');
        }

        $reference = $this->request->getPost('reference') ?: null;
        $items->adjustStock($id, (int) $newQuantity, $reference, $this->currentUserId());

        $this->logActivity('inventory', "Adjusted \"{$item->name}\" stock to {$newQuantity} {$item->unit}" . ($reference ? " ({$reference})" : '') . '.');

        return redirect()->to('inventory/' . $id)->with('success', 'Stock adjusted.');
    }

    public function new()
    {
        return view('inventory/form', [
            'pageTitle' => 'New Inventory Item',
            'item'      => null,
            'lookups'   => new Lookups(),
        ]);
    }

    public function create()
    {
        return $this->save(new InventoryItemModel());
    }

    public function edit(int $id)
    {
        $item = (new InventoryItemModel())->find($id);

        if ($item === null) {
            return redirect()->to('inventory')->with('error', 'Item not found.');
        }

        return view('inventory/form', [
            'pageTitle' => 'Edit Inventory Item',
            'item'      => $item,
            'lookups'   => new Lookups(),
        ]);
    }

    public function update(int $id)
    {
        $items = new InventoryItemModel();

        if ($items->find($id) === null) {
            return redirect()->to('inventory')->with('error', 'Item not found.');
        }

        return $this->save($items, $id);
    }

    private function save(InventoryItemModel $items, ?int $id = null)
    {
        $data = [
            'name'              => $this->request->getPost('name'),
            'category'          => $this->request->getPost('category'),
            'quantity_in_stock' => (int) $this->request->getPost('quantity_in_stock'),
            'unit'              => $this->request->getPost('unit'),
            'unit_cost'         => parse_money($this->request->getPost('unit_cost') ?: '0'),
            'reorder_level'     => (int) $this->request->getPost('reorder_level'),
        ];

        $ok = $id === null ? $items->insert($data) : $items->update($id, $data);

        if ($ok === false) {
            return $this->redirectWithModelErrors($items);
        }

        $this->logActivity('inventory', ($id === null ? 'Added' : 'Updated') . " inventory item \"{$data['name']}\".");

        return redirect()->to('inventory')->with('success', 'Item saved.');
    }

    public function delete(int $id)
    {
        $items = new InventoryItemModel();
        $item  = $items->find($id);

        if ($item === null) {
            return redirect()->to('inventory')->with('error', 'Item not found.');
        }

        $items->delete($id);
        $this->logActivity('inventory', "Deleted inventory item \"{$item->name}\".");

        return redirect()->to('inventory')->with('success', 'Item deleted.');
    }
}
