<?php

namespace App\Http\Controllers\Warehouse;

use App\Http\Controllers\Controller;
use App\Models\Warehouse\OutgoingTransaction;
use App\Models\Warehouse\Project;
use App\Models\Warehouse\ProjectDivision;
use App\Models\Department;
use App\Models\User;
use App\Models\Warehouse\IndirectGoods\IndirectGood;
use App\Models\Warehouse\IndirectGoods\IndirectGoodsRequest;
use App\Models\Warehouse\IndirectGoods\IndirectGoodsRequestItem;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class OutgoingTransactionController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        $query = OutgoingTransaction::with(['project', 'division', 'requester', 'approver', 'items'])
                                   ->latest('transaction_date');

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

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

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

        if ($request->filled('date_from')) {
            $query->where('transaction_date', '>=', $request->date_from);
        }

        if ($request->filled('date_to')) {
            $query->where('transaction_date', '<=', $request->date_to);
        }

        $transactions = $query->paginate(15);

        // Get statistics (total counts from database, not paginated collection)
        $stats = [
            'total' => OutgoingTransaction::count(),
            'pending' => OutgoingTransaction::where('status', 'pending')->count(),
            'approved' => OutgoingTransaction::where('status', 'approved')->count(),
            'completed' => OutgoingTransaction::whereIn('status', ['completed', 'dispatched', 'delivered', 'successful'])->count(),
        ];

        // Get filter options
        $projects = Project::all();
        $divisions = ProjectDivision::where('status', 'active')
            ->orderBy('division_name')
            ->get(['id', 'division_name', 'division_code']);

        return view('warehouse.outgoing.index', compact(
            'transactions', 'projects', 'divisions', 'stats'
        ));
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        $projects = Project::all();
        $divisions = ProjectDivision::where('status', 'active')
            ->orderBy('division_name')
            ->get(['id', 'division_name', 'division_code']);
        $users = User::where('status', 'active')
            ->orderBy('name')
            ->get();

        // Don't load all items - use lazy loading instead
        return view('warehouse.outgoing.create', compact(
            'projects', 'divisions', 'users'
        ));
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        $request->validate([
            'request_date' => 'required|date',
            'project_id' => 'required|exists:projects,id',
            'material_request_number' => 'required|string|max:255',
            'requested_by' => 'required|exists:users,id',
            'request_file' => 'nullable|file|max:10240|mimes:pdf,doc,docx,jpg,jpeg,png',
            'items' => 'required|array|min:1',
            'items.*.goods_type' => 'required|in:direct,indirect',
            'items.*.item_id' => 'required|string',
            'items.*.quantity_requested' => 'required|numeric|min:0.01',
        ]);

        $requestItems = collect($request->items)->map(function ($item) {
            $goodsType = $item['goods_type'];
            $rawItemId = (string) $item['item_id'];

            if (str_contains($rawItemId, ':')) {
                [$prefixedGoodsType, $itemId] = explode(':', $rawItemId, 2);
                $goodsType = $prefixedGoodsType;
            } else {
                $itemId = $rawItemId;
            }

            return [
                'goods_type' => $goodsType,
                'item_id' => (int) $itemId,
                'quantity_requested' => $item['quantity_requested'],
            ];
        });

        $directItems = $requestItems->where('goods_type', 'direct')->values();
        $indirectItems = $requestItems->where('goods_type', 'indirect')->values();

        foreach ($directItems as $itemData) {
            if (!\App\Models\Warehouse\Item::whereKey($itemData['item_id'])->exists()) {
                return back()->withInput()->withErrors(['items' => 'One or more selected direct goods are invalid.']);
            }
        }

        foreach ($indirectItems as $itemData) {
            if (!IndirectGood::whereKey($itemData['item_id'])->exists()) {
                return back()->withInput()->withErrors(['items' => 'One or more selected indirect goods are invalid.']);
            }
        }

        return DB::transaction(function () use ($request, $directItems, $indirectItems) {
            // Get project to determine division
            $project = \App\Models\Warehouse\Project::findOrFail($request->project_id);
            $divisionId = $project->division_id ?? $project->project_division_id ?? null;

            // Handle file upload
            $requestFile = null;
            if ($request->hasFile('request_file')) {
                $file = $request->file('request_file');
                $filename = 'request_' . time() . '_' . $file->getClientOriginalName();
                $uploadPath = 'uploads/material-requests';

                // Create directory if it doesn't exist
                $fullPath = public_path($uploadPath);
                if (!file_exists($fullPath)) {
                    mkdir($fullPath, 0755, true);
                }

                // Move file to public directory
                $file->move($fullPath, $filename);
                $requestFile = $uploadPath . '/' . $filename;
            }

            $createdDirectRequest = null;
            $createdIndirectRequest = null;

            if ($directItems->isNotEmpty()) {
                // Create outgoing transaction (pending decision)
                $createdDirectRequest = \App\Models\Warehouse\OutgoingTransaction::create([
                    'transaction_date' => $request->request_date,
                    'project_id' => $request->project_id,
                    'division_id' => $divisionId,
                    'material_request_number' => $request->material_request_number,
                    'type_of_goods' => $indirectItems->isNotEmpty() ? 'Material Request - Direct Goods' : 'Material Request',
                    'requested_by' => $request->requested_by,
                    'status' => 'pending', // Will be processed in Material Issue Decision Center
                    'notes' => $request->notes ?? 'Pending fulfillment decision',
                    'request_file' => $requestFile,
                ]);

                // Create transaction items
                foreach ($directItems as $itemData) {
                    $item = \App\Models\Warehouse\Item::findOrFail($itemData['item_id']);

                    // Get average unit price from inventory
                    $averagePrice = \App\Models\Warehouse\Inventory::where('item_id', $item->id)
                        ->where('quantity_available', '>', 0)
                        ->avg('unit_price') ?: 0;

                    \App\Models\Warehouse\OutgoingItem::create([
                        'outgoing_transaction_id' => $createdDirectRequest->id,
                        'item_id' => $item->id,
                        'division_id' => $divisionId,
                        'quantity_requested' => $itemData['quantity_requested'],
                        'quantity_released' => 0, // Will be filled during decision processing
                        'unit_price' => $averagePrice,
                    ]);
                }
            }

            if ($indirectItems->isNotEmpty()) {
                $indirectRequestNumber = $request->material_request_number . '-IG';
                if (IndirectGoodsRequest::where('request_number', $indirectRequestNumber)->exists()) {
                    $indirectRequestNumber .= '-' . now()->format('His');
                }

                $createdIndirectRequest = IndirectGoodsRequest::create([
                    'request_number' => $indirectRequestNumber,
                    'request_date' => $request->request_date,
                    'project_id' => $request->project_id,
                    'division_id' => $divisionId,
                    'status' => 'approved',
                    'requires_approval' => false,
                    'requested_by' => $request->requested_by,
                    'approved_by' => auth()->id(),
                    'approved_at' => now(),
                    'receiver_name' => null,
                    'notes' => trim(($request->notes ? $request->notes . "\n\n" : '') . 'Created from Material Request ' . $request->material_request_number . '. Indirect goods are issued without return tracking.'),
                    'request_file' => $requestFile,
                ]);

                foreach ($indirectItems as $itemData) {
                    IndirectGoodsRequestItem::create([
                        'indirect_goods_request_id' => $createdIndirectRequest->id,
                        'indirect_good_id' => $itemData['item_id'],
                        'quantity_requested' => $itemData['quantity_requested'],
                        'quantity_released' => 0,
                        'quantity_balance' => $itemData['quantity_requested'],
                        'unit_price' => 0,
                        'total_price' => 0,
                        'notes' => 'Created from Material Request ' . $request->material_request_number,
                    ]);
                }
            }

            $message = 'Material request created successfully.';
            if ($createdDirectRequest && $createdIndirectRequest) {
                $message .= ' Direct goods are pending fulfillment decision; indirect goods were created as approved request ' . $createdIndirectRequest->request_number . ' for issue without returns.';
            } elseif ($createdDirectRequest) {
                $message .= ' Your request is now pending approval.';
            } elseif ($createdIndirectRequest) {
                $message .= ' Indirect goods request ' . $createdIndirectRequest->request_number . ' is approved and ready to issue without returns.';
            }

            if (!$createdDirectRequest && $createdIndirectRequest) {
                return redirect()->route('warehouse.indirect-goods.requests.show', $createdIndirectRequest->id)
                    ->with('success', $message);
            }

            return redirect()->route('warehouse.inventory.material-requests')
                ->with('success', $message);
        });
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        $transaction = OutgoingTransaction::with(['project', 'division', 'requester', 'approver', 'items.item'])
                                         ->findOrFail($id);

        return view('warehouse.outgoing.show', compact('transaction'));
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(string $id)
    {
        $transaction = OutgoingTransaction::with(['items.item'])->findOrFail($id);

        if ($transaction->status === 'completed') {
            return back()->with('error', 'Cannot edit completed transactions.');
        }

        $projects = Project::all();
        $divisions = Department::where('is_active', true)->get();
        $users = User::where('status', 'active')
            ->orderBy('name')
            ->get();

        return view('warehouse.outgoing.edit', compact(
            'transaction', 'projects', 'divisions', 'users'
        ));
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id)
    {
        $transaction = OutgoingTransaction::findOrFail($id);

        if ($transaction->status === 'completed') {
            return back()->with('error', 'Cannot update completed transactions.');
        }

        $request->validate([
            'transaction_date' => 'required|date',
            'project_id' => 'required|exists:projects,id',
            'division_id' => 'required|exists:project_divisions,id',
            'material_request_number' => 'nullable|string|max:255',
            'type_of_goods' => 'required|string|max:255',
            'requested_by' => 'required|exists:users,id',
            'receiver_name' => 'required|string|max:255',
            'notes' => 'nullable|string',
        ]);

        $transaction->update($request->validated());

        return redirect()->route('warehouse.outgoing.show', $transaction)
                        ->with('success', 'Outgoing transaction updated successfully.');
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id)
    {
        $transaction = OutgoingTransaction::findOrFail($id);

        if ($transaction->status === 'completed') {
            return back()->with('error', 'Cannot delete completed transactions.');
        }

        $transaction->delete();

        return redirect()->route('warehouse.outgoing.index')
                        ->with('success', 'Outgoing transaction deleted successfully.');
    }

    /**
     * Search items for AJAX dropdown (lazy loading)
     */
    public function searchItems(Request $request)
    {
        $search = $request->get('q', '');
        $page = $request->get('page', 1);
        $perPage = 20;
        $directQuery = \App\Models\Warehouse\Item::active()
            ->with(['inventories' => function($query) {
                $query->where('quantity_available', '>', 0);
            }]);

        if (!empty($search)) {
            $directQuery->where(function($q) use ($search) {
                $q->where('item_code', 'LIKE', "%{$search}%")
                  ->orWhere('item_description', 'LIKE', "%{$search}%");
            });
        }

        $indirectQuery = IndirectGood::active()
            ->with(['inventories' => function($query) {
                $query->where('quantity_available', '>', 0);
            }]);

        if (!empty($search)) {
            $indirectQuery->where(function($q) use ($search) {
                $q->where('ig_code', 'LIKE', "%{$search}%")
                  ->orWhere('ig_description', 'LIKE', "%{$search}%");
            });
        }

        $directResults = $directQuery->limit($perPage)->get()->map(function($item) {
            $currentStock = $item->inventories->sum('quantity_available');
            return [
                'id' => 'direct:' . $item->id,
                'text' => "{$item->item_code} - {$item->item_description} (Direct Goods)",
                'item_code' => $item->item_code,
                'item_description' => $item->item_description,
                'unit_of_measure' => $item->unit_of_measure,
                'current_stock' => $currentStock,
                'goods_type' => 'direct',
            ];
        });

        $indirectResults = $indirectQuery->limit($perPage)->get()->map(function($item) {
            $currentStock = $item->inventories->sum('quantity_available');
            return [
                'id' => 'indirect:' . $item->id,
                'text' => "{$item->ig_code} - {$item->ig_description} (Indirect Goods)",
                'item_code' => $item->ig_code,
                'item_description' => $item->ig_description,
                'unit_of_measure' => $item->unit_of_measure,
                'current_stock' => $currentStock,
                'goods_type' => 'indirect',
            ];
        });

        $results = $directResults
            ->concat($indirectResults)
            ->sortBy('text', SORT_NATURAL | SORT_FLAG_CASE)
            ->values()
            ->take($perPage);

        return response()->json([
            'results' => $results,
            'pagination' => [
                'more' => false
            ]
        ]);
    }

    /**
     * Show pending approval transactions.
     */
    public function pendingApproval()
    {
        $transactions = OutgoingTransaction::with(['project', 'division', 'requester', 'items'])
                                          ->where('status', 'pending')
                                          ->latest('transaction_date')
                                          ->paginate(15);

        return view('warehouse.outgoing.pending-approval', compact('transactions'));
    }

    /**
     * Approve a transaction.
     */
    public function approve(Request $request, string $id)
    {
        $transaction = OutgoingTransaction::findOrFail($id);

        if ($transaction->status !== 'pending') {
            return back()->with('error', 'Only pending transactions can be approved.');
        }

        $transaction->approve(auth()->id());

        return back()->with('success', 'Transaction approved successfully.');
    }

    /**
     * Dispatch a transaction.
     */
    public function dispatch(string $id)
    {
        $transaction = OutgoingTransaction::findOrFail($id);

        if ($transaction->status !== 'approved') {
            return back()->with('error', 'Only approved transactions can be dispatched.');
        }

        if (!$transaction->can_be_fulfilled) {
            return back()->with('error', 'Insufficient inventory to fulfill this transaction.');
        }

        $transaction->complete();

        return back()->with('success', 'Transaction dispatched and inventory updated successfully.');
    }
}
