<?php

namespace App\Http\Controllers;

use App\BusinessLocation;
use App\Product;
use App\PurchaseLine;
use App\Transaction;
use App\Utils\ProductUtil;
use App\Utils\TransactionUtil;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class OpeningStockController extends Controller
{
    /**
     * All Utils instance.
     */
    protected $productUtil;

    protected $transactionUtil;

    /**
     * Constructor
     *
     * @param  ProductUtils  $product
     * @return void
     */
    public function __construct(ProductUtil $productUtil, TransactionUtil $transactionUtil)
    {
        $this->productUtil = $productUtil;
        $this->transactionUtil = $transactionUtil;
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function add($product_id)
    {
        if (! auth()->user()->can('product.opening_stock')) {
            abort(403, 'Unauthorized action.');
        }

        $business_id = request()->session()->get('user.business_id');

        //Get the product
        $product = Product::where('business_id', $business_id)
                            ->where('id', $product_id)
                            ->with(['variations',
                                'variations.product_variation',
                                'unit',
                                'product_locations',
                                'second_unit',
                            ])
                            ->first();
        if (! empty($product) && $product->enable_stock == 1) {
            //Get Opening Stock Transactions for the product if exists
            $transactions = Transaction::where('business_id', $business_id)
                                ->where('opening_stock_product_id', $product_id)
                                ->where('type', 'opening_stock')
                                ->with(['purchase_lines'])
                                ->get();

            $purchases = [];
            $purchase_lines = [];
            foreach ($transactions as $transaction) {
                foreach ($transaction->purchase_lines as $purchase_line) {
                    if (! empty($purchase_lines[$purchase_line->variation_id])) {
                        $k = count($purchase_lines[$purchase_line->variation_id]);
                    } else {
                        $k = 0;
                        $purchase_lines[$purchase_line->variation_id] = [];
                    }

                    //Show only remaining quantity for editing opening stock.
                    $purchase_lines[$purchase_line->variation_id][$k]['quantity'] = $purchase_line->quantity_remaining;
                    $purchase_lines[$purchase_line->variation_id][$k]['purchase_price'] = $purchase_line->purchase_price;
                    $purchase_lines[$purchase_line->variation_id][$k]['purchase_line_id'] = $purchase_line->id;
                    $purchase_lines[$purchase_line->variation_id][$k]['exp_date'] = $purchase_line->exp_date;
                    $purchase_lines[$purchase_line->variation_id][$k]['lot_number'] = $purchase_line->lot_number;
                    $purchase_lines[$purchase_line->variation_id][$k]['transaction_date'] = $this->productUtil->format_date($transaction->transaction_date, true);

                    $purchase_lines[$purchase_line->variation_id][$k]['purchase_line_note'] = $transaction->additional_notes;
                    $purchase_lines[$purchase_line->variation_id][$k]['location_id'] = $transaction->location_id;
                    $purchase_lines[$purchase_line->variation_id][$k]['secondary_unit_quantity'] = $purchase_line->secondary_unit_quantity;
                }
            }

            foreach ($purchase_lines as $v_id => $pls) {
                foreach ($pls as $pl) {
                    $purchases[$pl['location_id']][$v_id][] = $pl;
                }
            }

            $locations = BusinessLocation::forDropdown($business_id);

            //Unset locations where product is not available
            $available_locations = $product->product_locations->pluck('id')->toArray();
            foreach ($locations as $key => $value) {
                if (! in_array($key, $available_locations)) {
                    unset($locations[$key]);
                }
            }

            $enable_expiry = request()->session()->get('business.enable_product_expiry');
            $enable_lot = request()->session()->get('business.enable_lot_number');

            if (request()->ajax()) {
                return view('opening_stock.ajax_add')
                    ->with(compact(
                        'product',
                        'locations',
                        'purchases',
                        'enable_expiry',
                        'enable_lot'
                    ));
            }

            return view('opening_stock.add')
                    ->with(compact(
                        'product',
                        'locations',
                        'purchases',
                        'enable_expiry',
                        'enable_lot'
                    ));
        }
    }

    /**
     * Fetch existing opening stock lines by lot number (AJAX).
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function fetchByLot(Request $request)
    {
        if (! auth()->user()->can('product.opening_stock')) {
            abort(403, 'Unauthorized action.');
        }
    
        try {
            $business_id = $request->session()->get('user.business_id');
            $lot_number  = $request->input('lot_number');
            $location_id = $request->input('location_key'); 
            // You might also need $product_id if your form or table is product-specific:
            $product_id  = $request->input('product_id'); 
    
            // We’ll find all "opening_stock" transactions that match:
            // - This business
            // - This location
            // - This product (if you’re tying it to a single product_id)
            // - Have purchase_lines with the given lot_number
            $query = Transaction::where('business_id', $business_id)
                ->where('type', 'opening_stock');
    
            // If your user chooses location first, limit by that location
            if (!empty($location_id)) {
                $query->where('location_id', $location_id);
            }
    
            // If your page is product-specific, limit by product_id
            if (!empty($product_id)) {
                $query->where('opening_stock_product_id', $product_id);
            }
    
            // Only transactions that have a purchase_line with that lot_number
            $query->whereHas('purchase_lines', function ($q) use ($lot_number) {
                $q->where('lot_number', $lot_number);
            });
    
            // Eager load purchase_lines with product relationship to get product name
            $transactions = $query->with([
                'purchase_lines' => function($q) use ($lot_number) {
                    $q->where('lot_number', $lot_number)
                      ->with('product');  // So we can get product name, etc.
                }
            ])->get();
    
            $data = [];
    
            // Build an array for the front-end
            foreach ($transactions as $transaction) {
                foreach ($transaction->purchase_lines as $pl) {
                    // Some conversions/formatting if needed
                    $formatted_exp_date = null;
                    if (!empty($pl->exp_date)) {
                        $formatted_exp_date = $pl->exp_date->format('Y-m-d');
                    }
    
                    $data[] = [
                        'product_name'        => optional($pl->product)->name,
                        'quantity'            => $pl->quantity_remaining,
                        'purchase_price'      => $pl->purchase_price,
                        'exp_date'            => $formatted_exp_date,
                        'lot_number'          => $pl->lot_number,
                        'transaction_date'    => $transaction->transaction_date->format('Y-m-d'),
                        'purchase_line_note'  => $transaction->additional_notes,
                    ];
                }
            }
    
            return response()->json($data);
        } catch (\Exception $e) {
            \Log::error('Error fetching by lot: ' . $e->getMessage());
            return response()->json([], 500);
        }
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function save(Request $request)
    {
        if (! auth()->user()->can('product.opening_stock')) {
            abort(403, 'Unauthorized action.');
        }
    
        try {
            $opening_stocks = $request->input('stocks');
            $product_id = $request->input('product_id');
    
            $business_id = $request->session()->get('user.business_id');
            $user_id = $request->session()->get('user.id');
    
            $product = Product::where('business_id', $business_id)
                ->where('id', $product_id)
                ->with(['variations', 'product_tax'])
                ->first();
    
            $locations = BusinessLocation::forDropdown($business_id)->toArray();
    
            if (!empty($product) && $product->enable_stock == 1) {
                //Get product tax
                $tax_percent = ! empty($product->product_tax->amount)
                    ? $product->product_tax->amount
                    : 0;
                $tax_id = ! empty($product->product_tax->id)
                    ? $product->product_tax->id
                    : null;
    
                //Get start date for financial year
                $transaction_date = $request->session()
                    ->get('financial_year.start');
                $transaction_date = \Carbon::createFromFormat('Y-m-d', $transaction_date)
                    ->toDateTimeString();
    
                DB::beginTransaction();
    
                // Loop each location
                foreach ($opening_stocks as $location_id => $value) {
    
                    //Check if valid location
                    if (! array_key_exists($location_id, $locations)) {
                        continue;
                    }
    
                    // We'll group new purchase lines & existing purchase lines here
                    $new_purchase_lines = [];
                    $edit_purchase_lines = [];
                    $new_transaction_data = [];
                    $edit_transaction_data = [];
    
                    // Loop each variation ID => lines
                    foreach ($value as $vid => $purchase_lines_data) {
                        // For each row in the form for that variation
                        foreach ($purchase_lines_data as $k => $pl) {
                            $purchase_price = $this->productUtil->num_uf(trim($pl['purchase_price']));
                            $item_tax = $this->productUtil->calc_percentage($purchase_price, $tax_percent);
                            $purchase_price_inc_tax = $purchase_price + $item_tax;
    
                            $qty_remaining = $this->productUtil->num_uf(trim($pl['quantity']));
                            $secondary_unit_quantity = isset($pl['secondary_unit_quantity'])
                                ? $this->productUtil->num_uf(trim($pl['secondary_unit_quantity']))
                                : 0;
    
                            $exp_date = null;
                            if (!empty($pl['exp_date'])) {
                                $exp_date = $this->productUtil->uf_date($pl['exp_date']);
                            }
    
                            $lot_number = !empty($pl['lot_number'])
                                ? $pl['lot_number']
                                : null;
    
                            $purchase_line_note = !empty($pl['purchase_line_note'])
                                ? $pl['purchase_line_note']
                                : null;
    
                            $line_transaction_date = !empty($pl['transaction_date'])
                                ? $this->productUtil->uf_date($pl['transaction_date'], true)
                                : $transaction_date;
    
                            // Check if line references an existing purchase_line
                            $purchase_line = null;
    
                            if (!empty($pl['purchase_line_id'])) {
                                // Existing line => update it
                                $purchase_line = PurchaseLine::findOrFail($pl['purchase_line_id']);
    
                                // Adjust quantity
                                $qty_remaining = $qty_remaining + $purchase_line->quantity_used;
    
                                if ($qty_remaining != 0) {
                                    // Adjust product quantity in product_locations
                                    $old_qty = $purchase_line->quantity;
                                    $this->productUtil->updateProductQuantity(
                                        $location_id,
                                        $product->id,
                                        $vid,
                                        $qty_remaining,
                                        $old_qty,
                                        null,
                                        false
                                    );
                                }
                            } else {
                                // No purchase_line_id => new line
                                if ($qty_remaining != 0) {
                                    $purchase_line = new PurchaseLine();
                                    $purchase_line->product_id = $product->id;
                                    $purchase_line->variation_id = $vid;
    
                                    // Increase stock
                                    $this->productUtil->updateProductQuantity(
                                        $location_id,
                                        $product->id,
                                        $vid,
                                        $qty_remaining,
                                        0,
                                        null,
                                        false
                                    );
                                }
                            }
    
                            // If we have a valid line to store
                            if (! is_null($purchase_line)) {
                                $purchase_line->item_tax = $item_tax;
                                $purchase_line->tax_id = $tax_id;
                                $purchase_line->quantity = $qty_remaining;
                                $purchase_line->pp_without_discount = $purchase_price;
                                $purchase_line->purchase_price = $purchase_price;
                                $purchase_line->purchase_price_inc_tax = $purchase_price_inc_tax;
                                $purchase_line->exp_date = $exp_date;
                                $purchase_line->lot_number = $lot_number;
                                $purchase_line->secondary_unit_quantity = $secondary_unit_quantity;
                            }
    
                            if (! empty($purchase_line) && ! empty($purchase_line->transaction_id)) {
                                // This line belongs to an existing transaction => edit
                                $edit_purchase_lines[$purchase_line->transaction_id][] = $purchase_line;
    
                                $purchase_line->save();
    
                                $edit_transaction_data[$purchase_line->transaction_id] = [
                                    'transaction_date'   => $line_transaction_date,
                                    'additional_notes'   => $purchase_line_note,
                                ];
                            } else {
                                // This is a newly created line => new transaction
                                if (! empty($purchase_line)) {
                                    $new_purchase_lines[] = $purchase_line;
                                    $new_transaction_data[] = [
                                        'transaction_date'  => $line_transaction_date,
                                        'additional_notes'  => $purchase_line_note,
                                    ];
                                }
                            }
                        } // end foreach row
                    } // end foreach variation
    
                    // -----------------------------------------
                    // Process existing lines => update transaction
                    // -----------------------------------------
                    if (! empty($edit_purchase_lines)) {
                        foreach ($edit_purchase_lines as $t_id => $p_lines) {
                            $purchase_total = 0;
                            foreach ($p_lines as $p_line) {
                                // total = sum of purchase_price_inc_tax * quantity
                                $purchase_total += $p_line->purchase_price_inc_tax * $p_line->quantity;
                            }
    
                            // Find the existing transaction
                            $transaction = Transaction::where('type', 'opening_stock')
                                ->where('business_id', $business_id)
                                ->where('location_id', $location_id)
                                ->find($t_id);
    
                            if (!empty($transaction)) {
                                $transaction->total_before_tax = $purchase_total;
                                $transaction->final_total = $purchase_total;
    
                                $transaction->transaction_date = $edit_transaction_data[$t_id]['transaction_date'];
                                $transaction->additional_notes = $edit_transaction_data[$t_id]['additional_notes'];
                                $transaction->update();
    
                                // Adjust stock overselling if needed
                                $this->productUtil->adjustStockOverSelling($transaction);
    
                                // Adjust purchase-sell mappings (if any)
                                $this->transactionUtil->adjustMappingPurchaseSellAfterEditingPurchase(
                                    'received',
                                    $transaction
                                );
                            }
                        }
                    }
    
                    // -----------------------------------------
                    // Create new transactions for new lines
                    // -----------------------------------------
                    if (! empty($new_purchase_lines)) {
                        foreach ($new_purchase_lines as $index => $new_purchase_line) {
                            if (empty($new_purchase_line)) {
                                continue;
                            }
                            $purchase_total = $new_purchase_line->purchase_price_inc_tax * $new_purchase_line->quantity;
    
                            $transaction = Transaction::create([
                                'type' => 'opening_stock',
                                'opening_stock_product_id' => $product->id,
                                'status' => 'received',
                                'business_id' => $business_id,
                                'transaction_date' => $new_transaction_data[$index]['transaction_date'],
                                'additional_notes' => $new_transaction_data[$index]['additional_notes'],
                                'total_before_tax' => $purchase_total,
                                'location_id'      => $location_id,
                                'final_total'      => $purchase_total,
                                'payment_status'   => 'paid',
                                'created_by'       => $user_id,
                            ]);
    
                            $transaction->purchase_lines()->saveMany([$new_purchase_line]);
    
                            // Adjust over selling
                            $this->productUtil->adjustStockOverSelling($transaction);
                        }
                    }
    
                    // --------------------------------------------------------
                    // IMPORTANT: We do NOT delete lines or transactions
                    //            that weren't in the form => they remain
                    // --------------------------------------------------------
    
                } // end foreach location
    
                DB::commit();
            }
    
            $output = [
                'success' => 1,
                'msg' => __('lang_v1.opening_stock_added_successfully'),
            ];
        } catch (\Exception $e) {
            DB::rollBack();
            \Log::emergency('File:'.$e->getFile().' Line:'.$e->getLine().' Message:'.$e->getMessage());
    
            $output = [
                'success' => 0,
                'msg' => $e->getMessage(),
            ];
    
            return back()->with('status', $output);
        }
    
        if ($request->ajax()) {
            return $output;
        }
    
        return redirect('products')->with('status', $output);
    }

}
