<?php

namespace App\Services;

use App\Models\GoodsReceiving;
use App\Models\GoodsReceivingItem;
use App\Models\GrnItemBatch;
use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\RawMaterialItem;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class GoodsReceivingService
{
    public function getAllGoodsReceivings()
    {
        if (auth()->user()->hasRole('Superadmin')) {
            $goodsReceivings = GoodsReceiving::orderBy('created_at', 'desc')->get();
        } else {
            $goodsReceivings = GoodsReceiving::where('company_id', auth()->user()->employee->company_id)->orderBy('created_at', 'desc')->get();
        }
        return $goodsReceivings;
    }

    // public function createGoodsReceiving(array $data)
    // {
    //     $data['invoice_id'] = $data['invoice'];
    //     $data['party_id'] = $data['supplier'];
    //     $data['company_id'] = $data['company'];

    //     $goodsReceiving = GoodsReceiving::create($data);

    //     $items = $data['items'] ?? [];

    //     foreach ($items as $item) {
    //         $grn_items = $item['grn_items'] ?? [];
    //         foreach ($grn_items as $key => $grn_item) {
    //             $grn_item['product_id'] = $item['product'] ?? null;
    //             $grn_item['raw_material_item_id'] = $item['raw_material_item'] ?? null;
    //             $grn_item['code'] = $item['code'] ?? null;
    //             $grn_item['description'] = $item['description'] ?? null;
    //             $grn_item['quantity_ordered'] = $item['quantity_ordered'] ?? null;
    //             $grn_item['quantity_received'] = $item['quantity_received'] ?? null;

    //             if ($grn_item['product_id']) {
    //                 $grn_item['last_goods_receiving_id'] = GoodsReceivingItem::where('product_id', $grn_item['product_id'])
    //                     ->latest('id')
    //                     ->value('goods_receiving_id');
    //             } elseif ($grn_item['raw_material_item_id']) {
    //                 $grn_item['last_goods_receiving_id'] = GoodsReceivingItem::where('raw_material_item_id', $grn_item['raw_material_item_id'])
    //                     ->latest('id')
    //                     ->value('goods_receiving_id');
    //             }

    //             $goodsReceiving->items()->create($grn_item);

    //             $grn_item['quantity'] = $grn_item['balance_receivable'];
    //             $grn_item['total'] = $grn_item['total_amount'];
    //             $grn_item['company_id'] = $data['company_id'];

    //             $goodsReceiving->stocks()->create($grn_item);
    //         }
    //     }

    //     $allItemsMatch = $goodsReceiving->items->every(function ($item) {
    //         return $item->quantity_ordered == ($item->quantity_received + $item->balance_receivable);
    //     });

    //     // Handle vendor bills
    //     if (isset($data['vendor_bills']) && is_array($data['vendor_bills'])) {
    //         foreach ($data['vendor_bills'] as $vendorBill) {
    //             $goodsReceiving->vendor_bills()->create([
    //                 'item_index' => $vendorBill['item_index'],
    //                 'bill_no' => $vendorBill['bill_no'],
    //                 'bill_date' => $vendorBill['bill_date'] ?? null,
    //                 'amount' => $vendorBill['amount'] ?? 0,
    //             ]);
    //         }
    //     }

    //     return $goodsReceiving;
    // }

    public function createGoodsReceiving(array $request)
    {
        // dd($data);
        return DB::transaction(function () use ($request) {
            $data = [];
            $data['invoice_id'] = $request['invoice'];
            $data['code'] = $request['code'];
            $data['party_id']   = $request['supplier'];
            $data['company_id'] = $request['company'];
            $data['supplier_name']   = $request['supplier_name'];
            $data['supplier_code'] = $request['supplier_code'];
            $data['total_amount'] = $request['total_amount'];
            if ($request['is_approved'] && ($request['is_approved'] == 1 || $request['is_approved'] == '1')) {
                $data['is_approved'] = 1;
            }

            $goodsReceiving = GoodsReceiving::create($data);

            $invoice = Invoice::find($goodsReceiving->invoice_id);

            $invoiceItem = InvoiceItem::whereIn('id', $request['item_id'])->get();
            // dd($invoiceItem);

            foreach ($invoiceItem as $item) {
                $reqItemData = $request['items'][$item->id];
                $currentQty = array_sum(array_column($reqItemData['grn_items'], 'receiving_qty'));
                $totalItemAmount = array_sum(array_column($reqItemData['grn_items'], 'total_amount'));
                $previousReceived = GoodsReceivingItem::where('invoice_item_id', $item->id)->sum('quantity_received');

                $lastPurchasedGrnItem = GoodsReceivingItem::where('invoice_item_id', $item->id)
                    ->where('raw_material_item_id', $item->raw_material_item_id)
                    ->latest('id')->first();

                // dd($currentQty, $totalItemAmount, $reqItemData);
                $grnItemData = [
                    'goods_receiving_id' => $goodsReceiving->id,
                    'product_id' => $reqItemData['product'] ?? null,
                    'raw_material_item_id' => $item->raw_material_item_id ?? null,
                    'invoice_item_id' => $item->id,
                    'code' => $reqItemData['code'] ?? null,
                    'description' => $reqItemData['description'] ?? null,
                    'quantity_ordered' => $reqItemData['quantity_ordered'] ?? null,
                    // 'quantity_received' => $reqItemData['quantity_received'] ?? null,
                    'quantity_received' => $currentQty, // 👈 cumulative
                    'balance_receivable' => $reqItemData['quantity_ordered'] - ($previousReceived + $currentQty),
                    'total_amount' => $totalItemAmount,
                    'supplier_bill_no' => $reqItemData['supplier_bill_no'] ?? null,
                    'unit_price' => $reqItemData['grn_items'][0]['unit_price'] ?? null,
                    'unit' => $reqItemData['grn_items'][0]['unit'] ?? null,
                    'last_goods_receiving_id' => $lastPurchasedGrnItem->goods_receiving_id ?? null,
                    'last_grn_item_id' => $lastPurchasedGrnItem->id ?? null,
                ];

                $grnItem = GoodsReceivingItem::create($grnItemData);
                $item->update([
                    'grn_qty_received' => $previousReceived + $currentQty
                ]);
                $rawMaterialItem = RawMaterialItem::find($item->raw_material_item_id);
                $existingStockQty = $rawMaterialItem->current_stock;
                $rawMaterialItem->update([
                    'current_stock' => $existingStockQty + $currentQty,
                ]);
                foreach ($reqItemData['grn_items'] as $key => $batchData) {
                    GrnItemBatch::create([
                        'grn_id' => $goodsReceiving->id,
                        'grn_item_id' => $grnItem->id,
                        'batch' => $batchData['batch'] ?? null,
                        'mfg_date' => $batchData['mfg_date'] ?? null,
                        'exp_date' => $batchData['exp_date'] ?? null,
                        'unit_price' => $batchData['unit_price'] ?? null,
                        'unit' => $batchData['unit'] ?? null,
                        'total_amount' => $batchData['total_amount'] ?? null,
                        'receiving_quantity' => $batchData['receiving_qty'] ?? null,
                    ]);
                }

                $grnItemData['quantity'] = $currentQty;
                $grnItemData['total'] = $totalItemAmount;
                $grnItemData['company_id'] = $data['company_id'];

                $goodsReceiving->stocks()->create($grnItemData);
            }

            // Fetch invoice with all its items
            $invoice = Invoice::with(['items', 'goodsReceivings.items'])->find($goodsReceiving->invoice_id);
            // dd($invoice->toArray());

            // 1. Check that all invoice items are included in GRNs
            $invoiceItemIds = $invoice->items->pluck('id')->toArray();
            $grnItemIds = $invoice->goodsReceivings->flatMap->items->pluck('invoice_item_id')->unique()->toArray();
            $allItemsCovered = empty(array_diff($invoiceItemIds, $grnItemIds));

            // 2. Check quantities
            $allQtySatisfied = $invoice->items->every(function ($invItem) use ($invoice) {
                $totalReceived = $invoice->goodsReceivings
                    ->flatMap->items
                    ->where('invoice_item_id', $invItem->id)
                    ->sum('quantity_received');

                return $totalReceived >= $invItem->quantity;
            });

            $status = ($allItemsCovered && $allQtySatisfied) ? 'COMPLETED' : 'PARTIALLY COMPLETE';

            // dd($invoiceItemIds, $grnItemIds, $allItemsCovered, $allQtySatisfied, $status);

            // Update Invoice
            $invoice->update(['status' => $status]);

            // dd($data);

            // $items = $data['items'] ?? [];

            // foreach ($items as $item) {
            //     $grn_items = $item['grn_items'] ?? [];

            //     foreach ($grn_items as $key => $grn_item) {
            //         $grn_item['product_id']         = $item['product'] ?? null;
            //         $grn_item['raw_material_item_id'] = $item['raw_material_item'] ?? null;
            //         $grn_item['code']               = $item['code'] ?? null;
            //         $grn_item['description']        = $item['description'] ?? null;
            //         $grn_item['quantity_ordered']   = $item['quantity_ordered'] ?? null;
            //         $grn_item['quantity_received']  = $item['quantity_received'] ?? null;

            //         if ($grn_item['product_id']) {
            //             $grn_item['last_goods_receiving_id'] = GoodsReceivingItem::where('product_id', $grn_item['product_id'])
            //                 ->latest('id')
            //                 ->value('goods_receiving_id');
            //         } elseif ($grn_item['raw_material_item_id']) {
            //             $grn_item['last_goods_receiving_id'] = GoodsReceivingItem::where('raw_material_item_id', $grn_item['raw_material_item_id'])
            //                 ->latest('id')
            //                 ->value('goods_receiving_id');
            //         }

            //         // Create Goods Receiving Item
            //         $goodsReceiving->items()->create($grn_item);

            //         // Create Stock entry
            //         $grn_item['quantity']   = $grn_item['balance_receivable'];
            //         $grn_item['total']      = $grn_item['total_amount'];
            //         $grn_item['company_id'] = $data['company_id'];

            //         $goodsReceiving->stocks()->create($grn_item);
            //     }
            // }

            // ✅ Invoice Status Check
            // $allCompleted = $goodsReceiving->items->every(function ($item) {
            //     return $item->quantity_ordered <= ($item->quantity_received + $item->balance_receivable);
            // });

            // $status = $allCompleted ? 'COMPLETED' : 'PARTIALLY COMPLETE';

            // // Update Invoice status
            // Invoice::where('id', $goodsReceiving->invoice_id)->update([
            //     'status' => $status,
            // ]);

            // // Handle vendor bills
            // if (isset($data['vendor_bills']) && is_array($data['vendor_bills'])) {
            //     foreach ($data['vendor_bills'] as $vendorBill) {
            //         $goodsReceiving->vendor_bills()->create([
            //             'item_index' => $vendorBill['item_index'],
            //             'bill_no'    => $vendorBill['bill_no'],
            //             'bill_date'  => $vendorBill['bill_date'] ?? null,
            //             'amount'     => $vendorBill['amount'] ?? 0,
            //         ]);
            //     }
            // }

            return $goodsReceiving;
        });
    }

    public function updateGoodsReceiving($goodsReceiving, $request)
    {
        // dd($request->all(), $goodsReceiving);

        return DB::transaction(function () use ($goodsReceiving, $request) {
            $goodsReceiving->update([
                'is_approved' => $request->is_approved,
                'total_amount' => $request->total_amount,
            ]);

            $goodsReceiving->stocks->each->delete();

            foreach ($request->items as $key => $item) {
                $currentQty = array_sum(array_column($item['grn_items'], 'receiving_qty'));
                $totalItemAmount = array_sum(array_column($item['grn_items'], 'total_amount'));

                $grnItem = GoodsReceivingItem::find($key);
                if (!$grnItem) {
                    abort(404);
                }
                $previousReceived = GoodsReceivingItem::where('invoice_item_id', $grnItem->invoice_item_id)->sum('quantity_received');

                $oldQty = $grnItem->quantity_received;

                if ($currentQty > $oldQty) {
                    $oldReceivedPlusNewQty = ($previousReceived - $oldQty) + $currentQty;
                } else {
                    $diff = $oldQty - $currentQty;
                    $oldReceivedPlusNewQty = $previousReceived - $diff;
                }

                // dump($key, $item, $currentQty, $totalItemAmount, $previousReceived);

                $invoiceItem = $grnItem->invoiceItem;
                $totalReceivedTillNow = $oldReceivedPlusNewQty;
                // dd($invoiceItem->toArray(),$previouslyReceived,(float) $previousReceived, $totalReceivedTillNow);
                $invoiceItem->update([
                    'grn_qty_received' => $oldReceivedPlusNewQty, // $totalReceivedTillNow,
                ]);

                $grnItem->update([
                    'supplier_bill_no' => $request->supplier_bill_no,
                    'quantity_received' => $currentQty, // 👈 cumulative
                    'balance_receivable' => ($grnItem->quantity_ordered - $totalReceivedTillNow),
                    'total_amount' => $totalItemAmount,
                    'supplier_bill_no' => $item['supplier_bill_no'] ?? null,
                ]);

                $rawMaterialItem = RawMaterialItem::find($grnItem->raw_material_item_id);
                $existingStockQty = $rawMaterialItem->current_stock - $oldQty;
                $rawMaterialItem->update([
                    'current_stock' => $existingStockQty + $currentQty,
                ]);

                $goodsReceiving->stocks()->create([
                    'goods_receiving_id' => $goodsReceiving->id,
                    'quantity' => $grnItem->quantity_received,
                    'total' => $grnItem->total_amount,
                    'company_id' => $goodsReceiving->company_id,
                    'created_by' => Auth::id(),
                ]);

                foreach ($item['grn_items'] as $ind => $batchData) {
                    $data = [
                        'batch' => $batchData['batch'] ?? null,
                        'mfg_date' => $batchData['mfg_date'] ?? null,
                        'exp_date' => $batchData['exp_date'] ?? null,
                        'unit_price' => $batchData['unit_price'] ?? null,
                        'unit' => $batchData['unit'] ?? null,
                        'total_amount' => $batchData['total_amount'] ?? null,
                        'receiving_quantity' => $batchData['receiving_qty'] ?? null,
                    ];
                    if (array_key_exists('batch_id', $batchData)) {
                        $existingBatch = GrnItemBatch::find($batchData['batch_id']);
                        $existingBatch->update($data);
                    } else {
                        $data['grn_item_id'] = $grnItem->id;
                        $data['grn_id'] = $goodsReceiving->id;
                        GrnItemBatch::create($data);
                    }
                }
            }

            // Fetch invoice with all its items
            $invoice = Invoice::with(['items', 'goodsReceivings.items'])->find($goodsReceiving->invoice_id);
            // dd($invoice->toArray());

            // 1. Check that all invoice items are included in GRNs
            $invoiceItemIds = $invoice->items->pluck('id')->toArray();
            $grnItemIds = $invoice->goodsReceivings->flatMap->items->pluck('invoice_item_id')->unique()->toArray();
            $allItemsCovered = empty(array_diff($invoiceItemIds, $grnItemIds));

            // 2. Check quantities
            $allQtySatisfied = $invoice->items->every(function ($invItem) use ($invoice) {
                $totalReceived = $invoice->goodsReceivings
                    ->flatMap->items
                    ->where('invoice_item_id', $invItem->id)
                    ->sum('quantity_received');

                return $totalReceived >= $invItem->quantity;
            });

            $status = ($allItemsCovered && $allQtySatisfied) ? 'COMPLETED' : 'PARTIALLY COMPLETE';

            // dd($invoiceItemIds, $grnItemIds, $allItemsCovered, $allQtySatisfied, $status);

            // Update Invoice
            $invoice->update(['status' => $status]);

            return $goodsReceiving;
        });
    }

    // public function updateGoodsReceiving(GoodsReceiving $goodsReceiving, array $data)
    // {
    //     $data['invoice_id'] = $data['invoice'];
    //     $data['party_id'] = $data['supplier'];
    //     $data['company_id'] = $data['company'];

    //     $goodsReceiving->update($data);

    //     $goodsReceiving->stocks->each->delete();
    //     $goodsReceiving->items->each->delete();

    //     $items = $data['items'] ?? [];

    //     foreach ($items as $item) {
    //         $grn_items = $item['grn_items'] ?? [];
    //         foreach ($grn_items as $key => $grn_item) {
    //             $grn_item['product_id'] = $item['product'] ?? null;
    //             $grn_item['raw_material_item_id'] = $item['raw_material_item'] ?? null;
    //             $grn_item['code'] = $item['code'] ?? null;
    //             $grn_item['description'] = $item['description'] ?? null;
    //             $grn_item['quantity_ordered'] = $item['quantity_ordered'] ?? null;
    //             $grn_item['quantity_received'] = $item['quantity_received'] ?? null;

    //             if ($grn_item['product_id']) {
    //                 $grn_item['last_goods_receiving_id'] = GoodsReceivingItem::where('product_id', $grn_item['product_id'])
    //                     ->latest('id')
    //                     ->value('goods_receiving_id');
    //             } elseif ($grn_item['raw_material_item_id']) {
    //                 $grn_item['last_goods_receiving_id'] = GoodsReceivingItem::where('raw_material_item_id', $grn_item['raw_material_item_id'])
    //                     ->latest('id')
    //                     ->value('goods_receiving_id');
    //             }

    //             $goodsReceiving->items()->create($grn_item);

    //             $grn_item['quantity'] = $grn_item['balance_receivable'];
    //             $grn_item['total'] = $grn_item['total_amount'];
    //             $grn_item['company_id'] = $data['company_id'];

    //             $goodsReceiving->stocks()->create($grn_item);
    //         }
    //     }

    //     $allItemsMatch = $goodsReceiving->items->every(function ($item) {
    //         return $item->quantity_ordered == ($item->quantity_received + $item->balance_receivable);
    //     });

    //     // Handle vendor bills
    //     $goodsReceiving->vendor_bills()->delete(); // Remove existing vendor bills
    //     if (isset($data['vendor_bills']) && is_array($data['vendor_bills'])) {
    //         foreach ($data['vendor_bills'] as $vendorBill) {
    //             $goodsReceiving->vendor_bills()->create([
    //                 'item_index' => $vendorBill['item_index'],
    //                 'bill_no' => $vendorBill['bill_no'],
    //                 'bill_date' => $vendorBill['bill_date'] ?? null,
    //                 'amount' => $vendorBill['amount'] ?? 0,
    //             ]);
    //         }
    //     }

    //     return $goodsReceiving;
    // }

    // public function updateGoodsReceiving(GoodsReceiving $goodsReceiving, array $data)
    // {
    //     $data['invoice_id'] = $data['invoice'];
    //     $data['party_id']   = $data['supplier'];
    //     $data['company_id'] = $data['company'];

    //     // Update Goods Receiving record
    //     $goodsReceiving->update($data);

    //     // Delete old stocks & items
    //     $goodsReceiving->stocks()->delete();
    //     $goodsReceiving->items()->delete();

    //     $items = $data['items'] ?? [];

    //     foreach ($items as $item) {
    //         $grn_items = $item['grn_items'] ?? [];

    //         foreach ($grn_items as $key => $grn_item) {
    //             $grn_item['product_id']           = $item['product'] ?? null;
    //             $grn_item['raw_material_item_id'] = $item['raw_material_item'] ?? null;
    //             $grn_item['code']                 = $item['code'] ?? null;
    //             $grn_item['description']          = $item['description'] ?? null;
    //             $grn_item['quantity_ordered']     = $item['quantity_ordered'] ?? null;
    //             $grn_item['quantity_received']    = $item['quantity_received'] ?? null;

    //             if ($grn_item['product_id']) {
    //                 $grn_item['last_goods_receiving_id'] = GoodsReceivingItem::where('product_id', $grn_item['product_id'])
    //                     ->latest('id')
    //                     ->value('goods_receiving_id');
    //             } elseif ($grn_item['raw_material_item_id']) {
    //                 $grn_item['last_goods_receiving_id'] = GoodsReceivingItem::where('raw_material_item_id', $grn_item['raw_material_item_id'])
    //                     ->latest('id')
    //                     ->value('goods_receiving_id');
    //             }

    //             // Create new Goods Receiving Item
    //             $goodsReceiving->items()->create($grn_item);

    //             // Create new Stock entry
    //             $grn_item['quantity']   = $grn_item['balance_receivable'];
    //             $grn_item['total']      = $grn_item['total_amount'];
    //             $grn_item['company_id'] = $data['company_id'];

    //             $goodsReceiving->stocks()->create($grn_item);
    //         }
    //     }

    //     // ✅ Invoice Status Check
    //     $allCompleted = $goodsReceiving->items->count() > 0 &&
    //         $goodsReceiving->items->every(function ($item) {
    //             return $item->quantity_ordered <= ($item->quantity_received + $item->balance_receivable);
    //         });

    //     $status = $allCompleted ? 'COMPLETED' : 'PARTIALLY COMPLETE';

    //     // Update Invoice status
    //     Invoice::where('id', $goodsReceiving->invoice_id)->update([
    //         'status' => $status,
    //     ]);

    //     // Handle vendor bills
    //     $goodsReceiving->vendor_bills()->delete(); // Remove existing vendor bills
    //     if (isset($data['vendor_bills']) && is_array($data['vendor_bills'])) {
    //         foreach ($data['vendor_bills'] as $vendorBill) {
    //             $goodsReceiving->vendor_bills()->create([
    //                 'item_index' => $vendorBill['item_index'],
    //                 'bill_no'    => $vendorBill['bill_no'],
    //                 'bill_date'  => $vendorBill['bill_date'] ?? null,
    //                 'amount'     => $vendorBill['amount'] ?? 0,
    //             ]);
    //         }
    //     }

    //     return $goodsReceiving;
    // }

    public function deleteGoodsReceiving(GoodsReceiving $goodsReceiving)
    {
        $goodsReceiving->stocks->each->delete();
        $goodsReceiving->items->each->delete();
        $goodsReceiving->vendor_bills()->delete();
        return $goodsReceiving->delete();
    }

    public function getGoodsReceivingById($id)
    {
        return GoodsReceiving::with(['vendor_bills', 'items', 'company', 'party', 'invoice', 'createdBy'])->findOrFail($id);
    }

    public function createGoodsReceivingCode($company_id)
    {
        $lastGoodsReceivingCode = GoodsReceiving::latest('id')->where('company_id', $company_id)->value('code');
        if ($lastGoodsReceivingCode) {
            $numberPart = (int) substr($lastGoodsReceivingCode, 3);
            $newNumberPart = $numberPart + 1;
            $newGoodsReceivingCode = 'GRN' . str_pad($newNumberPart, 5, '0', STR_PAD_LEFT);
        } else {
            $newGoodsReceivingCode = 'GRN00001';
        }
        return $newGoodsReceivingCode;
    }
}
