<?php

namespace App\Http\Controllers\Warehouse\IndirectGoods;

use App\Http\Controllers\Controller;
use App\Models\Warehouse\IndirectGoods\IndirectGoodsInventory;
use App\Models\Warehouse\IndirectGoods\IndirectGoodsProjectInventory;
use App\Models\Warehouse\IndirectGoods\IndirectGoodsStockMovement;
use App\Models\Warehouse\IndirectGoods\IndirectGood;
use App\Models\Warehouse\Project;
use Illuminate\Http\Request;

class IndirectGoodsInventoryController extends Controller
{
    public function __construct()
    {
        $this->middleware('warehouse.access');
        $this->middleware('warehouse.permission:warehouse.indirect-inventory.view')->only(['index', 'projectInventory', 'lowStock', 'stockMovements']);
        $this->middleware('warehouse.permission:warehouse.indirect-inventory.adjust')->only(['adjustments', 'storeAdjustment']);
    }

    public function index(Request $request)
    {
        if ($request->ajax() || $request->expectsJson()) {
            $query = IndirectGoodsInventory::with(['indirectGood.category', 'division', 'supplier']);

            if ($request->filled('search.value') && $request->input('search.value') !== '') {
                $search = $request->input('search.value');
                $query->where(function ($q) use ($search) {
                    $q->where('invoice_number', 'LIKE', "%{$search}%")
                      ->orWhere('batch_number', 'LIKE', "%{$search}%")
                      ->orWhereHas('indirectGood', function ($q2) use ($search) {
                          $q2->where('ig_code', 'LIKE', "%{$search}%")
                             ->orWhere('ig_description', 'LIKE', "%{$search}%");
                      });
                });
            }

            if ($request->filled('status')) {
                $query->where('status', $request->status);
            }

            $totalRecords = IndirectGoodsInventory::count();
            $filteredRecords = $query->count();

            $orderColumn = $request->input('order.0.column', 0);
            $orderDir = $request->input('order.0.dir', 'desc');
            $columns = ['id', 'indirect_good_id', 'invoice_number', 'batch_number', 'quantity_available', 'unit_price', 'total_value', 'status', 'created_at'];
            $orderBy = $columns[$orderColumn] ?? 'created_at';
            $query->orderBy($orderBy, $orderDir);

            $start = $request->input('start', 0);
            $length = $request->input('length', 10);
            $records = $query->skip($start)->take($length)->get();

            return response()->json([
                'draw' => intval($request->input('draw')),
                'recordsTotal' => $totalRecords,
                'recordsFiltered' => $filteredRecords,
                'data' => $records->map(function ($record, $index) use ($start) {
                    return [
                        'DT_RowIndex' => $start + $index + 1,
                        'id' => $record->id,
                        'ig_code' => $record->indirectGood ? $record->indirectGood->ig_code : '-',
                        'ig_description' => $record->indirectGood ? $record->indirectGood->ig_description : '-',
                        'category' => $record->indirectGood && $record->indirectGood->category ? $record->indirectGood->category->category_name : '-',
                        'division' => $record->division ? $record->division->division_name : '-',
                        'supplier' => $record->supplier ? $record->supplier->supplier_name : '-',
                        'invoice_number' => $record->invoice_number ?: '-',
                        'batch_number' => $record->batch_number ?: '-',
                        'quantity_available' => number_format($record->quantity_available, 2),
                        'unit_price' => number_format($record->unit_price, 2),
                        'total_value' => number_format($record->total_value, 2),
                        'expiry_date' => $record->expiry_date ? $record->expiry_date->format('Y-m-d') : '-',
                        'status' => $record->status,
                    ];
                }),
            ]);
        }

        return view('warehouse.indirect-goods.inventory.index');
    }

    public function projectInventory(Request $request)
    {
        if ($request->ajax() || $request->expectsJson()) {
            $query = IndirectGoodsProjectInventory::with(['project', 'indirectGood']);

            if ($request->filled('project_id')) {
                $query->where('project_id', $request->project_id);
            }
            if ($request->filled('search.value') && $request->input('search.value') !== '') {
                $search = $request->input('search.value');
                $query->where(function ($q) use ($search) {
                    $q->where('invoice_number', 'LIKE', "%{$search}%")
                      ->orWhereHas('indirectGood', function ($q2) use ($search) {
                          $q2->where('ig_code', 'LIKE', "%{$search}%")
                             ->orWhere('ig_description', 'LIKE', "%{$search}%");
                      })
                      ->orWhereHas('project', function ($q2) use ($search) {
                          $q2->where('project_name', 'LIKE', "%{$search}%");
                      });
                });
            }

            $totalRecords = IndirectGoodsProjectInventory::count();
            $filteredRecords = $query->count();

            $orderColumn = $request->input('order.0.column', 0);
            $orderDir = $request->input('order.0.dir', 'desc');
            $columns = ['id', 'project_id', 'indirect_good_id', 'invoice_number', 'quantity_available', 'quantity_consumed', 'unit_price', 'total_value'];
            $orderBy = $columns[$orderColumn] ?? 'id';
            $query->orderBy($orderBy, $orderDir);

            $start = $request->input('start', 0);
            $length = $request->input('length', 10);
            $records = $query->skip($start)->take($length)->get();

            return response()->json([
                'draw' => intval($request->input('draw')),
                'recordsTotal' => $totalRecords,
                'recordsFiltered' => $filteredRecords,
                'data' => $records->map(function ($record, $index) use ($start) {
                    return [
                        'DT_RowIndex' => $start + $index + 1,
                        'id' => $record->id,
                        'project' => $record->project ? $record->project->project_name : '-',
                        'ig_code' => $record->indirectGood ? $record->indirectGood->ig_code : '-',
                        'ig_description' => $record->indirectGood ? $record->indirectGood->ig_description : '-',
                        'invoice_number' => $record->invoice_number ?: '-',
                        'batch_number' => $record->batch_number ?: '-',
                        'quantity_available' => number_format($record->quantity_available, 2),
                        'quantity_consumed' => number_format($record->quantity_consumed, 2),
                        'unit_price' => number_format($record->unit_price, 2),
                        'total_value' => number_format($record->total_value, 2),
                    ];
                }),
            ]);
        }

        $projects = Project::orderBy('project_name')->get();
        return view('warehouse.indirect-goods.inventory.project-inventory', compact('projects'));
    }

    public function lowStock()
    {
        $items = IndirectGood::active()
            ->needsReorder()
            ->with(['category', 'unit', 'inventories'])
            ->get()
            ->map(function ($item) {
                return [
                    'id' => $item->id,
                    'ig_code' => $item->ig_code,
                    'ig_description' => $item->ig_description,
                    'category' => $item->category ? $item->category->category_name : '-',
                    'unit' => $item->unit ? $item->unit->unit_symbol : '-',
                    'current_stock' => $item->total_quantity,
                    'reorder_point' => $item->reorder_point,
                    'min_stock_level' => $item->min_stock_level,
                    'status' => $item->is_out_of_stock ? 'out_of_stock' : 'low_stock',
                ];
            });

        return view('warehouse.indirect-goods.inventory.low-stock', compact('items'));
    }

    public function adjustments(Request $request)
    {
        $indirectGoods = IndirectGood::active()->orderBy('ig_description')->get();
        $adjustments = IndirectGoodsStockMovement::where('movement_type', 'adjustment')
            ->with(['indirectGood', 'user'])
            ->orderBy('created_at', 'desc')
            ->paginate(20);

        return view('warehouse.indirect-goods.inventory.adjustments', compact('indirectGoods', 'adjustments'));
    }

    public function storeAdjustment(Request $request)
    {
        $validated = $request->validate([
            'indirect_good_id' => 'required|exists:indirect_goods,id',
            'inventory_id' => 'required|exists:indirect_goods_inventory,id',
            'adjustment_type' => 'required|in:add,subtract',
            'quantity' => 'required|numeric|min:0.01',
            'reason' => 'required|string|max:500',
        ]);

        $inventory = IndirectGoodsInventory::findOrFail($validated['inventory_id']);
        $quantityBefore = $inventory->quantity_available;

        if ($validated['adjustment_type'] === 'subtract' && $inventory->quantity_available < $validated['quantity']) {
            return back()->withInput()->with('error', 'Cannot subtract more than available quantity.');
        }

        $inventory->updateQuantity($validated['quantity'], $inventory->unit_price, $validated['adjustment_type']);

        IndirectGoodsStockMovement::create([
            'indirect_good_id' => $validated['indirect_good_id'],
            'movement_type' => 'adjustment',
            'reference_type' => 'adjustment',
            'reference_id' => $inventory->id,
            'quantity_before' => $quantityBefore,
            'quantity_moved' => $validated['quantity'],
            'quantity_after' => $inventory->quantity_available,
            'invoice_number' => $inventory->invoice_number,
            'user_id' => auth()->id(),
            'notes' => ucfirst($validated['adjustment_type']) . ' adjustment: ' . $validated['reason'],
        ]);

        return back()->with('success', 'Inventory adjustment recorded successfully.');
    }

    public function stockMovements($id)
    {
        $indirectGood = IndirectGood::with('category', 'unit')->findOrFail($id);
        $movements = IndirectGoodsStockMovement::where('indirect_good_id', $id)
            ->with(['user', 'division'])
            ->orderBy('created_at', 'desc')
            ->paginate(30);

        return view('warehouse.indirect-goods.inventory.stock-movements', compact('indirectGood', 'movements'));
    }
}
