<?php

namespace App\Http\Controllers\Admin;

use App\Core\Repositories\ExpenseRepository;
use App\Http\Controllers\Controller;
use App\Models\BankAccount;
use App\Models\ChartOfAccount;
use App\Models\Customer;
use App\Models\Expense;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;

class ExpenseController extends Controller
{
    public function __construct(
        private ExpenseRepository $expenseRepository
    ) {}

    public function index(Request $request): View
    {
        $perPage = $request->get('per_page', 15);
        $search = $request->get('search');

        $filters = [];
        if ($request->has('status')) {
            $filters['status'] = $request->get('status');
        }
        if ($request->has('date_from')) {
            $filters['date_from'] = $request->get('date_from');
        }
        if ($request->has('date_to')) {
            $filters['date_to'] = $request->get('date_to');
        }

        $query = \App\Models\Expense::with(['account', 'vendor', 'creator']);

        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('expense_number', 'like', "%{$search}%")
                    ->orWhere('category', 'like', "%{$search}%")
                    ->orWhere('description', 'like', "%{$search}%");
            });
        }

        foreach ($filters as $key => $value) {
            if ($value) {
                switch ($key) {
                    case 'status':
                        $query->where('status', $value);
                        break;
                    case 'date_from':
                        $query->where('expense_date', '>=', $value);
                        break;
                    case 'date_to':
                        $query->where('expense_date', '<=', $value);
                        break;
                }
            }
        }

        $expenses = $query->orderBy('expense_date', 'desc')
            ->orderBy('created_at', 'desc')
            ->paginate($perPage)
            ->withQueryString();

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

    public function create(): View
    {
        // Get expense accounts (type = 'expense')
        $accounts = ChartOfAccount::where('type', 'expense')
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        // Get vendors (customers that can be used as vendors)
        $vendors = Customer::where('is_active', true)
            ->orderBy('name')
            ->get();

        // Common expense categories
        $categories = [
            'Office Supplies',
            'Travel',
            'Utilities',
            'Marketing',
            'Rent',
            'Insurance',
            'Professional Services',
            'Equipment',
            'Software',
            'Other',
        ];

        $bankAccounts = BankAccount::where('is_active', true)
            ->orderBy('is_default', 'desc')
            ->orderBy('account_name')
            ->get();

        return view('admin.expenses.create', compact('accounts', 'vendors', 'categories', 'bankAccounts'));
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'category' => 'required|string|max:255',
            'amount' => 'required|numeric|min:0.01',
            'date' => 'required|date',
            'payment_method' => 'required|string|in:cash,bank_transfer,credit_card,check',
            'description' => 'nullable|string',
            'account_id' => 'required|exists:chart_of_accounts,id',
            'vendor_id' => 'nullable|exists:customers,id',
            'bank_account_id' => 'nullable|exists:bank_accounts,id',
            'receipt' => 'nullable|file|mimes:jpg,jpeg,png,pdf|max:5120', // 5MB max
        ]);

        // Generate expense number
        $expenseNumber = $this->expenseRepository->generateExpenseNumber();

        // Handle receipt upload
        $receiptPath = null;
        if ($request->hasFile('receipt')) {
            $receiptPath = $request->file('receipt')->store('expenses/receipts', 'public');
        }

        // Calculate total (amount + tax, for now tax is 0)
        $taxAmount = 0;
        $total = $validated['amount'] + $taxAmount;

        // Create expense
        $expenseData = [
            'expense_number' => $expenseNumber,
            'expense_date' => $validated['date'],
            'account_id' => $validated['account_id'],
            'vendor_id' => $validated['vendor_id'] ?? null,
            'category' => $validated['category'],
            'payment_method' => $validated['payment_method'],
            'amount' => $validated['amount'],
            'tax_amount' => $taxAmount,
            'total' => $total,
            'currency' => \App\Models\Currency::getDefaultCode(),
            'description' => $validated['description'] ?? null,
            'receipt_path' => $receiptPath,
            'bank_account_id' => $validated['bank_account_id'] ?? null,
            'status' => 'draft',
            'created_by' => auth()->id(),
        ];

        $expense = $this->expenseRepository->create($expenseData);

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

    public function show($id): View
    {
        $expense = \App\Models\Expense::with(['account', 'vendor', 'creator'])->findOrFail($id);

        return view('admin.expenses.show', compact('expense'));
    }

    public function edit($id): View
    {
        $expense = \App\Models\Expense::with(['account', 'vendor', 'creator'])->findOrFail($id);

        // Get expense accounts
        $accounts = ChartOfAccount::where('type', 'expense')
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        // Get vendors
        $vendors = Customer::where('is_active', true)
            ->orderBy('name')
            ->get();

        // Common expense categories
        $categories = [
            'Office Supplies',
            'Travel',
            'Utilities',
            'Marketing',
            'Rent',
            'Insurance',
            'Professional Services',
            'Equipment',
            'Software',
            'Other',
        ];

        $bankAccounts = BankAccount::where('is_active', true)
            ->orderBy('is_default', 'desc')
            ->orderBy('account_name')
            ->get();

        return view('admin.expenses.edit', compact('expense', 'accounts', 'vendors', 'categories', 'bankAccounts'));
    }

    public function update(Request $request, $id): RedirectResponse
    {
        $expense = $this->expenseRepository->getById($id);

        if (! $expense) {
            abort(404, 'Expense not found');
        }

        $validated = $request->validate([
            'category' => 'required|string|max:255',
            'amount' => 'required|numeric|min:0.01',
            'date' => 'required|date',
            'payment_method' => 'required|string|in:cash,bank_transfer,credit_card,check',
            'description' => 'nullable|string',
            'account_id' => 'required|exists:chart_of_accounts,id',
            'vendor_id' => 'nullable|exists:customers,id',
            'bank_account_id' => 'nullable|exists:bank_accounts,id',
            'receipt' => 'nullable|file|mimes:jpg,jpeg,png,pdf|max:5120',
            'status' => 'required|string|in:draft,approved,paid,rejected',
        ]);

        // Prepare update data
        $status = $validated['status'];
        $updateData = [
            'expense_date' => $validated['date'],
            'account_id' => $validated['account_id'],
            'vendor_id' => $validated['vendor_id'] ?? null,
            'category' => $validated['category'],
            'payment_method' => $validated['payment_method'],
            'amount' => $validated['amount'],
            'description' => $validated['description'] ?? null,
            'status' => $status,
            'bank_account_id' => $validated['bank_account_id'] ?? null,
        ];

        if ($status === 'approved') {
            $updateData['approved_by'] = auth()->id();
            $updateData['approved_at'] = now();
        } elseif (in_array($status, ['draft', 'rejected'], true)) {
            $updateData['approved_by'] = null;
            $updateData['approved_at'] = null;
        }

        // Handle receipt upload
        if ($request->hasFile('receipt')) {
            // Delete old receipt if exists
            if ($expense->receipt_path) {
                Storage::disk('public')->delete($expense->receipt_path);
            }
            $updateData['receipt_path'] = $request->file('receipt')->store('expenses/receipts', 'public');
        }

        // Calculate total
        $taxAmount = $expense->tax_amount ?? 0;
        $updateData['total'] = $validated['amount'] + $taxAmount;

        // Update expense
        $this->expenseRepository->update($expense, $updateData);

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

    /**
     * Update expense workflow status (draft, approved, paid, rejected).
     */
    public function updateStatus(Request $request, Expense $expense): RedirectResponse
    {
        $validated = $request->validate([
            'status' => 'required|string|in:draft,approved,paid,rejected',
        ]);

        $status = $validated['status'];
        $data = ['status' => $status];

        if ($status === 'approved') {
            $data['approved_by'] = auth()->id();
            $data['approved_at'] = now();
        } elseif (in_array($status, ['draft', 'rejected'], true)) {
            $data['approved_by'] = null;
            $data['approved_at'] = null;
        }

        $this->expenseRepository->update($expense, $data);

        return redirect()
            ->back()
            ->with('success', 'Expense status updated.');
    }

    public function destroy($id): RedirectResponse
    {
        $expense = $this->expenseRepository->getById($id);

        if (! $expense) {
            abort(404, 'Expense not found');
        }

        // Delete receipt if exists
        if ($expense->receipt_path) {
            Storage::disk('public')->delete($expense->receipt_path);
        }

        $this->expenseRepository->delete($expense);

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