<?php

namespace App\Http\Controllers;

use App\Models\Account;
use App\Models\Organization;
use App\Models\Transaction;
use App\Models\TransactionCategory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class TransactionController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:transactions.view')->only(['index', 'show']);
        $this->middleware('permission:transactions.create')->only(['create', 'store']);
        $this->middleware('permission:transactions.edit')->only(['edit', 'update']);
        $this->middleware('permission:transactions.delete')->only(['destroy']);
        $this->middleware('permission:transactions.approve')->only(['approve', 'reject']);
    }

    protected function getOrganizationScope()
    {
        $user = Auth::user();
        if ($user->hasRole('Super Admin')) {
            return null;
        }
        $orgIds = collect([$user->organization_id]);
        $this->getChildOrganizations($user->organization_id, $orgIds);
        return $orgIds->toArray();
    }

    protected function getChildOrganizations($parentId, &$orgIds)
    {
        $children = Organization::where('parent_id', $parentId)->pluck('id');
        foreach ($children as $childId) {
            $orgIds->push($childId);
            $this->getChildOrganizations($childId, $orgIds);
        }
    }

    public function index(Request $request)
    {
        $query = Transaction::with(['organization', 'account', 'category', 'recorder']);
        $scope = $this->getOrganizationScope();
        if ($scope !== null) {
            $query->whereIn('organization_id', $scope);
        }

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

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

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

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

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

        $transactions = $query->orderByDesc('date')->orderByDesc('id')->paginate(20)->withQueryString();

        // Get accounts for filter
        $accounts = Account::query();
        if ($scope !== null) {
            $accounts->whereIn('organization_id', $scope);
        }
        $accounts = $accounts->orderBy('name')->get();

        return view('finance.transactions.index', compact('transactions', 'accounts'));
    }

    public function create()
    {
        $scope = $this->getOrganizationScope();

        $accounts = Account::query();
        if ($scope !== null) {
            $accounts->whereIn('organization_id', $scope);
        }
        $accounts = $accounts->orderBy('name')->get();

        $categories = TransactionCategory::whereNull('organization_id')
            ->orWhereIn('organization_id', $scope ?? [])
            ->orderBy('name')
            ->get();

        return view('finance.transactions.create', compact('accounts', 'categories'));
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'account_id' => 'required|exists:accounts,id',
            'category_id' => 'required|exists:transaction_categories,id',
            'amount' => 'required|numeric|min:0.01',
            'type' => 'required|in:Credit,Debit',
            'reference' => 'nullable|string|max:100',
            'description' => 'nullable|string|max:500',
            'date' => 'required|date',
        ]);

        $account = Account::findOrFail($validated['account_id']);
        $scope = $this->getOrganizationScope();
        if ($scope !== null && !in_array($account->organization_id, $scope)) {
            abort(403);
        }

        $validated['organization_id'] = $account->organization_id;
        $validated['recorded_by'] = Auth::id();
        
        // Debit transactions require approval (start as Pending)
        // Credit transactions are auto-approved
        if ($validated['type'] === 'Debit') {
            $validated['status'] = 'Pending';
            Transaction::create($validated);
            return redirect()->route('transactions.index')->with('success', 'Expense recorded. Awaiting approval.');
        } else {
            $validated['status'] = 'Approved';
            Transaction::create($validated);
            return redirect()->route('transactions.index')->with('success', 'Income recorded and balance updated.');
        }
    }

    public function show(Transaction $transaction)
    {
        $scope = $this->getOrganizationScope();
        if ($scope !== null && !in_array($transaction->organization_id, $scope)) {
            abort(403);
        }

        $transaction->load(['organization', 'account', 'category', 'recorder']);

        return view('finance.transactions.show', compact('transaction'));
    }

    public function destroy(Transaction $transaction)
    {
        $scope = $this->getOrganizationScope();
        if ($scope !== null && !in_array($transaction->organization_id, $scope)) {
            abort(403);
        }

        $transaction->delete();

        return redirect()->route('transactions.index')->with('success', 'Transaction deleted and balance reversed.');
    }

    public function export(Request $request)
    {
        $query = Transaction::with(['account', 'category']);
        $scope = $this->getOrganizationScope();
        if ($scope !== null) {
            $query->whereIn('organization_id', $scope);
        }

        if ($request->filled('type')) {
            $query->where('type', $request->type);
        }
        if ($request->filled('date_from')) {
            $query->whereDate('date', '>=', $request->date_from);
        }
        if ($request->filled('date_to')) {
            $query->whereDate('date', '<=', $request->date_to);
        }

        $transactions = $query->orderByDesc('date')->get();

        $filename = 'transactions_' . date('Y-m-d') . '.csv';
        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => "attachment; filename=\"{$filename}\"",
        ];

        $callback = function() use ($transactions) {
            $file = fopen('php://output', 'w');
            fputcsv($file, ['Date', 'Type', 'Account', 'Category', 'Amount', 'Reference', 'Description']);
            foreach ($transactions as $t) {
                fputcsv($file, [
                    $t->date->format('Y-m-d'),
                    $t->type,
                    $t->account?->name,
                    $t->category?->name,
                    $t->amount,
                    $t->reference,
                    $t->description,
                ]);
            }
            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    /**
     * Approve a pending transaction.
     */
    public function approve(Transaction $transaction)
    {
        $scope = $this->getOrganizationScope();
        if ($scope !== null && !in_array($transaction->organization_id, $scope)) {
            abort(403);
        }

        $user = Auth::user();

        // Validate approval
        if ($transaction->status !== 'Pending') {
            return back()->with('error', 'Only pending transactions can be approved.');
        }

        if ($transaction->recorded_by === $user->id) {
            return back()->with('error', 'You cannot approve your own transaction.');
        }

        if (!$user->can('finance.approve')) {
            return back()->with('error', 'You do not have permission to approve transactions.');
        }

        $transaction->approve($user);

        return back()->with('success', 'Transaction approved. Balance updated.');
    }

    /**
     * Reject a pending transaction.
     */
    public function reject(Request $request, Transaction $transaction)
    {
        $scope = $this->getOrganizationScope();
        if ($scope !== null && !in_array($transaction->organization_id, $scope)) {
            abort(403);
        }

        $request->validate([
            'rejection_reason' => 'required|string|max:500',
        ]);

        if ($transaction->status !== 'Pending') {
            return back()->with('error', 'Only pending transactions can be rejected.');
        }

        $transaction->reject(Auth::user(), $request->rejection_reason);

        return back()->with('success', 'Transaction rejected.');
    }

    /**
     * List pending transactions for approval.
     */
    public function pending(Request $request)
    {
        $query = Transaction::with(['organization', 'account', 'category', 'recorder'])
            ->where('status', 'Pending');
        
        $scope = $this->getOrganizationScope();
        if ($scope !== null) {
            $query->whereIn('organization_id', $scope);
        }

        $transactions = $query->orderByDesc('date')->paginate(20);

        $accounts = Account::query();
        if ($scope !== null) {
            $accounts->whereIn('organization_id', $scope);
        }
        $accounts = $accounts->orderBy('name')->get();

        return view('finance.transactions.pending', compact('transactions', 'accounts'));
    }
}

