<?php

namespace App\Http\Controllers\Warehouse\IndirectGoods;

use App\Http\Controllers\Controller;
use App\Models\Warehouse\IndirectGoods\IndirectGoodsIncoming;
use App\Models\Warehouse\IndirectGoods\IndirectGoodsIncomingItem;
use App\Models\Warehouse\IndirectGoods\IndirectGood;
use App\Models\Warehouse\Supplier;
use App\Models\Warehouse\Project;
use App\Models\Warehouse\ProjectDivision;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class IndirectGoodsIncomingController extends Controller
{
    /**
     * Display a listing of incoming receipts.
     */
    public function index(Request $request)
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.view')) {
            abort(403, 'Unauthorized action.');
        }

        $query = IndirectGoodsIncoming::with(['supplier', 'project', 'receiver', 'items'])
            ->latest('created_at');

        // Filter: status
        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        // Filter: date range
        if ($request->filled('date_from')) {
            $query->whereDate('created_at', '>=', $request->date_from);
        }
        if ($request->filled('date_to')) {
            $query->whereDate('created_at', '<=', $request->date_to);
        }

        // Filter: supplier
        if ($request->filled('supplier_id')) {
            $query->where('supplier_id', $request->supplier_id);
        }

        // Filter: invoice number
        if ($request->filled('invoice_number')) {
            $query->where('invoice_number', 'LIKE', '%' . $request->invoice_number . '%');
        }

        // General search
        if ($request->filled('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('receipt_number', 'LIKE', "%{$search}%")
                  ->orWhere('invoice_number', 'LIKE', "%{$search}%")
                  ->orWhereHas('supplier', function ($sq) use ($search) {
                      $sq->where('name', 'LIKE', "%{$search}%");
                  });
            });
        }

        // DataTable AJAX support
        if ($request->ajax()) {
            $receipts = $query->paginate($request->get('length', 25));

            return response()->json([
                'draw' => intval($request->get('draw')),
                'recordsTotal' => $receipts->total(),
                'recordsFiltered' => $receipts->total(),
                'data' => $receipts->items(),
            ]);
        }

        $receipts = $query->paginate(25)->withQueryString();

        $suppliers = Supplier::where('status', 'active')->orderBy('name')->get();

        return view('warehouse.indirect-goods.incoming.index', compact('receipts', 'suppliers'));
    }

    /**
     * Show the form for creating a new incoming receipt.
     */
    public function create()
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.create')) {
            abort(403, 'Unauthorized action.');
        }

        $suppliers = Supplier::where('status', 'active')->orderBy('name')->get();
        $projects = Project::orderBy('project_name')->get();
        $divisions = ProjectDivision::orderBy('division_name')->get();
        $indirectGoods = IndirectGood::where('status', 'active')->orderBy('ig_description')->get();

        return view('warehouse.indirect-goods.incoming.create', compact(
            'suppliers', 'projects', 'divisions', 'indirectGoods'
        ));
    }

    /**
     * Store a newly created incoming receipt.
     */
    public function store(Request $request)
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.create')) {
            abort(403, 'Unauthorized action.');
        }

        $request->validate([
            'supplier_id'                   => 'required|exists:suppliers,id',
            'invoice_number'                => 'required|string|max:255',
            'invoice_date'                  => 'required|date',
            'project_id'                    => 'nullable|exists:projects,id',
            'division_id'                   => 'nullable|exists:project_divisions,id',
            'notes'                         => 'nullable|string|max:2000',
            'vat_rate'                      => 'nullable|numeric|min:0|max:100',
            'items'                         => 'required|array|min:1',
            'items.*.indirect_good_id'      => 'required|exists:indirect_goods,id',
            'items.*.quantity_ordered'       => 'nullable|numeric|min:0',
            'items.*.quantity_delivered'     => 'required|numeric|min:0.01',
            'items.*.unit_price'            => 'required|numeric|min:0',
            'items.*.batch_number'          => 'nullable|string|max:255',
            'items.*.expiry_date'           => 'nullable|date',
            'items.*.notes'                 => 'nullable|string|max:500',
        ]);

        DB::beginTransaction();

        try {
            // Calculate totals
            $subtotal = 0;
            foreach ($request->items as $item) {
                $qty = floatval($item['quantity_delivered']);
                $price = floatval($item['unit_price']);
                $subtotal += $qty * $price;
            }

            $vatRate = floatval($request->input('vat_rate', 0));
            $vatAmount = $subtotal * ($vatRate / 100);
            $totalAmount = $subtotal + $vatAmount;

            // Create the incoming receipt
            $incoming = IndirectGoodsIncoming::create([
                'supplier_id'       => $request->supplier_id,
                'invoice_number'    => $request->invoice_number,
                'invoice_date'      => $request->invoice_date,
                'receipt_date'      => now(),
                'project_id'        => $request->project_id,
                'division_id'       => $request->division_id,
                'status'            => 'draft',
                'received_by'       => Auth::id(),
                'notes'             => $request->notes,
                'total_amount'      => $totalAmount,
                'vat_amount'        => $vatAmount,
                'vat_rate'          => $vatRate,
            ]);

            // Create items
            foreach ($request->items as $itemData) {
                $qtyDelivered = floatval($itemData['quantity_delivered']);
                $unitPrice = floatval($itemData['unit_price']);

                // Look up the indirect good for unit_of_measure
                $indirectGood = IndirectGood::find($itemData['indirect_good_id']);

                $incoming->items()->create([
                    'indirect_good_id'   => $itemData['indirect_good_id'],
                    'quantity_ordered'    => floatval($itemData['quantity_ordered'] ?? 0),
                    'quantity_delivered'  => $qtyDelivered,
                    'quantity_accepted'   => $qtyDelivered, // Default accepted = delivered
                    'unit_of_measure'     => $indirectGood ? $indirectGood->unit_of_measure : 'PCS',
                    'unit_price'          => $unitPrice,
                    'total_price'         => $qtyDelivered * $unitPrice,
                    'batch_number'        => $itemData['batch_number'] ?? null,
                    'expiry_date'         => $itemData['expiry_date'] ?? null,
                    'notes'               => $itemData['notes'] ?? null,
                ]);
            }

            DB::commit();

            return redirect()
                ->route('warehouse.indirect-goods.incoming.show', $incoming->id)
                ->with('success', 'Incoming receipt ' . $incoming->receipt_number . ' created successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()
                ->back()
                ->withInput()
                ->with('error', 'Failed to create incoming receipt: ' . $e->getMessage());
        }
    }

    /**
     * Display the specified incoming receipt.
     */
    public function show($id)
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.view')) {
            abort(403, 'Unauthorized action.');
        }

        $incoming = IndirectGoodsIncoming::with([
            'supplier',
            'project',
            'division',
            'receiver',
            'approver',
            'items.indirectGood',
        ])->findOrFail($id);

        return view('warehouse.indirect-goods.incoming.show', compact('incoming'));
    }

    /**
     * Show the form for editing an incoming receipt (draft only).
     */
    public function edit($id)
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.edit')) {
            abort(403, 'Unauthorized action.');
        }

        $incoming = IndirectGoodsIncoming::with(['items.indirectGood'])->findOrFail($id);

        if ($incoming->status !== 'draft') {
            return redirect()
                ->route('warehouse.indirect-goods.incoming.show', $incoming->id)
                ->with('error', 'Only draft receipts can be edited.');
        }

        $suppliers = Supplier::where('status', 'active')->orderBy('name')->get();
        $projects = Project::orderBy('project_name')->get();
        $divisions = ProjectDivision::orderBy('division_name')->get();
        $indirectGoods = IndirectGood::where('status', 'active')->orderBy('ig_description')->get();

        return view('warehouse.indirect-goods.incoming.edit', compact(
            'incoming', 'suppliers', 'projects', 'divisions', 'indirectGoods'
        ));
    }

    /**
     * Update the specified incoming receipt (draft only).
     */
    public function update(Request $request, $id)
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.edit')) {
            abort(403, 'Unauthorized action.');
        }

        $incoming = IndirectGoodsIncoming::findOrFail($id);

        if ($incoming->status !== 'draft') {
            return redirect()
                ->route('warehouse.indirect-goods.incoming.show', $incoming->id)
                ->with('error', 'Only draft receipts can be updated.');
        }

        $request->validate([
            'supplier_id'                   => 'required|exists:suppliers,id',
            'invoice_number'                => 'required|string|max:255',
            'invoice_date'                  => 'required|date',
            'project_id'                    => 'nullable|exists:projects,id',
            'division_id'                   => 'nullable|exists:project_divisions,id',
            'notes'                         => 'nullable|string|max:2000',
            'vat_rate'                      => 'nullable|numeric|min:0|max:100',
            'items'                         => 'required|array|min:1',
            'items.*.indirect_good_id'      => 'required|exists:indirect_goods,id',
            'items.*.quantity_ordered'       => 'nullable|numeric|min:0',
            'items.*.quantity_delivered'     => 'required|numeric|min:0.01',
            'items.*.unit_price'            => 'required|numeric|min:0',
            'items.*.batch_number'          => 'nullable|string|max:255',
            'items.*.expiry_date'           => 'nullable|date',
            'items.*.notes'                 => 'nullable|string|max:500',
        ]);

        DB::beginTransaction();

        try {
            // Calculate totals
            $subtotal = 0;
            foreach ($request->items as $item) {
                $qty = floatval($item['quantity_delivered']);
                $price = floatval($item['unit_price']);
                $subtotal += $qty * $price;
            }

            $vatRate = floatval($request->input('vat_rate', 0));
            $vatAmount = $subtotal * ($vatRate / 100);
            $totalAmount = $subtotal + $vatAmount;

            // Update the receipt
            $incoming->update([
                'supplier_id'       => $request->supplier_id,
                'invoice_number'    => $request->invoice_number,
                'invoice_date'      => $request->invoice_date,
                'project_id'        => $request->project_id,
                'division_id'       => $request->division_id,
                'notes'             => $request->notes,
                'total_amount'      => $totalAmount,
                'vat_amount'        => $vatAmount,
                'vat_rate'          => $vatRate,
            ]);

            // Delete existing items and recreate
            $incoming->items()->delete();

            foreach ($request->items as $itemData) {
                $qtyDelivered = floatval($itemData['quantity_delivered']);
                $unitPrice = floatval($itemData['unit_price']);

                $indirectGood = IndirectGood::find($itemData['indirect_good_id']);

                $incoming->items()->create([
                    'indirect_good_id'   => $itemData['indirect_good_id'],
                    'quantity_ordered'    => floatval($itemData['quantity_ordered'] ?? 0),
                    'quantity_delivered'  => $qtyDelivered,
                    'quantity_accepted'   => $qtyDelivered,
                    'unit_of_measure'     => $indirectGood ? $indirectGood->unit_of_measure : 'PCS',
                    'unit_price'          => $unitPrice,
                    'total_price'         => $qtyDelivered * $unitPrice,
                    'batch_number'        => $itemData['batch_number'] ?? null,
                    'expiry_date'         => $itemData['expiry_date'] ?? null,
                    'notes'               => $itemData['notes'] ?? null,
                ]);
            }

            DB::commit();

            return redirect()
                ->route('warehouse.indirect-goods.incoming.show', $incoming->id)
                ->with('success', 'Incoming receipt ' . $incoming->receipt_number . ' updated successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()
                ->back()
                ->withInput()
                ->with('error', 'Failed to update incoming receipt: ' . $e->getMessage());
        }
    }

    /**
     * Remove the specified incoming receipt (draft only).
     */
    public function destroy($id)
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.process')) {
            abort(403, 'Unauthorized action.');
        }

        $incoming = IndirectGoodsIncoming::findOrFail($id);

        if ($incoming->status !== 'draft') {
            return redirect()
                ->route('warehouse.indirect-goods.incoming.index')
                ->with('error', 'Only draft receipts can be deleted.');
        }

        DB::beginTransaction();

        try {
            $receiptNumber = $incoming->receipt_number;
            $incoming->items()->delete();
            $incoming->delete();

            DB::commit();

            return redirect()
                ->route('warehouse.indirect-goods.incoming.index')
                ->with('success', 'Incoming receipt ' . $receiptNumber . ' deleted successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()
                ->route('warehouse.indirect-goods.incoming.index')
                ->with('error', 'Failed to delete incoming receipt: ' . $e->getMessage());
        }
    }

    /**
     * Approve the incoming receipt.
     */
    public function approve($id)
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.process')) {
            abort(403, 'Unauthorized action.');
        }

        $incoming = IndirectGoodsIncoming::findOrFail($id);

        if ($incoming->status !== 'draft') {
            return redirect()
                ->route('warehouse.indirect-goods.incoming.show', $incoming->id)
                ->with('error', 'Only draft receipts can be approved.');
        }

        $incoming->update([
            'status'      => 'approved',
            'approved_by' => Auth::id(),
            'approved_at' => now(),
        ]);

        return redirect()
            ->route('warehouse.indirect-goods.incoming.show', $incoming->id)
            ->with('success', 'Incoming receipt ' . $incoming->receipt_number . ' has been approved.');
    }

    /**
     * Complete the incoming receipt and process items to inventory.
     */
    public function complete($id)
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.process')) {
            abort(403, 'Unauthorized action.');
        }

        $incoming = IndirectGoodsIncoming::with('items')->findOrFail($id);

        if ($incoming->status !== 'approved') {
            return redirect()
                ->route('warehouse.indirect-goods.incoming.show', $incoming->id)
                ->with('error', 'Only approved receipts can be completed.');
        }

        DB::beginTransaction();

        try {
            $result = $incoming->complete();

            if (!$result) {
                throw new \Exception('Failed to complete receipt. It may already be completed.');
            }

            DB::commit();

            return redirect()
                ->route('warehouse.indirect-goods.incoming.show', $incoming->id)
                ->with('success', 'Incoming receipt ' . $incoming->receipt_number . ' completed. Items have been added to inventory.');

        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()
                ->route('warehouse.indirect-goods.incoming.show', $incoming->id)
                ->with('error', 'Failed to complete receipt: ' . $e->getMessage());
        }
    }

    /**
     * Print the incoming receipt.
     */
    public function print($id)
    {
        if (!Auth::user()->can('warehouse.indirect-incoming.view')) {
            abort(403, 'Unauthorized action.');
        }

        $incoming = IndirectGoodsIncoming::with([
            'supplier',
            'project',
            'division',
            'receiver',
            'approver',
            'items.indirectGood',
        ])->findOrFail($id);

        return view('warehouse.indirect-goods.incoming.print', compact('incoming'));
    }
}
