<?php

namespace Modules\Inventory\Controllers;

use core\Controller;
use core\Auth;
use core\Database;

class StockController extends Controller
{
    public function transfers(): void
    {
        $this->requirePermission('inventory_view');

        $search = $this->request->get('search', '');
        $page = max(1, (int)$this->request->get('page', 1));
        $perPage = PAGINATION_LIMIT;
        $db = Database::getInstance();

        $branches = $db->table('branches')
            ->where('deleted_at', 'IS', null)
            ->orderBy('name', 'ASC')
            ->get();

        $query = $db->table('stock_transfers st')
            ->select('st.*, 
                     fb.name as from_branch_name, tb.name as to_branch_name,
                     u.first_name as user_first_name, u.last_name as user_last_name')
            ->leftJoin('branches fb', 'st.from_branch_id', '=', 'fb.id')
            ->leftJoin('branches tb', 'st.to_branch_id', '=', 'tb.id')
            ->leftJoin('users u', 'st.created_by', '=', 'u.id')
            ->where('st.deleted_at', 'IS', null);

        if (!empty($search)) {
            $query->where(function ($q) use ($search) {
                $q->where('st.reference', 'LIKE', '%' . $search . '%');
            });
        }

        $transfers = $query->orderBy('st.created_at', 'DESC')
            ->paginate($perPage, $page);

        $products = $db->table('products')
            ->where('deleted_at', 'IS', null)
            ->where('is_active', 1)
            ->where('track_inventory', 1)
            ->orderBy('name', 'ASC')
            ->get();

        $this->view('Inventory/stock/transfers', [
            'title' => 'Stock Transfers',
            'breadcrumb' => [
                'Inventory' => url('inventory'),
                'Stock Transfers' => url('stock/transfers'),
            ],
            'transfers' => $transfers,
            'branches' => $branches,
            'products' => $products,
            'search' => $search,
        ]);
    }

    public function storeTransfer(): void
    {
        $this->requirePermission('inventory_create');

        $validated = $this->validate([
            'from_branch_id' => 'required|integer',
            'to_branch_id' => 'required|integer',
            'notes' => 'max_length:2000',
            'items' => 'required',
        ]);

        if ($validated['from_branch_id'] === $validated['to_branch_id']) {
            $this->redirectWith(url('stock/transfers'), 'error', 'Source and destination branches must be different.');
        }

        $items = $this->request->get('items', []);
        if (empty($items) || !is_array($items)) {
            $this->redirectWith(url('stock/transfers'), 'error', 'At least one item is required.');
        }

        $db = Database::getInstance();
        $db->beginTransaction();

        try {
            $reference = 'ST-' . date('Ymd') . '-' . strtoupper(substr(uniqid(), -6));

            $transferId = $db->table('stock_transfers')->insert([
                'reference' => $reference,
                'from_branch_id' => (int)$validated['from_branch_id'],
                'to_branch_id' => (int)$validated['to_branch_id'],
                'status' => 'completed',
                'notes' => $validated['notes'] ?? '',
                'created_by' => Auth::id(),
                'created_at' => date(DATE_TIME_FORMAT),
                'updated_at' => date(DATE_TIME_FORMAT),
            ]);

            foreach ($items as $item) {
                if (empty($item['product_id']) || empty($item['quantity'])) {
                    continue;
                }

                $quantity = (int)$item['quantity'];
                $productId = (int)$item['product_id'];

                $product = $db->table('products')->where('id', $productId)->first();
                if (!$product) {
                    continue;
                }

                if ($product->current_stock < $quantity) {
                    throw new \RuntimeException("Insufficient stock for product: {$product->name}. Available: {$product->current_stock}, Requested: {$quantity}");
                }

                $db->table('stock_transfer_items')->insert([
                    'stock_transfer_id' => $transferId,
                    'product_id' => $productId,
                    'quantity' => $quantity,
                    'created_at' => date(DATE_TIME_FORMAT),
                ]);

                $db->table('products')
                    ->where('id', $productId)
                    ->update([
                        'current_stock' => $product->current_stock - $quantity,
                        'updated_at' => date(DATE_TIME_FORMAT),
                    ]);

                $db->table('stock_movements')->insert([
                    'product_id' => $productId,
                    'type' => 'transfer_out',
                    'quantity' => -$quantity,
                    'reference_type' => 'stock_transfer',
                    'reference_id' => $transferId,
                    'notes' => 'Transfer out to branch #' . $validated['to_branch_id'] . ' ref: ' . $reference,
                    'created_by' => Auth::id(),
                    'created_at' => date(DATE_TIME_FORMAT),
                ]);
            }

            $db->commit();
            $this->logActivity('stock_transfer', 'Created stock transfer: ' . $reference);

            $this->redirectWith(url('stock/transfers'), 'success', 'Stock transfer completed successfully.');
        } catch (\Throwable $e) {
            $db->rollback();
            $this->redirectWith(url('stock/transfers'), 'error', $e->getMessage());
        }
    }

    public function adjustments(): void
    {
        $this->requirePermission('inventory_view');

        $search = $this->request->get('search', '');
        $type = $this->request->get('type', '');
        $page = max(1, (int)$this->request->get('page', 1));
        $perPage = PAGINATION_LIMIT;
        $db = Database::getInstance();

        $query = $db->table('stock_adjustments sa')
            ->select('sa.*, p.name as product_name, p.sku,
                     u.first_name as user_first_name, u.last_name as user_last_name')
            ->leftJoin('products p', 'sa.product_id', '=', 'p.id')
            ->leftJoin('users u', 'sa.created_by', '=', 'u.id');

        if (!empty($search)) {
            $query->where(function ($q) use ($search) {
                $q->where('p.name', 'LIKE', '%' . $search . '%')
                  ->orWhere('p.sku', 'LIKE', '%' . $search . '%')
                  ->orWhere('sa.reason', 'LIKE', '%' . $search . '%');
            });
        }

        if (!empty($type)) {
            $query->where('sa.adjustment_type', $type);
        }

        $adjustments = $query->orderBy('sa.created_at', 'DESC')
            ->paginate($perPage, $page);

        $products = $db->table('products')
            ->where('deleted_at', 'IS', null)
            ->where('is_active', 1)
            ->where('track_inventory', 1)
            ->orderBy('name', 'ASC')
            ->get();

        $this->view('Inventory/stock/adjustments', [
            'title' => 'Stock Adjustments',
            'breadcrumb' => [
                'Inventory' => url('inventory'),
                'Stock Adjustments' => url('stock/adjustments'),
            ],
            'adjustments' => $adjustments,
            'products' => $products,
            'search' => $search,
            'type' => $type,
        ]);
    }

    public function storeAdjustment(): void
    {
        $this->requirePermission('inventory_edit');

        $validated = $this->validate([
            'product_id' => 'required|integer',
            'adjustment_type' => 'required|in:addition,deduction,correction',
            'quantity' => 'required|integer|min:1',
            'reason' => 'required|max_length:1000',
            'reference' => 'max_length:255',
        ]);

        $db = Database::getInstance();
        $db->beginTransaction();

        try {
            $product = $db->table('products')
                ->where('id', (int)$validated['product_id'])
                ->where('deleted_at', 'IS', null)
                ->first();

            if (!$product) {
                throw new \RuntimeException('Product not found.');
            }

            $quantity = (int)$validated['quantity'];
            $adjustmentType = $validated['adjustment_type'];
            $stockChange = 0;

            switch ($adjustmentType) {
                case 'addition':
                    $stockChange = $quantity;
                    break;
                case 'deduction':
                    $stockChange = -$quantity;
                    break;
                case 'correction':
                    $stockChange = $quantity - $product->current_stock;
                    break;
            }

            $newStock = $product->current_stock + $stockChange;
            if ($newStock < 0) {
                throw new \RuntimeException('Insufficient stock. Current: ' . $product->current_stock . ', Adjustment would result in negative stock.');
            }

            $adjustmentId = $db->table('stock_adjustments')->insert([
                'product_id' => (int)$validated['product_id'],
                'adjustment_type' => $adjustmentType,
                'quantity' => $quantity,
                'stock_before' => $product->current_stock,
                'stock_after' => $newStock,
                'reason' => $validated['reason'],
                'reference' => $validated['reference'] ?? '',
                'created_by' => Auth::id(),
                'created_at' => date(DATE_TIME_FORMAT),
                'updated_at' => date(DATE_TIME_FORMAT),
            ]);

            $db->table('products')
                ->where('id', (int)$validated['product_id'])
                ->update([
                    'current_stock' => $newStock,
                    'updated_at' => date(DATE_TIME_FORMAT),
                ]);

            $db->table('stock_movements')->insert([
                'product_id' => (int)$validated['product_id'],
                'type' => 'adjustment_' . $adjustmentType,
                'quantity' => $stockChange,
                'reference_type' => 'stock_adjustment',
                'reference_id' => $adjustmentId,
                'notes' => $validated['reason'],
                'created_by' => Auth::id(),
                'created_at' => date(DATE_TIME_FORMAT),
            ]);

            $db->commit();

            $this->logActivity('stock_adjustment', 'Stock adjustment for ' . $product->name . ': ' . $adjustmentType . ' (' . $quantity . ')');
            $this->logAudit('stock_adjustment', 'stock_adjustments', $adjustmentId, 
                ['product_id' => $product->id, 'stock_before' => $product->current_stock],
                ['product_id' => $product->id, 'stock_after' => $newStock]);

            $this->redirectWith(url('stock/adjustments'), 'success', 'Stock adjustment recorded successfully.');
        } catch (\Throwable $e) {
            $db->rollback();
            $this->redirectWith(url('stock/adjustments'), 'error', $e->getMessage());
        }
    }
}
