<?php

namespace App\Http\Controllers;

use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderItem;
use App\Models\Supplier;
use App\Models\Warehouse;
use App\Models\InventoryItem;
use App\Models\InventoryStock;
use App\Models\InventoryTransaction;
use App\Models\InventoryBatch;
use App\Models\InventorySerial;
use App\Models\Company;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

class PurchaseOrderController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $user = Auth::user();
        $company = $user->company;

        $suppliers = Supplier::where('company_id', $company->id)
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        $warehouses = Warehouse::where('company_id', $company->id)
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        $query = PurchaseOrder::where('company_id', $company->id)
            ->with(['supplier', 'warehouse', 'creator', 'approver']);

        // Filter by supplier
        if ($request->has('supplier_id') && $request->supplier_id) {
            $query->where('supplier_id', $request->supplier_id);
        }

        // Filter by warehouse
        if ($request->has('warehouse_id') && $request->warehouse_id) {
            $query->where('warehouse_id', $request->warehouse_id);
        }

        // Filter by status
        if ($request->has('status') && $request->status) {
            $query->where('status', $request->status);
        }

        // Filter by date range
        if ($request->has('date_from') && $request->date_from) {
            $query->whereDate('order_date', '>=', $request->date_from);
        }

        if ($request->has('date_to') && $request->date_to) {
            $query->whereDate('order_date', '<=', $request->date_to);
        }

        $purchaseOrders = $query->orderBy('order_date', 'desc')->paginate(20);

        return view('inventory.purchase_orders.index', compact('purchaseOrders', 'suppliers', 'warehouses'));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        $user = Auth::user();
        $company = $user->company;

        $suppliers = Supplier::where('company_id', $company->id)
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        $warehouses = Warehouse::where('company_id', $company->id)
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        $items = InventoryItem::where('company_id', $company->id)
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        return view('inventory.purchase_orders.create', compact('suppliers', 'warehouses', 'items'));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $user = Auth::user();
        $company = $user->company;

        $validator = Validator::make($request->all(), [
            'supplier_id' => 'required|exists:suppliers,id',
            'warehouse_id' => 'required|exists:warehouses,id',
            'po_number' => 'required|string|max:50|unique:purchase_orders,po_number',
            'order_date' => 'required|date',
            'expected_delivery_date' => 'required|date|after_or_equal:order_date',
            'payment_terms' => 'nullable|string|max:255',
            'shipping_method' => 'nullable|string|max:255',
            'notes' => 'nullable|string',
            'internal_notes' => 'nullable|string',
            'items' => 'required|array|min:1',
            'items.*.item_id' => 'required|exists:inventory_items,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_price' => 'required|numeric|min:0',
            'items.*.tax_rate' => 'nullable|numeric|min:0',
            'items.*.discount_amount' => 'nullable|numeric|min:0',
            'items.*.notes' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        // Calculate totals
        $subtotal = 0;
        $taxAmount = 0;
        $discountAmount = 0;

        foreach ($request->items as $item) {
            $itemSubtotal = $item['quantity'] * $item['unit_price'];
            $itemTaxAmount = isset($item['tax_rate']) ? ($itemSubtotal * $item['tax_rate'] / 100) : 0;
            $itemDiscountAmount = isset($item['discount_amount']) ? $item['discount_amount'] : 0;

            $subtotal += $itemSubtotal;
            $taxAmount += $itemTaxAmount;
            $discountAmount += $itemDiscountAmount;
        }

        $totalAmount = $subtotal + $taxAmount - $discountAmount;

        // Begin transaction
        DB::beginTransaction();

        try {
            // Create purchase order
            $purchaseOrder = new PurchaseOrder();
            $purchaseOrder->company_id = $company->id;
            $purchaseOrder->supplier_id = $request->supplier_id;
            $purchaseOrder->warehouse_id = $request->warehouse_id;
            $purchaseOrder->created_by = $user->id;
            $purchaseOrder->po_number = $request->po_number;
            $purchaseOrder->order_date = $request->order_date;
            $purchaseOrder->expected_delivery_date = $request->expected_delivery_date;
            $purchaseOrder->status = 'pending';
            $purchaseOrder->subtotal = $subtotal;
            $purchaseOrder->tax_amount = $taxAmount;
            $purchaseOrder->discount_amount = $discountAmount;
            $purchaseOrder->total_amount = $totalAmount;
            $purchaseOrder->payment_terms = $request->payment_terms;
            $purchaseOrder->shipping_method = $request->shipping_method;
            $purchaseOrder->notes = $request->notes;
            $purchaseOrder->internal_notes = $request->internal_notes;
            $purchaseOrder->save();

            // Create purchase order items
            foreach ($request->items as $item) {
                $itemSubtotal = $item['quantity'] * $item['unit_price'];
                $itemTaxAmount = isset($item['tax_rate']) ? ($itemSubtotal * $item['tax_rate'] / 100) : 0;
                $itemDiscountAmount = isset($item['discount_amount']) ? $item['discount_amount'] : 0;
                $itemTotal = $itemSubtotal + $itemTaxAmount - $itemDiscountAmount;

                $purchaseOrderItem = new PurchaseOrderItem();
                $purchaseOrderItem->purchase_order_id = $purchaseOrder->id;
                $purchaseOrderItem->item_id = $item['item_id'];
                $purchaseOrderItem->quantity = $item['quantity'];
                $purchaseOrderItem->received_quantity = 0;
                $purchaseOrderItem->unit_price = $item['unit_price'];
                $purchaseOrderItem->tax_rate = isset($item['tax_rate']) ? $item['tax_rate'] : 0;
                $purchaseOrderItem->tax_amount = $itemTaxAmount;
                $purchaseOrderItem->discount_amount = $itemDiscountAmount;
                $purchaseOrderItem->total_amount = $itemTotal;
                $purchaseOrderItem->notes = isset($item['notes']) ? $item['notes'] : null;
                $purchaseOrderItem->save();
            }

            DB::commit();

            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('success', 'تم إنشاء أمر الشراء بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();

            return redirect()->back()
                ->with('error', 'حدث خطأ أثناء إنشاء أمر الشراء: ' . $e->getMessage())
                ->withInput();
        }
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $user = Auth::user();
        $company = $user->company;

        $purchaseOrder = PurchaseOrder::where('company_id', $company->id)
            ->where('id', $id)
            ->with(['supplier', 'warehouse', 'items.item', 'creator', 'approver', 'transactions'])
            ->firstOrFail();

        return view('inventory.purchase_orders.show', compact('purchaseOrder'));
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $user = Auth::user();
        $company = $user->company;

        $purchaseOrder = PurchaseOrder::where('company_id', $company->id)
            ->where('id', $id)
            ->with(['supplier', 'warehouse', 'items.item'])
            ->firstOrFail();

        // Only pending purchase orders can be edited
        if ($purchaseOrder->status != 'pending') {
            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('error', 'لا يمكن تعديل أمر الشراء بعد الموافقة عليه أو استلامه');
        }

        $suppliers = Supplier::where('company_id', $company->id)
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        $warehouses = Warehouse::where('company_id', $company->id)
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        $items = InventoryItem::where('company_id', $company->id)
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        return view('inventory.purchase_orders.edit', compact('purchaseOrder', 'suppliers', 'warehouses', 'items'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $user = Auth::user();
        $company = $user->company;

        $purchaseOrder = PurchaseOrder::where('company_id', $company->id)
            ->where('id', $id)
            ->firstOrFail();

        // Only pending purchase orders can be edited
        if ($purchaseOrder->status != 'pending') {
            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('error', 'لا يمكن تعديل أمر الشراء بعد الموافقة عليه أو استلامه');
        }

        $validator = Validator::make($request->all(), [
            'supplier_id' => 'required|exists:suppliers,id',
            'warehouse_id' => 'required|exists:warehouses,id',
            'po_number' => 'required|string|max:50|unique:purchase_orders,po_number,' . $purchaseOrder->id,
            'order_date' => 'required|date',
            'expected_delivery_date' => 'required|date|after_or_equal:order_date',
            'payment_terms' => 'nullable|string|max:255',
            'shipping_method' => 'nullable|string|max:255',
            'notes' => 'nullable|string',
            'internal_notes' => 'nullable|string',
            'items' => 'required|array|min:1',
            'items.*.item_id' => 'required|exists:inventory_items,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_price' => 'required|numeric|min:0',
            'items.*.tax_rate' => 'nullable|numeric|min:0',
            'items.*.discount_amount' => 'nullable|numeric|min:0',
            'items.*.notes' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        // Calculate totals
        $subtotal = 0;
        $taxAmount = 0;
        $discountAmount = 0;

        foreach ($request->items as $item) {
            $itemSubtotal = $item['quantity'] * $item['unit_price'];
            $itemTaxAmount = isset($item['tax_rate']) ? ($itemSubtotal * $item['tax_rate'] / 100) : 0;
            $itemDiscountAmount = isset($item['discount_amount']) ? $item['discount_amount'] : 0;

            $subtotal += $itemSubtotal;
            $taxAmount += $itemTaxAmount;
            $discountAmount += $itemDiscountAmount;
        }

        $totalAmount = $subtotal + $taxAmount - $discountAmount;

        // Begin transaction
        DB::beginTransaction();

        try {
            // Update purchase order
            $purchaseOrder->supplier_id = $request->supplier_id;
            $purchaseOrder->warehouse_id = $request->warehouse_id;
            $purchaseOrder->po_number = $request->po_number;
            $purchaseOrder->order_date = $request->order_date;
            $purchaseOrder->expected_delivery_date = $request->expected_delivery_date;
            $purchaseOrder->subtotal = $subtotal;
            $purchaseOrder->tax_amount = $taxAmount;
            $purchaseOrder->discount_amount = $discountAmount;
            $purchaseOrder->total_amount = $totalAmount;
            $purchaseOrder->payment_terms = $request->payment_terms;
            $purchaseOrder->shipping_method = $request->shipping_method;
            $purchaseOrder->notes = $request->notes;
            $purchaseOrder->internal_notes = $request->internal_notes;
            $purchaseOrder->save();

            // Delete existing items
            $purchaseOrder->items()->delete();

            // Create new purchase order items
            foreach ($request->items as $item) {
                $itemSubtotal = $item['quantity'] * $item['unit_price'];
                $itemTaxAmount = isset($item['tax_rate']) ? ($itemSubtotal * $item['tax_rate'] / 100) : 0;
                $itemDiscountAmount = isset($item['discount_amount']) ? $item['discount_amount'] : 0;
                $itemTotal = $itemSubtotal + $itemTaxAmount - $itemDiscountAmount;

                $purchaseOrderItem = new PurchaseOrderItem();
                $purchaseOrderItem->purchase_order_id = $purchaseOrder->id;
                $purchaseOrderItem->item_id = $item['item_id'];
                $purchaseOrderItem->quantity = $item['quantity'];
                $purchaseOrderItem->received_quantity = 0;
                $purchaseOrderItem->unit_price = $item['unit_price'];
                $purchaseOrderItem->tax_rate = isset($item['tax_rate']) ? $item['tax_rate'] : 0;
                $purchaseOrderItem->tax_amount = $itemTaxAmount;
                $purchaseOrderItem->discount_amount = $itemDiscountAmount;
                $purchaseOrderItem->total_amount = $itemTotal;
                $purchaseOrderItem->notes = isset($item['notes']) ? $item['notes'] : null;
                $purchaseOrderItem->save();
            }

            DB::commit();

            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('success', 'تم تحديث أمر الشراء بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();

            return redirect()->back()
                ->with('error', 'حدث خطأ أثناء تحديث أمر الشراء: ' . $e->getMessage())
                ->withInput();
        }
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $user = Auth::user();
        $company = $user->company;

        $purchaseOrder = PurchaseOrder::where('company_id', $company->id)
            ->where('id', $id)
            ->firstOrFail();

        // Only pending purchase orders can be deleted
        if ($purchaseOrder->status != 'pending') {
            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('error', 'لا يمكن حذف أمر الشراء بعد الموافقة عليه أو استلامه');
        }

        // Begin transaction
        DB::beginTransaction();

        try {
            // Delete purchase order items
            $purchaseOrder->items()->delete();

            // Delete purchase order
            $purchaseOrder->delete();

            DB::commit();

            return redirect()->route('inventory.purchase-orders.index')
                ->with('success', 'تم حذف أمر الشراء بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();

            return redirect()->back()
                ->with('error', 'حدث خطأ أثناء حذف أمر الشراء: ' . $e->getMessage());
        }
    }

    /**
     * Show the form for receiving purchase order.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function receiveForm($id)
    {
        $user = Auth::user();
        $company = $user->company;

        $purchaseOrder = PurchaseOrder::where('company_id', $company->id)
            ->where('id', $id)
            ->with(['supplier', 'warehouse', 'items.item'])
            ->firstOrFail();

        // Only approved purchase orders can be received
        if ($purchaseOrder->status != 'approved' && $purchaseOrder->status != 'partially_received') {
            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('error', 'يجب الموافقة على أمر الشراء قبل استلامه');
        }

        return view('inventory.purchase_orders.receive', compact('purchaseOrder'));
    }

    /**
     * Receive purchase order.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function receive(Request $request, $id)
    {
        $user = Auth::user();
        $company = $user->company;

        $purchaseOrder = PurchaseOrder::where('company_id', $company->id)
            ->where('id', $id)
            ->with(['supplier', 'warehouse', 'items.item'])
            ->firstOrFail();

        // Only approved purchase orders can be received
        if ($purchaseOrder->status != 'approved' && $purchaseOrder->status != 'partially_received') {
            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('error', 'يجب الموافقة على أمر الشراء قبل استلامه');
        }

        $validator = Validator::make($request->all(), [
            'delivery_date' => 'required|date',
            'items' => 'required|array',
            'items.*.item_id' => 'required|exists:inventory_items,id',
            'items.*.quantity' => 'required|numeric|min:0',
            'items.*.batch_number' => 'nullable|string|max:50',
            'items.*.expiry_date' => 'nullable|date',
            'items.*.serial_numbers' => 'nullable|string',
            'notes' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        // Begin transaction
        DB::beginTransaction();

        try {
            // Update purchase order
            $purchaseOrder->delivery_date = $request->delivery_date;

            // Process each item
            foreach ($request->items as $itemData) {
                $poItem = $purchaseOrder->items->where('item_id', $itemData['item_id'])->first();

                if (!$poItem) {
                    continue;
                }

                $receiveQuantity = $itemData['quantity'];

                // Skip if quantity is 0
                if ($receiveQuantity <= 0) {
                    continue;
                }

                // Make sure not to receive more than ordered
                $remainingQuantity = $poItem->quantity - $poItem->received_quantity;
                if ($receiveQuantity > $remainingQuantity) {
                    $receiveQuantity = $remainingQuantity;
                }

                // Update received quantity
                $poItem->received_quantity += $receiveQuantity;
                $poItem->save();

                // Get or create stock record
                $stock = InventoryStock::firstOrCreate(
                    [
                        'company_id' => $company->id,
                        'warehouse_id' => $purchaseOrder->warehouse_id,
                        'item_id' => $poItem->item_id,
                    ],
                    [
                        'quantity' => 0,
                        'reserved_quantity' => 0,
                    ]
                );

                // Update stock quantity
                $stock->quantity += $receiveQuantity;
                $stock->save();

                // Create inventory transaction
                $transaction = new InventoryTransaction();
                $transaction->company_id = $company->id;
                $transaction->transaction_type = 'purchase';
                $transaction->item_id = $poItem->item_id;
                $transaction->warehouse_id = $purchaseOrder->warehouse_id;
                $transaction->quantity = $receiveQuantity;
                $transaction->unit_price = $poItem->unit_price;
                $transaction->reference_number = $purchaseOrder->po_number;
                $transaction->reference_type = 'purchase_order';
                $transaction->reference_id = $purchaseOrder->id;
                $transaction->created_by = $user->id;
                $transaction->notes = $request->notes;
                $transaction->save();

                // Process batch if applicable
                $item = $poItem->item;
                if ($item->track_batches && isset($itemData['batch_number']) && $itemData['batch_number']) {
                    $batch = new InventoryBatch();
                    $batch->company_id = $company->id;
                    $batch->warehouse_id = $purchaseOrder->warehouse_id;
                    $batch->item_id = $poItem->item_id;
                    $batch->batch_number = $itemData['batch_number'];
                    $batch->quantity = $receiveQuantity;
                    $batch->purchase_date = $request->delivery_date;
                    $batch->expiry_date = isset($itemData['expiry_date']) ? $itemData['expiry_date'] : null;
                    $batch->purchase_price = $poItem->unit_price;
                    $batch->supplier_id = $purchaseOrder->supplier_id;
                    $batch->notes = $request->notes;
                    $batch->save();

                    // Update transaction with batch ID
                    $transaction->batch_id = $batch->id;
                    $transaction->save();
                }

                // Process serial numbers if applicable
                if ($item->track_serial_numbers && isset($itemData['serial_numbers']) && $itemData['serial_numbers']) {
                    $serialNumbers = explode(',', $itemData['serial_numbers']);

                    foreach ($serialNumbers as $serialNumber) {
                        $serialNumber = trim($serialNumber);

                        if (!$serialNumber) {
                            continue;
                        }

                        // Check if serial number already exists
                        $existingSerial = InventorySerial::where('company_id', $company->id)
                            ->where('serial_number', $serialNumber)
                            ->first();

                        if ($existingSerial) {
                            continue;
                        }

                        $serial = new InventorySerial();
                        $serial->company_id = $company->id;
                        $serial->warehouse_id = $purchaseOrder->warehouse_id;
                        $serial->item_id = $poItem->item_id;
                        $serial->batch_id = isset($batch) ? $batch->id : null;
                        $serial->serial_number = $serialNumber;
                        $serial->status = 'in_stock';
                        $serial->purchase_date = $request->delivery_date;
                        $serial->purchase_price = $poItem->unit_price;
                        $serial->supplier_id = $purchaseOrder->supplier_id;
                        $serial->notes = $request->notes;
                        $serial->save();
                    }
                }
            }

            // Update purchase order status
            if ($purchaseOrder->is_fully_received) {
                $purchaseOrder->status = 'completed';
            } else {
                $purchaseOrder->status = 'partially_received';
            }

            $purchaseOrder->save();

            DB::commit();

            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('success', 'تم استلام أمر الشراء بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();

            return redirect()->back()
                ->with('error', 'حدث خطأ أثناء استلام أمر الشراء: ' . $e->getMessage())
                ->withInput();
        }
    }

    /**
     * Print purchase order.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function print($id)
    {
        $user = Auth::user();
        $company = $user->company;

        $purchaseOrder = PurchaseOrder::where('company_id', $company->id)
            ->where('id', $id)
            ->with(['supplier', 'warehouse', 'items.item', 'creator', 'approver'])
            ->firstOrFail();

        return view('inventory.purchase_orders.print', compact('purchaseOrder', 'company'));
    }

    /**
     * Approve purchase order.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function approve(Request $request, $id)
    {
        $user = Auth::user();
        $company = $user->company;

        $purchaseOrder = PurchaseOrder::where('company_id', $company->id)
            ->where('id', $id)
            ->firstOrFail();

        // Only pending purchase orders can be approved
        if ($purchaseOrder->status != 'pending') {
            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('error', 'لا يمكن الموافقة على أمر الشراء لأنه ليس في حالة معلق');
        }

        $purchaseOrder->status = 'approved';
        $purchaseOrder->approved_by = $user->id;
        $purchaseOrder->approved_at = now();
        $purchaseOrder->save();

        return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
            ->with('success', 'تمت الموافقة على أمر الشراء بنجاح');
    }

    /**
     * Cancel purchase order.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function cancel(Request $request, $id)
    {
        $user = Auth::user();
        $company = $user->company;

        $purchaseOrder = PurchaseOrder::where('company_id', $company->id)
            ->where('id', $id)
            ->firstOrFail();

        // Only pending or approved purchase orders can be cancelled
        if ($purchaseOrder->status != 'pending' && $purchaseOrder->status != 'approved') {
            return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
                ->with('error', 'لا يمكن إلغاء أمر الشراء لأنه تم استلامه بالفعل');
        }

        $purchaseOrder->status = 'cancelled';
        $purchaseOrder->save();

        return redirect()->route('inventory.purchase-orders.show', $purchaseOrder->id)
            ->with('success', 'تم إلغاء أمر الشراء بنجاح');
    }
}
