<?php

namespace App\Http\Controllers;

use App\Models\Voucher;
use App\Models\Account;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;

class VoucherController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Credit Voucher (Receipt - Money In)
    |--------------------------------------------------------------------------
    */
    
    public function creditIndex(Request $request): View
    {
        $query = Voucher::with(['entries.account', 'user'])
            ->where('type', 'CREDIT')
            ->latest('date');
        
        if ($request->filled('from_date')) {
            $query->whereDate('date', '>=', $request->from_date);
        }
        if ($request->filled('to_date')) {
            $query->whereDate('date', '<=', $request->to_date);
        }
        if ($request->filled('search')) {
            $query->where('voucher_no', 'like', "%{$request->search}%");
        }
        
        $vouchers = $query->paginate(20)->withQueryString();
        $totals = Voucher::where('type', 'CREDIT')->sum('amount');
        
        return view('vouchers.credit.index', compact('vouchers', 'totals'));
    }

    public function creditCreate(): View
    {
        $accounts = Account::where('is_active', true)->orderBy('name')->get();
        $cashBankAccounts = Account::whereIn('type', ['CASH', 'BANK'])->where('is_active', true)->get();
        $nextVoucherNo = Voucher::generateVoucherNo('CREDIT');
        
        return view('vouchers.credit.create', compact('accounts', 'cashBankAccounts', 'nextVoucherNo'));
    }

    public function creditStore(Request $request)
    {
        $request->validate([
            'date' => 'required|date',
            'account_id' => 'required|exists:accounts,id',
            'cash_bank_id' => 'required|exists:accounts,id',
            'amount' => 'required|numeric|min:0.01',
            'narration' => 'nullable|string|max:500',
        ]);

        DB::beginTransaction();
        try {
            $voucher = Voucher::create([
                'voucher_no' => Voucher::generateVoucherNo('CREDIT'),
                'type' => 'CREDIT',
                'date' => $request->date,
                'amount' => $request->amount,
                'narration' => $request->narration,
                'user_id' => Auth::id(),
            ]);
            
            // Debit Cash/Bank (increase cash)
            $voucher->entries()->create([
                'account_id' => $request->cash_bank_id,
                'debit' => $request->amount,
                'credit' => 0,
            ]);
            
            // Credit the selected account (decrease liability or income)
            $voucher->entries()->create([
                'account_id' => $request->account_id,
                'debit' => 0,
                'credit' => $request->amount,
            ]);
            
            // Post to ledger
            $voucher->postToLedger();
            
            DB::commit();
            
            return redirect()->route('vouchers.credit.index')
                ->with('success', "Credit Voucher {$voucher->voucher_no} created successfully.");
                
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withInput()->with('error', 'Error creating voucher: ' . $e->getMessage());
        }
    }

    public function creditShow(Voucher $voucher): View
    {
        $voucher->load(['entries.account', 'transactions.account', 'user']);
        return view('vouchers.credit.show', compact('voucher'));
    }

    public function creditDestroy(Voucher $voucher)
    {
        DB::beginTransaction();
        try {
            $voucher->reverseLedger();
            $voucher->entries()->delete();
            $voucher->delete();
            
            DB::commit();
            return redirect()->route('vouchers.credit.index')
                ->with('success', 'Credit voucher deleted successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->with('error', 'Error deleting voucher: ' . $e->getMessage());
        }
    }

    public function creditPrint(Voucher $voucher): View
    {
        $voucher->load(['entries.account', 'user']);
        return view('vouchers.credit.print', compact('voucher'));
    }

    /*
    |--------------------------------------------------------------------------
    | Debit Voucher (Payment - Money Out)
    |--------------------------------------------------------------------------
    */
    
    public function debitIndex(Request $request): View
    {
        $query = Voucher::with(['entries.account', 'user'])
            ->where('type', 'DEBIT')
            ->latest('date');
        
        if ($request->filled('from_date')) {
            $query->whereDate('date', '>=', $request->from_date);
        }
        if ($request->filled('to_date')) {
            $query->whereDate('date', '<=', $request->to_date);
        }
        if ($request->filled('search')) {
            $query->where('voucher_no', 'like', "%{$request->search}%");
        }
        
        $vouchers = $query->paginate(20)->withQueryString();
        $totals = Voucher::where('type', 'DEBIT')->sum('amount');
        
        return view('vouchers.debit.index', compact('vouchers', 'totals'));
    }

    public function debitCreate(): View
    {
        $accounts = Account::where('is_active', true)->orderBy('name')->get();
        $cashBankAccounts = Account::whereIn('type', ['CASH', 'BANK'])->where('is_active', true)->get();
        $nextVoucherNo = Voucher::generateVoucherNo('DEBIT');
        
        return view('vouchers.debit.create', compact('accounts', 'cashBankAccounts', 'nextVoucherNo'));
    }

    public function debitStore(Request $request)
    {
        $request->validate([
            'date' => 'required|date',
            'account_id' => 'required|exists:accounts,id',
            'cash_bank_id' => 'required|exists:accounts,id',
            'amount' => 'required|numeric|min:0.01',
            'narration' => 'nullable|string|max:500',
        ]);

        DB::beginTransaction();
        try {
            $voucher = Voucher::create([
                'voucher_no' => Voucher::generateVoucherNo('DEBIT'),
                'type' => 'DEBIT',
                'date' => $request->date,
                'amount' => $request->amount,
                'narration' => $request->narration,
                'user_id' => Auth::id(),
            ]);
            
            // Debit the selected account (increase expense or asset)
            $voucher->entries()->create([
                'account_id' => $request->account_id,
                'debit' => $request->amount,
                'credit' => 0,
            ]);
            
            // Credit Cash/Bank (decrease cash)
            $voucher->entries()->create([
                'account_id' => $request->cash_bank_id,
                'debit' => 0,
                'credit' => $request->amount,
            ]);
            
            // Post to ledger
            $voucher->postToLedger();
            
            DB::commit();
            
            return redirect()->route('vouchers.debit.index')
                ->with('success', "Debit Voucher {$voucher->voucher_no} created successfully.");
                
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withInput()->with('error', 'Error creating voucher: ' . $e->getMessage());
        }
    }

    public function debitShow(Voucher $voucher): View
    {
        $voucher->load(['entries.account', 'transactions.account', 'user']);
        return view('vouchers.debit.show', compact('voucher'));
    }

    public function debitDestroy(Voucher $voucher)
    {
        DB::beginTransaction();
        try {
            $voucher->reverseLedger();
            $voucher->entries()->delete();
            $voucher->delete();
            
            DB::commit();
            return redirect()->route('vouchers.debit.index')
                ->with('success', 'Debit voucher deleted successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->with('error', 'Error deleting voucher: ' . $e->getMessage());
        }
    }

    public function debitPrint(Voucher $voucher): View
    {
        $voucher->load(['entries.account', 'user']);
        return view('vouchers.debit.print', compact('voucher'));
    }

    /*
    |--------------------------------------------------------------------------
    | Journal Voucher (Double-Entry)
    |--------------------------------------------------------------------------
    */
    
    public function journalIndex(Request $request): View
    {
        $query = Voucher::with(['entries.account', 'user'])
            ->where('type', 'JOURNAL')
            ->latest('date');
        
        if ($request->filled('from_date')) {
            $query->whereDate('date', '>=', $request->from_date);
        }
        if ($request->filled('to_date')) {
            $query->whereDate('date', '<=', $request->to_date);
        }
        if ($request->filled('search')) {
            $query->where('voucher_no', 'like', "%{$request->search}%");
        }
        
        $vouchers = $query->paginate(20)->withQueryString();
        
        return view('vouchers.journal.index', compact('vouchers'));
    }

    public function journalCreate(): View
    {
        $accounts = Account::where('is_active', true)->orderBy('name')->get();
        $nextVoucherNo = Voucher::generateVoucherNo('JOURNAL');
        
        return view('vouchers.journal.create', compact('accounts', 'nextVoucherNo'));
    }

    public function journalStore(Request $request)
    {
        $request->validate([
            'date' => 'required|date',
            'entries' => 'required|array|min:2',
            'entries.*.account_id' => 'required|exists:accounts,id',
        ]);

        // Validate debit = credit
        $totalDebit = 0;
        $totalCredit = 0;
        foreach ($request->entries as $entry) {
            $totalDebit += floatval($entry['debit'] ?? 0);
            $totalCredit += floatval($entry['credit'] ?? 0);
        }
        
        if (round($totalDebit, 2) != round($totalCredit, 2)) {
            return back()->withInput()->with('error', 'Total Debit must equal Total Credit.');
        }
        
        if ($totalDebit == 0) {
            return back()->withInput()->with('error', 'Voucher amount cannot be zero.');
        }

        DB::beginTransaction();
        try {
            $voucher = Voucher::create([
                'voucher_no' => Voucher::generateVoucherNo('JOURNAL'),
                'type' => 'JOURNAL',
                'date' => $request->date,
                'amount' => $totalDebit,
                'narration' => $request->narration,
                'user_id' => Auth::id(),
            ]);
            
            // Create entries
            foreach ($request->entries as $entry) {
                if (!empty($entry['account_id']) && (($entry['debit'] ?? 0) > 0 || ($entry['credit'] ?? 0) > 0)) {
                    $voucher->entries()->create([
                        'account_id' => $entry['account_id'],
                        'debit' => $entry['debit'] ?? 0,
                        'credit' => $entry['credit'] ?? 0,
                    ]);
                }
            }
            
            // Post to ledger
            $voucher->postToLedger();
            
            DB::commit();
            
            return redirect()->route('vouchers.journal.index')
                ->with('success', "Journal Voucher {$voucher->voucher_no} created successfully.");
                
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withInput()->with('error', 'Error creating voucher: ' . $e->getMessage());
        }
    }

    public function journalShow(Voucher $voucher): View
    {
        $voucher->load(['entries.account', 'transactions.account', 'user']);
        return view('vouchers.journal.show', compact('voucher'));
    }

    public function journalDestroy(Voucher $voucher)
    {
        DB::beginTransaction();
        try {
            $voucher->reverseLedger();
            $voucher->entries()->delete();
            $voucher->delete();
            
            DB::commit();
            return redirect()->route('vouchers.journal.index')
                ->with('success', 'Journal voucher deleted successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->with('error', 'Error deleting voucher: ' . $e->getMessage());
        }
    }

    public function journalPrint(Voucher $voucher): View
    {
        $voucher->load(['entries.account', 'user']);
        return view('vouchers.journal.print', compact('voucher'));
    }
}
