<?php

namespace App\Http\Controllers;

use App\Models\Expense;
use App\Models\ExpenseCategory;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Barryvdh\DomPDF\Facade\Pdf;

class ExpenseController extends Controller
{
    public function index(Request $request)
    {
        $expenses = Expense::with('category')
            ->when($request->type, fn($q, $t) => $q->where('type', $t))
            ->when($request->category_id, fn($q, $c) => $q->where('category_id', $c))
            ->when($request->date_from, fn($q, $d) => $q->where('date', '>=', $d))
            ->when($request->date_to, fn($q, $d) => $q->where('date', '<=', $d))
            ->latest('date')
            ->paginate(20)
            ->withQueryString();

        $categories = ExpenseCategory::orderBy('name')->get();

        $totalIn = Expense::cashIn()
            ->when($request->date_from, fn($q, $d) => $q->where('date', '>=', $d))
            ->when($request->date_to, fn($q, $d) => $q->where('date', '<=', $d))
            ->sum('amount');

        $totalOut = Expense::cashOut()
            ->when($request->date_from, fn($q, $d) => $q->where('date', '>=', $d))
            ->when($request->date_to, fn($q, $d) => $q->where('date', '<=', $d))
            ->sum('amount');

        return Inertia::render('Expenses/Index', [
            'expenses' => $expenses,
            'categories' => $categories,
            'totalIn' => (float) $totalIn,
            'totalOut' => (float) $totalOut,
            'balance' => (float) ($totalIn - $totalOut),
            'filters' => $request->only('type', 'category_id', 'date_from', 'date_to'),
        ]);
    }

    public function create()
    {
        $categories = ExpenseCategory::orderBy('name')->get();

        return Inertia::render('Expenses/Create', [
            'categories' => $categories,
        ]);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'type' => 'required|in:cash_in,cash_out',
            'category_id' => 'required|exists:expense_categories,id',
            'amount' => 'required|numeric|min:0.01',
            'description' => 'required|string',
            'date' => 'required|date',
            'reference_no' => 'nullable|string|max:100',
            'proof_file' => 'nullable|file|max:5120',
        ]);

        if ($request->hasFile('proof_file')) {
            $validated['proof_file'] = $request->file('proof_file')->store('expense-proofs', 'public');
        }

        Expense::create($validated);

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

    public function edit(Expense $expense)
    {
        $categories = ExpenseCategory::orderBy('name')->get();

        return Inertia::render('Expenses/Edit', [
            'expense' => $expense,
            'categories' => $categories,
        ]);
    }

    public function update(Request $request, Expense $expense)
    {
        $validated = $request->validate([
            'type' => 'required|in:cash_in,cash_out',
            'category_id' => 'required|exists:expense_categories,id',
            'amount' => 'required|numeric|min:0.01',
            'description' => 'required|string',
            'date' => 'required|date',
            'reference_no' => 'nullable|string|max:100',
            'proof_file' => 'nullable|file|max:5120',
        ]);

        if ($request->hasFile('proof_file')) {
            $validated['proof_file'] = $request->file('proof_file')->store('expense-proofs', 'public');
        }

        $expense->update($validated);

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

    public function destroy(Expense $expense)
    {
        $expense->delete();
        return redirect()->route('expenses.index')->with('success', 'Expense deleted.');
    }

    public function report(Request $request)
    {
        $period = $request->get('period', 'daily');
        $date = $request->get('date', now()->format('Y-m-d'));

        if ($period === 'daily') {
            $expenses = Expense::with('category')
                ->where('date', $date)
                ->orderBy('created_at')
                ->get();
            $totalIn = $expenses->where('type', 'cash_in')->sum('amount');
            $totalOut = $expenses->where('type', 'cash_out')->sum('amount');
        } elseif ($period === 'weekly') {
            $startOfWeek = Carbon::parse($date)->startOfWeek();
            $endOfWeek = Carbon::parse($date)->endOfWeek();
            $expenses = Expense::with('category')
                ->whereBetween('date', [$startOfWeek, $endOfWeek])
                ->orderBy('date')
                ->orderBy('created_at')
                ->get();
            $totalIn = $expenses->where('type', 'cash_in')->sum('amount');
            $totalOut = $expenses->where('type', 'cash_out')->sum('amount');
        } else {
            // monthly
            $startOfMonth = Carbon::parse($date)->startOfMonth();
            $endOfMonth = Carbon::parse($date)->endOfMonth();
            $expenses = Expense::with('category')
                ->whereBetween('date', [$startOfMonth, $endOfMonth])
                ->orderBy('date')
                ->orderBy('created_at')
                ->get();
            $totalIn = $expenses->where('type', 'cash_in')->sum('amount');
            $totalOut = $expenses->where('type', 'cash_out')->sum('amount');
        }

        return Inertia::render('Expenses/Report', [
            'expenses' => $expenses,
            'totalIn' => (float) $totalIn,
            'totalOut' => (float) $totalOut,
            'balance' => (float) ($totalIn - $totalOut),
            'period' => $period,
            'date' => $date,
        ]);
    }

    public function downloadPdf(Request $request)
    {
        $period = $request->get('period', 'daily');
        $date = $request->get('date', now()->format('Y-m-d'));

        if ($period === 'daily') {
            $expenses = Expense::with('category')
                ->where('date', $date)
                ->orderBy('created_at')
                ->get();
            $totalIn = $expenses->where('type', 'cash_in')->sum('amount');
            $totalOut = $expenses->where('type', 'cash_out')->sum('amount');
        } elseif ($period === 'weekly') {
            $startOfWeek = Carbon::parse($date)->startOfWeek();
            $endOfWeek = Carbon::parse($date)->endOfWeek();
            $expenses = Expense::with('category')
                ->whereBetween('date', [$startOfWeek, $endOfWeek])
                ->orderBy('date')
                ->orderBy('created_at')
                ->get();
            $totalIn = $expenses->where('type', 'cash_in')->sum('amount');
            $totalOut = $expenses->where('type', 'cash_out')->sum('amount');
        } else {
            // monthly
            $startOfMonth = Carbon::parse($date)->startOfMonth();
            $endOfMonth = Carbon::parse($date)->endOfMonth();
            $expenses = Expense::with('category')
                ->whereBetween('date', [$startOfMonth, $endOfMonth])
                ->orderBy('date')
                ->orderBy('created_at')
                ->get();
            $totalIn = $expenses->where('type', 'cash_in')->sum('amount');
            $totalOut = $expenses->where('type', 'cash_out')->sum('amount');
        }

        $balance = $totalIn - $totalOut;

        $pdf = Pdf::loadView('expenses.report-pdf', compact('expenses', 'totalIn', 'totalOut', 'balance', 'period', 'date'))
            ->setPaper('a4', 'portrait');

        $filename = 'cash-book-report-' . $period . '-' . $date . '.pdf';
        
        return $pdf->download($filename);
    }
}

