<?php

namespace App\Http\Controllers;

use App\Http\Requests\Qc\StoreQcRequest;
use App\Models\Qc;
use App\Models\QcItem;
use App\Models\Grn;
use App\Models\GatePass;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderItem;
use App\Models\Account;
use App\Services\QcService;
use App\Services\WarehouseService;
use App\Services\StockAccountingService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Yajra\DataTables\Facades\DataTables;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class QcController extends Controller
{
    protected $stockAccountingService;
    protected QcService $qcService;
    protected WarehouseService $warehouseService;

    public function __construct(StockAccountingService $stockAccountingService, QcService $qcService, WarehouseService $warehouseService)
    {
        $this->stockAccountingService = $stockAccountingService;
        $this->qcService = $qcService;
        $this->warehouseService = $warehouseService;
    }
    /**
     * Search QCs for filter dropdown
     */
    public function filterPoSearch(Request $request): JsonResponse
    {
        try {
            $search = $request->input('q', '');

            $pos = \App\Models\PurchaseOrder::where('po_number', 'like', "%{$search}%")
                ->with(['supplier'])
                ->limit(10)
                ->get()
                ->map(function($po) {
                    return [
                        'id' => $po->id,
                        'text' => $po->po_number
                    ];
                });

            return response()->json([
                'results' => $pos
            ]);
        } catch (\Exception $e) {
            \Log::error('PO filter search failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return response()->json([
                'results' => []
            ]);
        }
    }
 public function filterIgpSearch(Request $request): JsonResponse
{
    try {
        $search = trim($request->input('q', ''));

        $igps = \App\Models\GatePass::query()
            ->when($search, function ($query) use ($search) {
                $query->where('gate_pass_number', 'like', "%{$search}%");
            })
            ->with(['purchaseOrder.supplier']) // assuming these relations exist
            ->limit(10)
            ->get()
            ->map(function ($igp) {
                return [
                    'id' => $igp->id,
                    'gate_pass_number' => $igp->gate_pass_number,
                    // 'po_number' => $igp->purchaseOrder->po_number ?? 'N/A',
                    // 'vendor_name' => $igp->purchaseOrder->supplier->name ?? 'N/A',
                    'text' => "{$igp->gate_pass_number} "
                ];
            });

        return response()->json([
            'results' => $igps
        ]);

    } catch (\Exception $e) {
        \Log::error('IGP filter search failed', [
            'error' => $e->getMessage(),
            'trace' => $e->getTraceAsString(),
        ]);

        return response()->json(['results' => []]);
    }
}



    public function filterSearch(Request $request): JsonResponse
    {
        try {
            $search = $request->input('q', '');

            $qcs = Qc::where('qc_number', 'like', "%{$search}%")
                ->with(['igp.purchaseOrder.supplier'])
                ->limit(10)
                ->get()
                ->map(function($qc) {
                    return [
                        'id' => $qc->id,
                        'text' => $qc->qc_number
                                // ($qc->igp ? $qc->igp->gate_pass_number : 'N/A') . ' - ' .
                                // ($qc->igp && $qc->igp->purchaseOrder ? $qc->igp->purchaseOrder->po_number : 'N/A')
                    ];
                });

            return response()->json([
                'results' => $qcs
            ]);
        } catch (\Exception $e) {
            \Log::error('QC filter search failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return response()->json([
                'results' => []
            ]);
        }
    }

    /**
     * Display QC index or return data for AJAX
     */
    public function index(Request $request)
    {
        // If it's an AJAX request, return JSON data for DataTables
        if ($request->ajax()) {
            $query = Qc::with(['igp.purchaseOrder.vendor', 'inspector'])
                ->select('qcs.*');

            // Apply filters
            if ($request->filled('qc_id')) {
                $query->where('id', 'like', '%' . $request->qc_id . '%');
            }

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

            if ($request->filled('po_id')) {
                $query->whereHas('igp', function($q) use ($request) {
                    $q->where('purchase_order_id', $request->po_id);
                });
            }

            // if ($request->filled('supplier_id')) {
            //     $query->whereHas('igp.purchaseOrder', function($q) use ($request) {
            //         $q->where('vendor_id', $request->supplier_id);
            //     });
            // }

            if ($request->filled('date_from') && $request->filled('date_to')) {
                $query->whereBetween('created_at', [
                    $request->date_from . ' 00:00:00',
                    $request->date_to . ' 23:59:59'
                ]);
            }

            $query->orderBy('qcs.created_at', 'desc');

            try {
                return DataTables::of($query)
                    ->addColumn('po_number', function ($qc) {
                        return $qc->igp && $qc->igp->purchaseOrder
                            ? $qc->igp->purchaseOrder->po_number
                            : 'N/A';
                    })
                    ->addColumn('igp_number', function ($qc) {
                        return $qc->igp
                            ? $qc->igp->gate_pass_number
                            : 'N/A';
                    })
                    ->addColumn('vendor_name', function ($qc) {
    return optional($qc->igp->purchaseOrder->vendor)->name ?? 'N/A';
})
                    ->addColumn('inspector_name', function ($qc) {
                        return optional($qc->inspector)->name ?? 'N/A';
                    })
                    ->addColumn('actions', function ($qc) {
                        return view('qcs.partials.actions', compact('qc'))->render();
                    })
                    ->editColumn('created_at', function ($qc) {
                        return $qc->created_at ? $qc->created_at->format('Y-m-d H:i:s') : 'N/A';
                    })
                    ->rawColumns(['actions'])
                    ->make(true);
            } catch (\Exception $e) {
                \Log::error('QC DataTable error:', [
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString()
                ]);
                return response()->json([
                    'error' => true,
                    'message' => 'Error loading QC data'
                ], 500);
            }
        }

        // If it's a regular request, return the view
        return view('qcs.index');
    }

    /**
     * Show QC form for GRN or general create
     */
    public function create(?Grn $grn = null)
    {

        // If GRN is provided, use the old workflow
        if ($grn) {
            // Check if GRN can have QC
            if ($grn->status !== 'awaiting_qc') {
                // dd($grn);
                return redirect()->route('grns.show', ['grn' => $grn->id])
                    ->with('error', 'GRN is not ready for QC inspection');
            }

            // Get or create QC for this GRN
            $qc = $grn->qcs()->first();
            if (!$qc) {
                $qc = $this->qcService->createQcForGrn($grn);
            }

            $warehouses = \App\Models\Warehouse::orderBy('name')->pluck('name', 'id');
            // $inspectors = \App\Models\Account::where('model_type', 'employee')
            //     ->whereIn('employee_type', ['employee', 'worker'])
            //     ->orderBy('name')->pluck('name', 'id');
            $inspectors = \App\Models\Account::query()
    ->where('model_type', 'employee')
    ->whereIn('employee_type', ['employee', 'worker'])
    ->orderBy('name')
    ->pluck('name', 'id');


            // Get current user's employee account as default inspector
            $currentUser = auth()->user();
            $defaultInspector = null;

            if ($currentUser) {
                // Try to find employee account for current user
                $defaultInspector = \App\Models\Account::where('model_type', 'employee')
                    ->whereIn('employee_type', ['employee', 'worker'])
                    ->where('email', $currentUser->email)
                    ->orWhere('user_id', $currentUser->id)
                    ->first();
            }

            return view('qcs.create', compact('grn', 'qc', 'warehouses', 'inspectors', 'defaultInspector'));
        }

        // If no GRN provided, show the new IGP-based create page
        return view('qcs.create');
    }

    /**
     * Store a newly created QC inspection
     */
    public function store(StoreQcRequest $request)
    {
        try {
            DB::beginTransaction();
            // dd($request->input());
            // Create QC record
            $qc = Qc::create([
                'qc_number' => $request->qc_number,
                'igp_id' => $request->igp_id,
                'inspector_id' => $request->inspector_id,
                'remarks' => $request->remarks,
                'inspected_at' => $request->input('inspected_at', now()),
                // 'status' => 'completed',
                'created_by' => auth()->id(),
            ]);

            // Process QC items
            $acceptedItems = [];
            $rejectedItems = [];

            foreach ($request->items as $item) {
                $acceptedQty = floatval($item['accepted_qty'] ?? 0);
                $rejectedQty = floatval($item['rejected_qty'] ?? 0);

                // Create QC item record
                $qcItem = QcItem::create([
                    'qc_id' => $qc->id,
                    'item_id' => $item['item_id'],
                    'purchase_order_item_id' => $item['purchase_order_item_id'],
                    'uom_id' => $item['uom_id'],
                    'unit_code' => $item['unit_code'],
                    'ordered_qty' => $item['ordered_qty'],
                    'igp_qty' => $item['igp_qty'],
                    'accepted_qty' => $acceptedQty,
                    'rejected_qty' => $rejectedQty,
                    'warehouse_id' => $acceptedQty > 0 ? $item['warehouse_id'] : null,
                    // 'bin_id' => $acceptedQty > 0 ? $item['bin_id'] : null,
                ]);

                // Categorize items for stock processing
                if ($acceptedQty > 0) {
                    $acceptedItems[] = [
                        'item_id' => $item['item_id'],
                        'quantity_received' => $acceptedQty,
                        'warehouse_id' => $item['warehouse_id'],
                        'bin_id' => $item['bin_id'],
                    ];
                }

                if ($rejectedQty > 0) {
                    $rejectedItems[] = [
                        'item_id' => $item['item_id'],
                        'quantity_rejected' => $rejectedQty,
                    ];
                }
            }

            // 1. Process QC with double-entry accounting
            if (count($acceptedItems) > 0) {
                $this->stockAccountingService->handleQcEvent($qc);
            }

            // Record rejected items in ledger
            foreach ($rejectedItems as $item) {
                if ($item['quantity_rejected'] > 0) {
                    \App\Models\StockLedger::create([
                        'account_id' => $item['item_id'],
                        'qc_id' => $qc->id,
                        'po_id' => $qc->igp->purchase_order_id,
                        'igp_id' => $qc->igp_id,
                        'quantity' => -$item['quantity_rejected'], // Negative quantity for rejected items

                        'remarks' => 'QC Rejected - ' . $qc->qc_number,
                        'timestamp' => now(),
                    ]);
                }
            }

            // 2. Determine QC status
            $totalAccepted = array_sum(array_map(fn($i) => (float)($i['accepted_qty'] ?? 0), $request->items));
            $totalRejected = array_sum(array_map(fn($i) => (float)($i['rejected_qty'] ?? 0), $request->items));

            $finalQcStatus = null;
            // if ($totalAccepted > 0 && $totalRejected > 0) {
            //     $finalQcStatus = \App\Models\Qc::STATUS_PARTIALLY_QC_PASSED;
            // } elseif ($totalAccepted > 0 && $totalRejected == 0) {
            //     $finalQcStatus = \App\Models\Qc::STATUS_QC_PASSED;
            // } else {
            //     $finalQcStatus = \App\Models\Qc::STATUS_QC_REJECTED;
            // }

            // $qc->update(['status' => $finalQcStatus]);

            // 3. Update Gate Pass status
            if ($qc->igp_id) {
                $igp = \App\Models\GatePass::find($qc->igp_id);
                if ($igp) {
                    $igp->update(['status' => 'closed']);
                }
            }

            // 4. Update PO status
            if ($qc->igp && $qc->igp->purchaseOrder) {
                $po = $qc->igp->purchaseOrder;

                // Calculate total ordered and received quantities for this PO
                $totalOrdered = $po->items->sum('quantity');
                $totalReceived = \App\Models\QcItem::whereHas('qc', function($q) use ($po) {
                    $q->whereHas('igp', function($q) use ($po) {
                        $q->where('purchase_order_id', $po->id);
                    });
                })->sum('accepted_qty');

                // Update PO status
                if ($totalReceived >= $totalOrdered) {
                    $po->update(['status' => 'closed']);
                } elseif ($totalReceived > 0) {
                    $po->update(['status' => 'partial']);
                }
            }

            DB::commit();

            return redirect()->route('qcs.index')
                ->with('success', 'QC inspection submitted successfully! QC Number: ' . $qc->qc_number);

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('QC creation failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request_data' => $request->validated()
            ]);

            return redirect()->back()
                ->withInput()
                ->with('error', 'Failed to submit QC inspection: ' . $e->getMessage().$e->getLine().$e->getFile());
        }
    }

    /**
     * Update QC results
     */
    public function update(Request $request, Qc $qc): JsonResponse
    {
        try {
            if (!$qc->canEdit()) {
                return response()->json(['success' => false, 'message' => 'QC cannot be edited in its current status.'], 422);
            }

            $request->validate([
                'warehouse_id' => 'required|integer|exists:warehouses,id',
                'inspected_by' => 'required|integer|exists:accounts,id',
                'qc_items' => 'required|array|min:1',
                'qc_items.*.qc_item_id' => 'required|integer|exists:qc_items,id',
                'qc_items.*.qty_passed' => 'required|numeric|gte:0',
                'qc_items.*.available_bin_id' => 'required|integer|exists:warehouse_bins,id',
                'qc_items.*.rejected_bin_id' => 'required|integer|exists:warehouse_bins,id',
                'qc_items.*.lot_no' => 'nullable|string|max:100',
                'qc_items.*.remarks' => 'nullable|string|max:1000',
            ]);

            // Additional validation: Check if passed quantities exceed received quantities
            foreach ($request->input('qc_items') as $itemData) {
                $qcItem = \App\Models\QcItem::find($itemData['qc_item_id']);
                if ($qcItem) {
                    $receivedQty = (float) $qcItem->grnItem->received_quantity;
                    $passedQty = (float) $itemData['qty_passed'];

                    if ($passedQty > $receivedQty) {
                        return response()->json([
                            'success' => false,
                            'message' => "Passed quantity ({$passedQty}) cannot exceed received quantity ({$receivedQty}) for item: {$qcItem->item->name}",
                        ], 400);
                    }
                }
            }

            $result = $this->qcService->submitQcResults(
                $qc,
                $request->input('qc_items'),
                $request->input('warehouse_id'),
                $request->input('inspected_by')
            );

            return response()->json([
                'success' => true,
                'message' => 'QC results updated successfully',
                'data' => $result,
            ]);

        } catch (\Exception $e) {
            Log::error('QC update failed', [
                'qc_id' => $qc->id,
                'error' => $e->getMessage(),
                'request_data' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Show QC details
     */
    public function show(Qc $qc)
    {
        $qc->load(['igp.items.item', 'igp.purchaseOrder', 'qcItems.item', 'qcItems.warehouse', 'inspector']);

        return view('qcs.show', compact('qc'));
    }

    /**
     * Cancel QC
     */
    public function cancel(Request $request, Qc $qc): JsonResponse
    {
        try {
            $request->validate([
                'cancelled_reason' => 'required|string|max:1000',
            ]);

            $this->qcService->cancelQc(
                $qc,
                auth()->id(),
                $request->input('cancelled_reason')
            );

            return response()->json([
                'success' => true,
                'message' => 'QC cancelled successfully',
            ]);

        } catch (\Exception $e) {
            Log::error('QC cancellation failed', [
                'qc_id' => $qc->id,
                'error' => $e->getMessage(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }



    /**
     * Get QC items for a specific QC
     */
    /**
     * Get IGP items with DN quantities
     */
    public function getIgpItems(GatePass $gatepass): JsonResponse
    {
        // dd("ddd");
        $items = $gatepass->items()
            ->with(['item', 'purchaseOrderItem.uom'])
            ->get()
            ->map(function ($item) {
                return [
                    'item_id' => $item->item_id,
                    'purchase_order_item_id' => $item->purchase_order_item_id,
                    'item_name' => $item->item->name,
                    'ordered_qty' => $item->purchaseOrderItem->quantity,
                    'igp_qty' => $item->dn_quantity,
                    'uom_id' => optional($item->item->uom)->id,
                    'unit_code' => optional($item->item->uom)->unit_code ?? 'N/A',
                    'uom_name' => optional($item->item->uom)->name ?? 'N/A'
                ];
            });

        return response()->json([
            'success' => true,
            'data' => $items
        ]);
    }

    public function getQcItems(Qc $qc): JsonResponse
    {
        $qcItems = $qc->qcItems()->with(['item', 'grnItem'])->get();

        return response()->json([
            'success' => true,
            'data' => $qcItems,
        ]);
    }

    /**
     * Get warehouse stock for an item
     */
    public function getWarehouseStock(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'item_id' => 'required|integer|exists:items,id',
                'warehouse_id' => 'required|integer|exists:warehouses,id',
            ]);

            $stock = $this->warehouseService->getCurrentStock(
                $request->input('item_id'),
                $request->input('warehouse_id')
            );

            return response()->json([
                'success' => true,
                'data' => $stock,
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Get available bins for a warehouse
     */
    public function getWarehouseBins(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'warehouse_id' => 'required|integer|exists:warehouses,id',
                'bin_type' => 'nullable|string|in:available,rejected,all',
            ]);

            $warehouseId = $request->input('warehouse_id');
            $binType = $request->input('bin_type', 'all');

            $query = \App\Models\WarehouseBin::where('warehouse_id', $warehouseId)
                ->where('is_active', true);

            if ($binType !== 'all') {
                $query->where('type', $binType);
            }

            $bins = $query->orderBy('code')->get(['id', 'code', 'type']);

            return response()->json([
                'success' => true,
                'data' => $bins,
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Add QC items to stock (move from quarantine to available/rejected)
     */
    public function addToStock(Qc $qc): JsonResponse
    {
        try {
            // Check if QC is completed
            if ($qc->status !== 'completed') {
                return response()->json([
                    'success' => false,
                    'message' => 'QC must be completed before adding items to stock',
                ], 400);
            }

            // Check if stock already added
            if ($qc->stock_added) {
                return response()->json([
                    'success' => false,
                    'message' => 'Stock has already been added for this QC',
                ], 400);
            }

            // Add items to stock using QC service
            $result = $this->qcService->addQcItemsToStock($qc);

            return response()->json([
                'success' => true,
                'message' => 'Items added to stock successfully',
                'data' => $result,
            ]);

        } catch (\Exception $e) {
            Log::error('Adding QC items to stock failed', [
                'qc_id' => $qc->id,
                'error' => $e->getMessage(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Update IGP status based on QC completion
     */
    protected function updateIgpStatus($igpId): void
    {
        $igp = GatePass::find($igpId);
        if (!$igp) {
            return;
        }

        // Get total accepted quantity from all QC records for this IGP
        $totalAcceptedQty = QcItem::whereHas('qc', function($q) use ($igpId) {
            $q->where('igp_id', $igpId);
        })->sum('accepted_qty');

        // Get total IGP quantity
        $totalIgpQty = QcItem::whereHas('qc', function($q) use ($igpId) {
            $q->where('igp_id', $igpId);
        })->sum('igp_qty');

        // Update IGP status
        if ($totalAcceptedQty >= $totalIgpQty) {
            $igp->update(['status' => 'closed']);
        } else {
            // $igp->update(['status' => 'partially_received']);
        }

        // Update PO status if needed
        if ($igp->purchaseOrder) {
            $po = $igp->purchaseOrder;
            $totalPoQty = $po->items->sum('quantity');
            $totalReceivedQty = QcItem::whereHas('qc', function($q) use ($po) {
                $q->whereHas('igp', function($igp) use ($po) {
                    $igp->where('purchase_order_id', $po->id);
                });
            })->sum('accepted_qty');

            if ($totalReceivedQty >= $totalPoQty) {
                $po->update(['status' => 'completed']);
            } elseif ($totalReceivedQty > 0) {
                $po->update(['status' => 'partial']);
            }
        }
    }

    public function inspectorSearch(Request $request): JsonResponse
    {
        try {
            $query = Account::where('model_type','employee');
            $search = $request->input('q', '');
            // $type = $request->input('type');

            // Filter by type if specified
            // if ($type) {
            //     $query->where('type', $type);
            // }

            // Search by name, email, or contact person
                if ($search) {
                    $query->where(function ($q) use ($search) {
                        $q->where('name', 'like', "%{$search}%");
                        // ->orWhere('email', 'like', "%{$search}%")
                        // ->orWhere('contact_person', 'like', "%{$search}%");
                    });
                }

                $contacts = $query->where('is_active', 1)
                    ->orderBy('name')
                    ->limit(20)
                    ->get()
                    ->map(function ($contact) {
                        return [
                            'id' => $contact->id,
                            'text' => $contact->name . ' - ' . $contact->phone
                        ];
                    });
                // dd("ddd");


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

        } catch (\Exception $e) {
            Log::error('Failed to search contacts', [
                'error' => $e->getMessage(),
                'search' => $search ?? '',
                // 'type' => $type ?? ''
            ]);

            return response()->json([]);
        }
    }
}
