<?php

namespace App\Http\Controllers;

use App\Models\DisposedProduct;
use App\Models\Expense;
use App\Models\InventoryLog;
use App\Models\OpeningBalance;
use App\Models\Order;
use App\Models\Product;
use App\Models\Supplier;
use App\Models\SupplierPayment;
use Carbon\Carbon;
use Illuminate\Http\Request;

class ExpenseController extends Controller
{
    public function index(Request $request)
    {
        $query = Expense::with('user');

        if ($request->category) {
            $query->where('category', $request->category);
        }

        if ($request->date_from) {
            $query->whereDate('expense_date', '>=', $request->date_from);
        }

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

        $expenses = $query->orderBy('expense_date', 'desc')->paginate(30);
        $categories = Expense::categories();

        return view('expenses.index', compact('expenses', 'categories'));
    }

    public function create()
    {
        $categories = Expense::categories();

        return view('expenses.create', compact('categories'));
    }

    public function store(Request $request)
    {
        $request->validate([
            'category' => 'required|string',
            'amount' => 'required|numeric|min:0.01',
            'description' => 'nullable|string',
            'expense_date' => 'required|date',
        ]);

        Expense::create([
            'category' => $request->category,
            'amount' => $request->amount,
            'description' => $request->description,
            'expense_date' => $request->expense_date,
            'user_id' => auth()->id(),
        ]);

        return redirect()->route('expenses.index')->with('success', 'Expense recorded successfully.');
    }

    public function destroy(Expense $expense)
    {
        $expense->delete();

        return back()->with('success', 'Expense deleted.');
    }

    public function cashflow(Request $request)
    {
        $dateFrom = $request->date_from ? Carbon::parse($request->date_from) : now()->startOfMonth();
        $dateTo = $request->date_to ? Carbon::parse($request->date_to)->endOfDay() : now()->endOfDay();

        $orders = Order::whereBetween('created_at', [$dateFrom, $dateTo])
            ->where('status', 'completed')
            ->get();

        $totalSales = $orders->sum('total');

        $totalCashPayments = 0;
        $totalMpesaPayments = 0;
        $totalCardPayments = 0;

        foreach ($orders as $order) {
            if ($order->payment_methods) {
                $methods = json_decode($order->payment_methods, true);
                if (is_array($methods)) {
                    foreach ($methods as $pm) {
                        if ($pm['method'] === 'cash') {
                            $totalCashPayments += $pm['amount'];
                        } elseif ($pm['method'] === 'mpesa') {
                            $totalMpesaPayments += $pm['amount'];
                        } elseif ($pm['method'] === 'card') {
                            $totalCardPayments += $pm['amount'];
                        }
                    }
                }
            } elseif ($order->payment_method === 'cash') {
                $totalCashPayments += $order->total;
            } elseif ($order->payment_method === 'mpesa') {
                $totalMpesaPayments += $order->total;
            } elseif ($order->payment_method === 'card') {
                $totalCardPayments += $order->total;
            }
        }

        $totalCostOfGoods = InventoryLog::whereBetween('created_at', [$dateFrom, $dateTo])
            ->where('type', 'stock_in')
            ->get()
            ->sum(function ($log) {
                return $log->quantity * $log->unit_cost;
            });

        $totalExpenses = Expense::whereBetween('expense_date', [$dateFrom, $dateTo])
            ->sum('amount');

        $expiredItemsTotal = Product::whereNotNull('expiry_date')
            ->whereDate('expiry_date', '>=', $dateFrom)
            ->whereDate('expiry_date', '<=', $dateTo)
            ->get()
            ->sum(function ($product) {
                return ($product->cost_price ?? 0) * $product->stock_quantity;
            });

        $disposedProductsTotal = DisposedProduct::whereBetween('created_at', [$dateFrom, $dateTo])
            ->sum('total_value');

        $totalValueLost = $expiredItemsTotal + $disposedProductsTotal;

        $supplierPayments = SupplierPayment::whereBetween('payment_date', [$dateFrom, $dateTo])->sum('amount');

        $totalOrderedFromSuppliers = InventoryLog::where('type', 'stock_in')
            ->whereNotNull('supplier_id')
            ->get()
            ->sum(function ($log) {
                return $log->quantity * $log->unit_cost;
            });

        $totalPaidToSuppliers = Supplier::sum('total_paid');
        $unpaidSupplierBalances = $totalOrderedFromSuppliers - $totalPaidToSuppliers;

        $openingBalances = OpeningBalance::whereBetween('date', [
            is_string($dateFrom) ? $dateFrom : $dateFrom->toDateString(),
            is_string($dateTo) ? $dateTo : $dateTo->toDateString(),
        ])->sum('amount');

        $grossProfit = $totalSales - $totalCostOfGoods;
        $netProfit = $openingBalances + $totalSales - $totalExpenses - $totalPaidToSuppliers - $unpaidSupplierBalances - $expiredItemsTotal - $disposedProductsTotal;
        $totalIncome = $openingBalances + $totalSales;
        $totalOutflow = $totalExpenses + $totalPaidToSuppliers + $unpaidSupplierBalances + $expiredItemsTotal + $disposedProductsTotal;
        $finalCashPosition = $totalIncome - $totalOutflow;

        return view('expenses.cashflow', compact(
            'dateFrom', 'dateTo', 'totalSales', 'totalCostOfGoods',
            'totalExpenses', 'grossProfit', 'netProfit',
            'totalCashPayments', 'totalMpesaPayments', 'totalCardPayments',
            'supplierPayments', 'openingBalances', 'totalIncome', 'totalOutflow', 'finalCashPosition', 'unpaidSupplierBalances', 'totalPaidToSuppliers',
            'expiredItemsTotal', 'disposedProductsTotal', 'totalValueLost'
        ));
    }

    public function cashflowExport(Request $request)
    {
        $dateFrom = $request->date_from ? Carbon::parse($request->date_from) : now()->startOfMonth();
        $dateTo = $request->date_to ? Carbon::parse($request->date_to)->endOfDay() : now()->endOfDay();

        $orders = Order::whereBetween('created_at', [$dateFrom, $dateTo])
            ->where('status', 'completed')
            ->get();

        $totalSales = $orders->sum('total');

        $totalCashPayments = 0;
        $totalMpesaPayments = 0;
        $totalCardPayments = 0;

        foreach ($orders as $order) {
            if ($order->payment_methods) {
                $methods = json_decode($order->payment_methods, true);
                if (is_array($methods)) {
                    foreach ($methods as $pm) {
                        if ($pm['method'] === 'cash') {
                            $totalCashPayments += $pm['amount'];
                        } elseif ($pm['method'] === 'mpesa') {
                            $totalMpesaPayments += $pm['amount'];
                        } elseif ($pm['method'] === 'card') {
                            $totalCardPayments += $pm['amount'];
                        }
                    }
                }
            } elseif ($order->payment_method === 'cash') {
                $totalCashPayments += $order->total;
            } elseif ($order->payment_method === 'mpesa') {
                $totalMpesaPayments += $order->total;
            } elseif ($order->payment_method === 'card') {
                $totalCardPayments += $order->total;
            }
        }

        $totalCostOfGoods = InventoryLog::whereBetween('created_at', [$dateFrom, $dateTo])
            ->where('type', 'stock_in')
            ->get()
            ->sum(function ($log) {
                return $log->quantity * $log->unit_cost;
            });

        $totalExpenses = Expense::whereBetween('expense_date', [$dateFrom, $dateTo])
            ->sum('amount');

        $expiredItemsTotal = Product::whereNotNull('expiry_date')
            ->whereDate('expiry_date', '>=', $dateFrom)
            ->whereDate('expiry_date', '<=', $dateTo)
            ->get()
            ->sum(function ($product) {
                return ($product->cost_price ?? 0) * $product->stock_quantity;
            });

        $disposedProductsTotal = DisposedProduct::whereBetween('created_at', [$dateFrom, $dateTo])
            ->sum('total_value');

        $totalValueLost = $expiredItemsTotal + $disposedProductsTotal;

        $supplierPayments = SupplierPayment::whereBetween('payment_date', [$dateFrom, $dateTo])->sum('amount');

        $totalOrderedFromSuppliers = InventoryLog::where('type', 'stock_in')
            ->whereNotNull('supplier_id')
            ->get()
            ->sum(function ($log) {
                return $log->quantity * $log->unit_cost;
            });

        $totalPaidToSuppliers = Supplier::sum('total_paid');
        $unpaidSupplierBalances = $totalOrderedFromSuppliers - $totalPaidToSuppliers;

        $openingBalances = OpeningBalance::whereBetween('date', [
            is_string($dateFrom) ? $dateFrom : $dateFrom->toDateString(),
            is_string($dateTo) ? $dateTo : $dateTo->toDateString(),
        ])->sum('amount');

        $grossProfit = $totalSales - $totalCostOfGoods;
        $netProfit = $openingBalances + $totalSales - $totalExpenses - $totalPaidToSuppliers - $unpaidSupplierBalances - $expiredItemsTotal - $disposedProductsTotal;
        $totalIncome = $openingBalances + $totalSales;
        $totalOutflow = $totalExpenses + $totalPaidToSuppliers + $unpaidSupplierBalances + $expiredItemsTotal + $disposedProductsTotal;
        $finalCashPosition = $totalIncome - $totalOutflow;

        $data = [
            ['Cash Flow Report'],
            ['Period:', $dateFrom->format('Y-m-d').' to '.$dateTo->format('Y-m-d')],
            [''],
            ['INCOME'],
            ['Opening Balance', number_format($openingBalances, 2)],
            ['Total Sales Revenue', number_format($totalSales, 2)],
            ['Total Income', number_format($totalIncome, 2)],
            ['Cash Payments', number_format($totalCashPayments, 2)],
            ['M-Pesa Payments', number_format($totalMpesaPayments, 2)],
            ['Card Payments', number_format($totalCardPayments, 2)],
            [''],
            ['EXPENSES'],
            ['Supplier Paid Totals', number_format($totalPaidToSuppliers, 2)],
            ['Unpaid Supplier Balances', number_format($unpaidSupplierBalances, 2)],
            ['Operating Expenses', number_format($totalExpenses, 2)],
            ['Expired Items Value', number_format($expiredItemsTotal, 2)],
            ['Disposed Products Value', number_format($disposedProductsTotal, 2)],
            ['Total Value Lost', number_format($totalValueLost, 2)],
            ['Total Outflow', number_format($totalOutflow, 2)],
            [''],
            ['FINAL CALCULATION'],
            ['Net Final Profit', number_format($netProfit, 2)],
            ['Final Cash Position', number_format($finalCashPosition, 2)],
        ];

        $filename = 'cashflow_'.date('Y-m-d').'.csv';

        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="'.$filename.'"');

        $output = fopen('php://output', 'w');
        foreach ($data as $row) {
            fputcsv($output, $row);
        }
        fclose($output);
        exit;
    }
}
