<?php

namespace App\Service\Warehouse;

use App\Models\purchase_maker_masters;
use App\Models\PurchaseCheckerDetalis;
use App\Models\PurchaseCheckerMaster;
use App\Models\PurchaseMaster;
use App\Models\SupplierOpeningStock;
use App\Models\Warehouse;
use App\Models\WarehouseStock;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class WarehouseService
{
    public static function StoreData(array $data)
    {

        $prepared = collect($data);
        Warehouse::create($prepared->all());
    }

    public static function UpdateData($data, $id)
    {
        $prepared = collect($data);
        Warehouse::where('id', $id)->update($prepared->all());
    }

    public static function DataStore($data)
    {
        DB::transaction(function () use ($data) {

            $data = collect($data);
            //  New Stock Data insert and Update
            foreach ($data['list'] as $key => $value) {

                $existing = WarehouseStock::where('product_id', $value['product_id'])->when(setting()->business_id == 3, fn($q) => $q->where('batch_no', $value['batch_no']))->where('attribute_id', $value['attribute_id'])->where('warehouse_id', $data['warehouse_id'])->first();
                if ($existing) {
                    WarehouseStock::where('id', $existing->id)->update([
                        // 'opening_stock_date' =>  $data['opening_date'],
                        // 'opening_stock' =>   DB::raw('quantity +' . $value['quantity']),
                        'product_id' => $value['product_id'],
                        'attribute_id' => $value['attribute_id'],
                        'quantity' => DB::raw('quantity +' . $value['quantity']),
                        'unit_price' => (float) str_replace(',', '', ($existing->unit_price_total + ($value['unit_price'] * $value['quantity'])) / ($existing->quantity + $value['quantity'])),
                        'unit_price_total' => (float) str_replace(',', '', (($existing->unit_price_total + ($value['unit_price'] * $value['quantity'])) / ($existing->quantity + $value['quantity'])) * ($existing->quantity + $value['quantity'])),
                        'tp_price' => (float) str_replace(',', '', $value['tp_price']),
                        'tp_price_total' => (float) str_replace(',', '', ($value['tp_price']) * ($existing->quantity + $value['quantity'])),
                        'mrp_price' => (float) str_replace(',', '', $value['mrp_price']),
                        'mrp_price_total' => (float) str_replace(',', '', ($value['mrp_price']) * ($existing->quantity + $value['quantity'])),
                        'mfg_date' => (isset($value['mfg_date']) && $value['mfg_date'] != 'NaN-NaN-NaN') ? $value['mfg_date'] : null,
                        'exp_date' => (isset($value['exp_date']) && $value['exp_date'] != 'NaN-NaN-NaN') ? $value['exp_date'] : null,
                    ]);
                } else {
                    WarehouseStock::create([
                        // 'opening_stock_date' =>  $data['opening_date'],
                        // 'opening_stock' => (int) $value['quantity'],
                        'warehouse_id' => $data['warehouse_id'],

                        'product_id' => $value['product_id'],
                        'attribute_id' => $value['attribute_id'],
                        'quantity' => (int) $value['quantity'],
                        'unit_price' => (float) str_replace(',', '', $value['unit_price']),
                        'unit_price_total' => (float) str_replace(',', '', $value['unit_price'] * $value['quantity']),
                        'tp_price' => (float) str_replace(',', '', $value['tp_price']),
                        'tp_price_total' => (float) str_replace(',', '', $value['tp_price'] * $value['quantity']),
                        'mrp_price' => (float) str_replace(',', '', $value['mrp_price']),
                        'mrp_price_total' => (float) str_replace(',', '', $value['mrp_price'] * $value['quantity']),
                        'mfg_date' => (isset($value['mfg_date']) && $value['mfg_date'] != 'NaN-NaN-NaN') ? $value['mfg_date'] : null,
                        'exp_date' => (isset($value['exp_date']) && $value['exp_date'] != 'NaN-NaN-NaN') ? $value['exp_date'] : null,
                        'batch_no' => isset($value['batch_no']) ? $value['batch_no'] : null,
                    ]);
                }
            }
        });
    }

    public static function UpdateDataStore($data, $id, $type = 'auto')
    {

        DB::transaction(function () use ($data, $type) {

            $data = collect($data);


            if ($type == 'manual') {
     
                foreach ($data['list'] as $key => $value) {
                  
                        $preQty = (int) $value['previous_opening_stock'];
                        
                        $existing = WarehouseStock::when(setting()->business_id == 3, fn($q) => $q->where('batch_no', $value['batch_no']))->where('product_id', operator: $value['product_id'])->where('attribute_id', $value['attribute_id'])->where('warehouse_id', $data['warehouse_id'])->first();
                        if($existing){
                        $existing->where('id', $existing->id)->update([
                            'quantity' => DB::raw('quantity -' . $preQty),
                            // Keep unit price totals consistent when we reduce quantity.
                            // Otherwise unit_price can "jump" (example: 300 -> 600) because
                            // unit_price is derived from unit_price_total / quantity later.
                            'unit_price_total' => DB::raw('unit_price_total - (unit_price * ' . $preQty . ')'),
                            'tp_price_total' => DB::raw('tp_price_total - (tp_price * ' . $preQty . ')'),
                            'mrp_price_total' => DB::raw('mrp_price_total - (mrp_price * ' . $preQty . ')'),
                        ]);
                    }
                    
                }
            } else {
                $prev = SupplierOpeningStock::withoutGlobalScope('typeScope')->where('warehouse_id', $data['warehouse_id'])->whereDate('opening_stock_date', Carbon::parse($data['opening_date']))->get();
                foreach ($prev as $key => $item) {
                    $preQty = isset($item) ? (int) $item->opening_stock : 0;
                    $existing = WarehouseStock::when(setting()->business_id == 3, fn($q) => $q->where('batch_no', $item['batch_no']))->where('product_id', $item->product_id)->where('attribute_id', $item->attribute_id)->where('warehouse_id', $data['warehouse_id'])->first();

                    if ($existing) {
                        $existing->where('id', $existing->id)->update([
                            'quantity' => DB::raw('quantity -' . $preQty),
                            // Keep unit price totals consistent when we reduce quantity.
                            'unit_price_total' => DB::raw('unit_price_total - (unit_price * ' . $preQty . ')'),
                            'tp_price_total' => DB::raw('tp_price_total - (tp_price * ' . $preQty . ')'),
                            'mrp_price_total' => DB::raw('mrp_price_total - (mrp_price * ' . $preQty . ')'),
                        ]);
                    }
                }
            }


            //  New Stock Data insert and Update
            foreach ($data['list'] as $key => $value) {
                

                $existing = WarehouseStock::where('product_id', $value['product_id'])->when(setting()->business_id == 3, fn($q) => $q->where('batch_no', $value['batch_no']))->where('attribute_id', $value['attribute_id'])->where('warehouse_id', $data['warehouse_id'])->first();
           

                if ($existing) {

                    $totalQty = $existing->quantity + $value['quantity'];

                    if ($totalQty > 0) {
                        $unitPrice = ($existing->unit_price_total + ($value['unit_price'] * $value['quantity'])) / $totalQty;
                        $unitPriceTotal = $unitPrice * $totalQty;
                    } else {

                
                        if (Auth::check() && Auth::user()->can('no_qty_validation_check')) {
                            $unitPrice = $value['unit_price'];
                            $unitPriceTotal = $unitPrice * $totalQty;
                        } else {  
                         
                            $unitPrice = $existing->unit_price;
                            $unitPriceTotal = $existing->unit_price_total;
                        }
                    }

                    WarehouseStock::where('id', $existing->id)->update([
                        // 'opening_stock_date' =>  $data['opening_date'],
                        // 'opening_stock' =>   DB::raw('quantity +' . $value['quantity']),
                        'product_id' => $value['product_id'],
                        'attribute_id' => $value['attribute_id'],
                        'quantity' => DB::raw('quantity + ' . $value['quantity']),
                        'unit_price' => $unitPrice < 0 ? $existing->unit_price : $unitPrice,
                        'unit_price_total' => $unitPriceTotal < 0 ? $existing->unit_price_total : $unitPriceTotal,
                        'tp_price_total' => (float) str_replace(',', '', ($value['tp_price']) * ($existing->quantity + $value['quantity'])),
                        'mrp_price' => (float) str_replace(',', '', $value['mrp_price']),
                        'mrp_price_total' => (float) str_replace(',', '', ($value['mrp_price']) * ($existing->quantity + $value['quantity'])),
                        'mfg_date' => (isset($value['mfg_date']) && $value['mfg_date'] != 'NaN-NaN-NaN') ? $value['mfg_date'] : null,
                        'exp_date' => (isset($value['exp_date']) && $value['exp_date'] != 'NaN-NaN-NaN') ? $value['exp_date'] : null,

                    ]);
                } else {

                    WarehouseStock::create([
                        // 'opening_stock_date' =>  $data['opening_date'],
                        // 'opening_stock' => (int) $value['quantity'],
                        'warehouse_id' => $data['warehouse_id'],

                        'product_id' => $value['product_id'],
                        'attribute_id' => $value['attribute_id'],
                        'quantity' => (int) $value['quantity'],
                        'unit_price' => (float) str_replace(',', '', $value['unit_price']),
                        'unit_price_total' => (float) str_replace(',', '', $value['unit_price'] * $value['quantity']),
                        'tp_price' => (float) str_replace(',', '', $value['tp_price']),
                        'tp_price_total' => (float) str_replace(',', '', $value['tp_price'] * $value['quantity']),
                        'mrp_price' => (float) str_replace(',', '', $value['mrp_price']),
                        'mrp_price_total' => (float) str_replace(',', '', $value['mrp_price'] * $value['quantity']),
                        'mfg_date' => (isset($value['mfg_date']) && $value['mfg_date'] != 'NaN-NaN-NaN') ? $value['mfg_date'] : null,
                        'exp_date' => (isset($value['exp_date']) && $value['exp_date'] != 'NaN-NaN-NaN') ? $value['exp_date'] : null,
                        'batch_no' => isset($value['batch_no']) ? $value['batch_no'] : null,
                    ]);
                }
            }
        });
    }

    public static function PurchaseDataStore(array $data, $id)
    {
        $purchase = PurchaseMaster::find($id);

        //  New Stock Data insert and Update
        foreach ($data['list'] as $key => $value) {
            $existing = WarehouseStock::where('product_id', $value['product_id'])->where('warehouse_id', $data['warehouse_id'])->first();
            if ($existing) {
                WarehouseStock::where('id', $existing->id)->update([
                    'product_id' => $value['product_id'],
                    'stock_date' => $purchase->purchase_date,
                    'quantity' => DB::raw('quantity +' . $value['quantity']),
                    'price' => $value['price'],
                    'total' => DB::raw('total +' . $value['total']),
                ]);
            } else {

                WarehouseStock::create([
                    'warehouse_id' => $data['warehouse_id'],
                    'product_id' => $value['product_id'],
                    'stock_date' => $purchase->purchase_date,
                    'quantity' => $value['quantity'],
                    'price' => $value['price'],
                    'total' => $value['total'],
                ]);
            }
        }

        //  Purchase Maker Status change to complite
        $purchase->status = 2;
        $purchase->warehouse_id = $data['warehouse_id'];
        $purchase->purchase_received_date = Carbon::now();
        $purchase->save();

        if (isset($purchase->purchase_maker_id)) {

            purchase_maker_masters::where('id', $purchase->purchase_maker_id)->update([
                'status' => 2,
            ]);
        }
        self::purchaseCacker($data, $purchase);
    }

    public static function purchaseCacker($collect, $purchase)
    {
        // Sum all product total
        $total = array_reduce($collect['list'], function ($item, $item2) {
            return $item + $item2['total'];
        }, 0);

        // Create purchase Chacker Master
        $master_id = PurchaseCheckerMaster::create([
            'invoice_no' => $purchase->invoice_no,
            'purchase_date' => $purchase->purchase_date,
            'warehouse_id' => isset($collect['warehouse_id']) ? $collect['warehouse_id'] : null,
            'created_by' => Auth::user()->id,
            'total' => $total,
        ]);
        // Create Purchase Chacker Details
        foreach ($collect['list'] as $key => $value) {
            PurchaseCheckerDetalis::create([
                'checker_masters_id' => $master_id->id,
                'product_id' => $value['product_id'],
                'quantity' => $value['quantity'],
                'price' => $value['price'],
                'unit_id' => $value['unit_id'],
                'category_id' => $value['category_id'],
                'total' => $value['total'],
            ]);
        }
    }

    public static function CompanyOpeningStock($data, $product_id)
    {

        DB::table('supplier_opening_stocks')
            ->where('product_id', $product_id)
            ->delete();
        foreach ($data['list'] as $key => $value) {
            $prev = DB::table('supplier_opening_stocks')
                ->where('warehouse_id', $data['warehouse_id'])
                ->where('product_id', $value['product_id'])
                ->where('attribute_id', $value['attribute_id'])
                ->when($value['batch_no'] != null, fn($q) => $q->where('batch_no', $value['batch_no']))
                ->first();

            // Clean and prepare values
            $quantity   = (int) $value['quantity'];
            $unit_price =  str_replace(',', '', $value['unit_price']);
            $tp_price   = str_replace(',', '', $value['tp_price']);
            $mrp_price  = str_replace(',', '', $value['mrp_price']);
            $pack_qty  = isset($value['pack_qty']) ? $value['pack_qty'] : 0;
            $pack_price = isset($value['pack_price']) ? $value['pack_price'] : 0;
            $batch_no = isset($value['batch_no']) ? $value['batch_no'] : null;
            $mfg_date = (isset($value['mfg_date']) && $value['mfg_date'] != 'NaN-NaN-NaN') ? $value['mfg_date'] : null;
            $exp_date = (isset($value['exp_date']) && $value['exp_date'] != 'NaN-NaN-NaN') ? $value['exp_date'] : null;

            $dataToSave = [
                'quantity'          => $quantity,
                'opening_stock'     => $quantity,
                'unit_price'        => $unit_price,
                'unit_price_total'  => $unit_price * $quantity,
                'tp_price'          => $tp_price,
                'pack_qty'          => $pack_qty,
                'pack_price'          => $pack_price,
                'tp_price_total'    => $tp_price * $quantity,
                'mrp_price'         => $mrp_price,
                'mrp_price_total'   => $mrp_price * $quantity,
                'batch_no'          => $batch_no,
                'mfg_date'          => $mfg_date,
                'exp_date'          => $exp_date,
            ];

            // if ($prev) {
            //     // Update if exists
            //     DB::table('supplier_opening_stocks')
            //         ->where('id', $prev->id)
            //         ->update($dataToSave);
            // } else {
      
            SupplierOpeningStock::create([
                    'opening_stock_date' => Carbon::parse($data['opening_date']),
                    'opening_stock' => (int) $value['quantity'],
                    'warehouse_id' => $data['warehouse_id'],
                    'supplier_id' => null,
                    'product_id' => $value['product_id'],
                    'attribute_id' => $value['attribute_id'],
                    'quantity' => (int) $value['quantity'],
                    'batch_no' => isset($value['batch_no']) ? $value['batch_no'] : null,
                    'pack_qty' => isset($value['pack_qty']) ? $value['pack_qty'] : 0,
                    'pack_price' => isset($value['pack_price']) ? $value['pack_price'] : 0,
                    'unit_price' => (float) str_replace(',', '', $value['unit_price']),
                    'unit_price_total' => (float) str_replace(',', '', $value['unit_price'] * $value['quantity']),
                    'tp_price' => (float) str_replace(',', '', $value['tp_price']),
                    'tp_price_total' => (float) str_replace(',', '', $value['tp_price'] * $value['quantity']),
                    'mrp_price' => (float) str_replace(',', '', $value['mrp_price']),
                    'mrp_price_total' => (float) str_replace(',', '', $value['mrp_price'] * $value['quantity']),
                    'mfg_date' => (isset($value['mfg_date']) && $value['mfg_date'] != 'NaN-NaN-NaN') ? $value['mfg_date'] : null,
                    'exp_date' => (isset($value['exp_date']) && $value['exp_date'] != 'NaN-NaN-NaN') ? $value['exp_date'] : null,
                    'batch_no' => isset($value['batch_no']) ? $value['batch_no'] : null,
                ]);
            // }
        }
    }

    public static function CompanyOpeningStockStore($data)
    {

        foreach ($data['list'] as $key => $value) {
            SupplierOpeningStock::create([
                'opening_stock_date' => Carbon::parse($data['opening_date']),
                'opening_stock' => (int) $value['quantity'],
                'warehouse_id' => $data['warehouse_id'],
                'supplier_id' => null,
                'product_id' => $value['product_id'],
                'attribute_id' => $value['attribute_id'],
                'quantity' => (int) $value['quantity'],
                'pack_qty' => isset($value['pack_qty']) ? $value['pack_qty'] : 0,
                'pack_price' => isset($value['pack_price']) ? $value['pack_price'] : 0,
                'unit_price' => (float) str_replace(',', '', $value['unit_price']),
                'unit_price_total' => (float) str_replace(',', '', $value['unit_price'] * $value['quantity']),
                'tp_price' => (float) str_replace(',', '', $value['tp_price']),
                'tp_price_total' => (float) str_replace(',', '', $value['tp_price'] * $value['quantity']),
                'mrp_price' => (float) str_replace(',', '', $value['mrp_price']),
                'mrp_price_total' => (float) str_replace(',', '', $value['mrp_price'] * $value['quantity']),
                'mfg_date' => (isset($value['mfg_date']) && $value['mfg_date'] != 'NaN-NaN-NaN') ? $value['mfg_date'] : null,
                'exp_date' => (isset($value['exp_date']) && $value['exp_date'] != 'NaN-NaN-NaN') ? $value['exp_date'] : null,
                'batch_no' => isset($value['batch_no']) ? $value['batch_no'] : null,
            ]);
        }
    }

    public static function CompanyOpeningStockDelete($id)
    {

        $firstData =  SupplierOpeningStock::withoutGlobalScope('typeScope')->where('id', $id)->first();

        $openingDate = Carbon::parse($firstData->opening_stock_date)->toDateString(); // returns '2025-07-16'

        $prev = SupplierOpeningStock::withoutGlobalScope('typeScope')->where('warehouse_id', $firstData->warehouse_id)->whereDate('opening_stock_date', Carbon::parse($firstData->opening_stock_date))->get();

        foreach ($prev as $key => $item) {
            $preQty = isset($item) ? (int) $item->opening_stock : 0;
            $existing = WarehouseStock::where('product_id', $item->product_id)->where('attribute_id', $item->attribute_id)->where('warehouse_id', $item->warehouse_id)->first();
            if ($existing) {
                $existing->where('id', $existing->id)->update([
                    'quantity' => DB::raw('quantity -' . $preQty),
                    // Keep unit price totals consistent when we reduce quantity.
                    'unit_price_total' => DB::raw('unit_price_total - (unit_price * ' . $preQty . ')'),
                    'tp_price_total' => DB::raw('tp_price_total - (tp_price * ' . $preQty . ')'),
                    'mrp_price_total' => DB::raw('mrp_price_total - (mrp_price * ' . $preQty . ')'),
                ]);
            }
        }

        SupplierOpeningStock::withoutGlobalScope('typeScope')->where('warehouse_id', $firstData->warehouse_id)->whereDate('opening_stock_date', Carbon::parse($firstData->opening_stock_date))->delete();
    }
}
