<?php

namespace App\Http\Controllers;

use App\Models\Account;
use App\Models\FactoryInvoice;
use App\Models\FactoryInvoiceItem;
use App\Models\StockLedger;
use App\Services\NumberGenerationService;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Illuminate\Support\Facades\DB;
use Yajra\DataTables\Facades\DataTables;

class FactoryPOSController extends Controller
{
    protected $numberGenerationService;

    public function __construct(NumberGenerationService $numberGenerationService)
    {
        $this->numberGenerationService = $numberGenerationService;
    }

    /**
     * Display a listing of factory invoices
     */
    public function index(): View
    {
        // Get customers for filter dropdown
        $customers = Account::where('model_type', 'contact')
                           ->whereHas('contact', function($q) {
                               $q->whereIn('type', ['customer', 'shop_manager']);
                           })
                           ->where('is_active', true)
                           ->orderBy('name')
                           ->get();

        return view('factory-pos.index', compact('customers'));
    }

    /**
     * Get data for DataTables
     */
    public function getData(Request $request)
    {
        $query = FactoryInvoice::with(['customer', 'supervisingEmployee', 'warehousePicker', 'deliveryMan', 'invoiceType'])->orderBy('id', 'desc');;

        // Apply filters
        if ($request->filled('status') && $request->status !== 'all') {
            $query->where('status', $request->status);
        }

        if ($request->filled('customer_id')) {
            $query->where('customer_account_id', $request->customer_id);
        }

        // if ($request->filled('date_from') && $request->filled('date_to')) {
        //     $query->whereBetween('invoice_date', [$request->date_from, $request->date_to]);
        // }

        if ($request->filled('date_from') && $request->filled('date_to')) {
            $query->whereBetween('invoice_date', [$request->date_from, $request->date_to]);
        } elseif ($request->filled('date_from')) {
            $query->whereDate('invoice_date', '>=', $request->date_from);
        } elseif ($request->filled('date_to')) {
            $query->whereDate('invoice_date', '<=', $request->date_to);
        }


        $search = $request->input('search.value');

        if (!empty($search)) {
            $query->where(function ($q) use ($search) {
                $q->where('invoice_number', 'like', "%{$search}%")
                ->orWhere('status', 'like', "%{$search}%")
                
                ->orWhereHas('customer', function ($cq) use ($search) {
                    $cq->where('name', 'like', "%{$search}%");
                })

                ->orWhereHas('supervisingEmployee', function ($sq) use ($search) {
                    $sq->where('name', 'like', "%{$search}%");
                })

                ->orWhereHas('invoiceType', function ($tq) use ($search) {
                    $tq->where('name', 'like', "%{$search}%");
                });
            });
        }


        return DataTables::of($query)
            ->addColumn('invoice_number', function ($invoice) {
                return $invoice->invoice_number;
            })
            ->addColumn('invoice_type', function ($invoice) {
                return $invoice->invoiceType->name ?? '-';
            })
            ->addColumn('customer_name', function ($invoice) {
                return $invoice->customer->name ?? 'N/A';
            })
            ->addColumn('supervisor', function ($invoice) {
                return $invoice->supervisingEmployee->name ?? 'N/A';
            })
            ->addColumn('total_ordered_amount', function ($invoice) {
                return $invoice->total_ordered_amount;
            })
            ->addColumn('tax_amount', function ($invoice) {
                return $invoice->tax_amount;
            })
            ->addColumn('gross_total', function ($invoice) {
                return $invoice->gross_total;
            })
            ->addColumn('total_delivered_amount', function ($invoice) {
                return $invoice->total_delivered_amount;
            })
            ->addColumn('created_at', function ($invoice) {
                return $invoice->created_at;
            })
            ->addColumn('status_badge', function ($invoice) {
                $badges = [
                    'warehouse_pending' => '<span class="badge bg-warning">Warehouse Pending</span>',
                    'picked' => '<span class="badge bg-info">Picked</span>',
                    'delivered' => '<span class="badge bg-primary">Delivered</span>',
                    'completed' => '<span class="badge bg-success">Completed</span>',
                ];
                return $badges[$invoice->status] ?? '<span class="badge bg-secondary">' . ucfirst($invoice->status) . '</span>';
            })
            ->addColumn('actions', function ($invoice) {
                $actions = '<a href="' . route('factory-pos.show', $invoice) . '" class="btn btn-sm btn-info">View</a>';
                $actions .= '&nbsp;<a href="' . route('factory-pos.print', $invoice) . '" class="btn btn-sm btn-secondary" target="_blank">Print</a>';

                return $actions;
            })
            ->rawColumns(['status_badge', 'actions'])
            ->make(true);
    }

    /**
     * Show the form for creating a new invoice
     */
    public function create(): View
    {
        // Get customers (accounts with model_type = contact and contact type = customer or shop_manager)
        $customers = Account::select('id','name')
                        //    ->whereHas('contact', function($q) {
                        //        $q->whereIn('type', ['customer', 'shop_manager']);
                        //    })
                        ->whereIn('model_type', ['customer', 'shop_manager'])
                           ->where('is_active', true)
                           ->orderBy('name')
                           ->get();
        // dd($customers);
        // Get supervising employees
        $employees = Account::select('id','name')
                        //    ->whereHas('contact', function($q) {
                        //        $q->where('type', 'employee');
                        //    })
                        ->whereIn('model_type', ['employee'])

                           ->where('is_active', true)
                           ->orderBy('name')
                           ->get();

        $invoiceTypes = \App\Models\InvoiceType::where('is_active', true)->orderBy('name')->get();

        return view('factory-pos.create', compact('customers', 'employees', 'invoiceTypes'));
    }

    /**
     * Store a newly created invoice
     */
    public function store(Request $request): RedirectResponse
    {
        $request->validate([
            'invoice_type_id' => 'required|exists:invoice_types,id',
            'customer_id' => 'required|exists:accounts,id',
            'supervising_employee_id' => 'required|exists:accounts,id',
            'tax_amount' => 'nullable|numeric|min:0',
            'gross_total' => 'nullable|numeric|min:0',
            'discount_amount' => 'nullable|numeric|min:0',
            'discount_percentage' => 'nullable|numeric|min:0|max:100',
            'items' => 'required|array|min:1',
            'items.*.item_id' => 'required|exists:accounts,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_price' => 'required|numeric|min:0',
        ]);

        DB::transaction(function () use ($request) {
            $invoiceType = \App\Models\InvoiceType::find($request->invoice_type_id);
            // Generate invoice number
            $invoiceNumber = $this->numberGenerationService->generateNumber('factory_invoice', $invoiceType->prefix);

            $totalAmount = 0;

            // Calculate total from items first
            foreach ($request->items as $itemData) {
                $quantity = $itemData['quantity'];
                $unitPrice = $itemData['unit_price'];
                $total = $quantity * $unitPrice;
                $totalAmount += $total;
            }

            // Calculate discount
            $discountAmount = $request->discount_amount ?? 0;
            $discountPercentage = $request->discount_percentage ?? 0;

            // If percentage is provided, calculate discount amount
            if ($discountPercentage > 0) {
                $discountAmount = ($totalAmount * $discountPercentage) / 100;
            }

            $netTotal = $totalAmount - $discountAmount;

            // Create invoice
            $invoice = FactoryInvoice::create([
                'invoice_number' => $invoiceNumber,
                'invoice_type_id' => $request->invoice_type_id,
                'customer_account_id' => $request->customer_id,
                'supervising_employee_account_id' => $request->supervising_employee_id,
                'total_ordered_amount' => $totalAmount,
                'discount_amount' => $discountAmount,
                'discount_percentage' => $discountPercentage > 0 ? $discountPercentage : null,
                'net_total' => $netTotal,
                'tax_amount' => $request->tax_amount ?? 0,
                'gross_total' => $request->gross_total ?? $netTotal,
                'status' => 'warehouse_pending',
                'invoice_date' => now(),
            ]);

            // Create invoice items
            foreach ($request->items as $itemData) {
                $quantity = $itemData['quantity'];
                $unitPrice = $itemData['unit_price'];
                $total = $quantity * $unitPrice;

                FactoryInvoiceItem::create([
                    'factory_invoice_id' => $invoice->id,
                    'item_account_id' => $itemData['item_id'],
                    'ordered_quantity' => $quantity,
                    'ordered_unit_price' => $unitPrice,
                    'ordered_total' => $total,
                ]);
            }
        });

        return redirect()->route('factory-pos.index')->with('success', 'Factory invoice created successfully');
    }

    /**
     * Store factory invoice via API
     */
    public function storeApi(Request $request)
    {
        $request->validate([
            'invoice_type_id' => 'required|exists:invoice_types,id',
            'customer_id' => 'required|exists:accounts,id',
            'supervising_employee_id' => 'required|exists:accounts,id',
            'tax_amount' => 'nullable|numeric|min:0',
            'gross_total' => 'nullable|numeric|min:0',
            'discount_amount' => 'nullable|numeric|min:0',
            'discount_percentage' => 'nullable|numeric|min:0|max:100',
            'items' => 'required|array|min:1',
            'items.*.item_id' => 'required|exists:accounts,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_price' => 'required|numeric|min:0',
            'items.*.warehouse_id' => 'required|exists:warehouses,id',
            'items.*.length' => 'nullable|numeric',
        ]);

        try {
            DB::transaction(function () use ($request) {
                // Simple invoice number generation (without service class)
                $currentYear = now()->format('Y');
                $currentMonth = now()->format('m');
                $invoiceType = \App\Models\InvoiceType::find($request->invoice_type_id);
                $prefix = rtrim($invoiceType->prefix, '-');

                // Get last invoice number for current month
                $lastInvoice = FactoryInvoice::where('invoice_number', 'like', "{$prefix}-{$currentYear}{$currentMonth}-%")
                    ->orderBy('invoice_number', 'desc')
                    ->first();

                $sequence = 1;
                if ($lastInvoice) {
                    $parts = explode('-', $lastInvoice->invoice_number);
                    $sequence = (int) end($parts) + 1;
                }

                $invoiceNumber = sprintf("%s-%s%s-%03d", $prefix, $currentYear, $currentMonth, $sequence);

                $totalAmount = 0;

                // Calculate total from items first
                foreach ($request->items as $itemData) {
                    $quantity = $itemData['quantity'];
                    $unitPrice = $itemData['unit_price'];
                    $total = $quantity * $unitPrice;
                    $totalAmount += $total;
                }

                // Calculate discount
                $discountAmount = $request->discount_amount ?? 0;
                $discountPercentage = $request->discount_percentage ?? 0;

                // If percentage is provided, calculate discount amount
                if ($discountPercentage > 0) {
                    $discountAmount = ($totalAmount * $discountPercentage) / 100;
                }

                $netTotal = $totalAmount - $discountAmount;

                // Create invoice
                $invoice = FactoryInvoice::create([
                    'invoice_number' => $invoiceNumber,
                    'invoice_type_id' => $request->invoice_type_id,
                    'customer_account_id' => $request->customer_id,
                    'supervising_employee_account_id' => $request->supervising_employee_id,
                    'total_ordered_amount' => $totalAmount,
                    'discount_amount' => $discountAmount,
                    'discount_percentage' => $discountPercentage > 0 ? $discountPercentage : null,
                    'net_total' => $netTotal,
                    'tax_amount' => $request->tax_amount ?? 0,
                    'gross_total' => $request->gross_total ?? $netTotal,
                    'status' => 'warehouse_pending',
                    'invoice_date' => now(),
                ]);

                // Create invoice items
                foreach ($request->items as $itemData) {
                    $quantity = $itemData['quantity'];
                    $unitPrice = $itemData['unit_price'];
                    $total = $quantity * $unitPrice;

                    FactoryInvoiceItem::create([
                        'factory_invoice_id' => $invoice->id,
                        'item_account_id' => $itemData['item_id'],
                        'ordered_quantity' => $quantity,
                        'ordered_unit_price' => $unitPrice,
                        'ordered_total' => $total,
                        'warehouse_id' => $itemData['warehouse_id'],
                        'length' => $itemData['length'] ?? null,
                    ]);

                    // Record stock deduction in ledger
                    // StockLedger::create([
                    //     'factory_invoice_id' => $invoice->id,
                    //     'account_id' => $itemData['item_id'],
                    //     'warehouse_id' => $itemData['warehouse_id'],
                    //     'quantity' => -$quantity, // Negative for sale
                    //     'length' => $itemData['length'] ?? null,
                    //     'remarks' => 'Sold via POS - Invoice ' . $invoice->invoice_number,
                    //     'timestamp' => now(),
                    // ]);
                }
            });

            return response()->json([
                'success' => true,
                'data' => null,
                'message' => 'Factory invoice created successfully'
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'data' => null,
                'message' => 'Validation failed',
                'errors' => $e->errors()
            ], 422);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'data' => null,
                'message' => 'Failed to create invoice: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Display the specified invoice
     */
    public function show($id): View
    {
        $invoice = FactoryInvoice::findOrFail($id);
        $invoice->load(['customer', 'supervisingEmployee', 'items.item', 'warehousePicker', 'deliveryMan', 'deliveryReceipts.items']);
        return view('factory-pos.show', compact('invoice'));
    }

    /**
     * Display the unified invoice view (Factory POS)
     */
    public function invoiceShow($id): View
    {
        $invoice = FactoryInvoice::findOrFail($id);
        $invoice->load([
            'customer', 
            'supervisingEmployee', 
            'items.item', 
            'deliveryReceipts.items.gatePassItem',
            'deliveryReceipts.deliveryMan'
        ]);
        
        return view('factory-pos.invoice-show', compact('invoice'));
    }

    /**
     * Show the form for editing the invoice (only if warehouse_pending)
     */
    public function edit($id): View
    {
        $invoice = FactoryInvoice::findOrFail($id);

        if (!$invoice->isPendingWarehouse()) {
            abort(403, 'Cannot edit invoice that has been processed');
        }

        $customers = Account::where('model_type', 'contact')
                           ->whereHas('contact', function($q) {
                               $q->whereIn('type', ['customer', 'shop_manager']);
                           })
                           ->where('is_active', true)
                           ->orderBy('name')
                           ->get();

        $employees = Account::where('model_type', 'contact')
                           ->whereHas('contact', function($q) {
                               $q->where('type', 'employee');
                           })
                           ->where('is_active', true)
                           ->orderBy('name')
                           ->get();

        return view('factory-pos.edit', compact('invoice', 'customers', 'employees'));
    }

    /**
     * Update the specified invoice
     */
    public function update(Request $request, $id): RedirectResponse
    {
        $invoice = FactoryInvoice::findOrFail($id);

        if (!$invoice->isPendingWarehouse()) {
            abort(403, 'Cannot edit invoice that has been processed');
        }

        $request->validate([
            'customer_id' => 'required|exists:accounts,id',
            'supervising_employee_id' => 'required|exists:accounts,id',
            'discount_amount' => 'nullable|numeric|min:0',
            'discount_percentage' => 'nullable|numeric|min:0|max:100',
            'items' => 'required|array|min:1',
            'items.*.item_id' => 'required|exists:accounts,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_price' => 'required|numeric|min:0',
        ]);

        DB::transaction(function () use ($request, $invoice) {
            $totalAmount = 0;

            // Calculate total from items first
            foreach ($request->items as $itemData) {
                $quantity = $itemData['quantity'];
                $unitPrice = $itemData['unit_price'];
                $total = $quantity * $unitPrice;
                $totalAmount += $total;
            }

            // Calculate discount
            $discountAmount = $request->discount_amount ?? 0;
            $discountPercentage = $request->discount_percentage ?? 0;

            // If percentage is provided, calculate discount amount
            if ($discountPercentage > 0) {
                $discountAmount = ($totalAmount * $discountPercentage) / 100;
            }

            $netTotal = $totalAmount - $discountAmount;

            // Update invoice
            $invoice->update([
                'customer_account_id' => $request->customer_id,
                'supervising_employee_account_id' => $request->supervising_employee_id,
                'total_ordered_amount' => $totalAmount,
                'discount_amount' => $discountAmount,
                'discount_percentage' => $discountPercentage > 0 ? $discountPercentage : null,
                'net_total' => $netTotal,
            ]);

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

            // Create new items
            foreach ($request->items as $itemData) {
                $quantity = $itemData['quantity'];
                $unitPrice = $itemData['unit_price'];
                $total = $quantity * $unitPrice;

                FactoryInvoiceItem::create([
                    'factory_invoice_id' => $invoice->id,
                    'item_account_id' => $itemData['item_id'],
                    'ordered_quantity' => $quantity,
                    'ordered_unit_price' => $unitPrice,
                    'ordered_total' => $total,
                ]);
            }
        });

        return redirect()->route('factory-pos.show', $invoice)->with('success', 'Factory invoice updated successfully');
    }

    /**
     * Get items for autocomplete with stock information
     */
    public function getItems(Request $request)
    {
        $search = $request->get('q', '');
        $showAll = $request->boolean('show_all', false);

        // Get items with their stock information (multiple entries for different lengths/warehouses)
        $query = \DB::table('accounts')
            ->join('stocks', 'accounts.id', '=', 'stocks.account_id')
            ->join('warehouses', 'stocks.warehouse_id', '=', 'warehouses.id')
            ->join('chart_of_accounts', 'accounts.chart_of_account_id', '=', 'chart_of_accounts.id')
            ->join('uoms', 'accounts.unit_of_measure', '=', 'uoms.code')
            ->where('accounts.model_type', 'Item')
            ->where('accounts.is_active', true)
            ->where('stocks.quantity', '>', 0)
            ->where('warehouses.is_active', true)
            ->where(function($q) {
                $q->where('chart_of_accounts.id', 53)
                  ->orWhere('chart_of_accounts.parent_id', 53);
            })
            ->select([
                'accounts.id as item_id',
                'accounts.name as item_name',
                'accounts.sku',
                'stocks.length',
                'stocks.quantity',
                'stocks.warehouse_id',
                'warehouses.name as warehouse_name',
                'warehouses.code as warehouse_code',
                'uoms.name as uom_name',
                \DB::raw("CONCAT(accounts.name, ' (', IFNULL(accounts.sku, 'No SKU'), ') - ', warehouses.name, ' - Length: ', IFNULL(stocks.length, 'N/A'), 'm - Qty: ', stocks.quantity) as display_text")
            ]);
            // dd($query->toSql());
        // Apply search filter only if not showing all
        if (!$showAll && !empty($search)) {
            $query->where(function($q) use ($search) {
                $q->where('accounts.name', 'like', "%{$search}%")
                  ->orWhere('accounts.sku', 'like', "%{$search}%")
                  ->orWhere('warehouses.name', 'like', "%{$search}%");
            });
        }

        $items = $query->orderBy('accounts.name')
                       ->orderBy('stocks.length')
                       ->orderBy('warehouses.name')
                       ->limit($showAll ? 50 : 10)
                       ->get();

        return response()->json([
            'results' => $items->map(function ($item) {
                return [
                    'id' => $item->item_id . '_' . $item->warehouse_id . '_' . ($item->length ?: 'null'),
                    'item_id' => $item->item_id,
                    'warehouse_id' => $item->warehouse_id,
                    'length' => $item->length,
                    'quantity' => $item->quantity,
                    'text' => $item->display_text,
                    'name' => $item->item_name,
                    'sku' => $item->sku,
                    'is_meter' => $item->uom_name == 'Meter' ? true : false,
                    'is_foot' => $item->uom_name == 'Foot' ? true : false,
                    'warehouse_name' => $item->warehouse_name,
                    'warehouse_code' => $item->warehouse_code,
                ];
            })
        ]);
    }

    /**
     * Get warehouses with stock for a specific item
     */
    public function getWarehouses(Request $request)
    {
        $itemId = $request->get('item_id');
        $search = $request->get('q', '');

        // Get warehouses that have stock for this item
        $warehouses = \App\Models\Warehouse::whereHas('stocks', function ($query) use ($itemId) {
            $query->where('item_id', $itemId)
                  ->where('quantity', '>', 0);
        })
        ->when(!empty($search), function ($query) use ($search) {
            $query->where('name', 'like', "%{$search}%");
        })
        ->with(['stocks' => function ($query) use ($itemId) {
            $query->where('item_id', $itemId);
        }])
        ->get()
        ->map(function ($warehouse) use ($itemId) {
            $stock = $warehouse->stocks->first();
            return [
                'id' => $warehouse->id,
                'name' => $warehouse->name,
                'stock' => $stock ? $stock->quantity : 0
            ];
        });

        return response()->json($warehouses);
    }

    /**
     * Print the specified invoice using its respective template
     */
    public function print($id): View
    {
        $invoice = FactoryInvoice::with([
            'customer', 
            'supervisingEmployee', 
            'items.item', 
            'invoiceType'
        ])->findOrFail($id);

        $template = 'commercial_invoice'; // Default

        if ($invoice->invoiceType) {
            // map invoice type code or name to template
            $code = strtolower($invoice->invoiceType->code);
            if (str_contains($code, 'tax')) {
                $template = 'tax_invoice';
            }
        }

        return view("factory-pos.print.{$template}", compact('invoice'));
    }
}
