<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\DocumentHeader;
use App\Models\DocumentLine;
use App\Models\GeneralLedger;
use App\Models\Currency;
use App\Models\CompanySettings;
use App\Models\CashbookEntry;
use App\Models\AccountTypes;
use PDF;

class GlTransactionController extends Controller
{
    // Display initial form
    public function index()
    {
        $accounts = GeneralLedger::orderBy('code', 'asc')->get();
        $currencies = Currency::orderBy('code')->get();
        
        // Set default dates to current day
        $dateFrom = date('Y-m-d');
        $dateTo = date('Y-m-d');
        
        return view('reports.gl-transaction', compact('accounts', 'currencies', 'dateFrom', 'dateTo'));
    }

    // Generate GL transaction report
    public function generate(Request $request)
    {
        $request->validate([
            'gl_account_from' => 'required',
            'gl_account_to' => 'required',
            'date_from' => 'required|date',
            'date_to' => 'required|date|after_or_equal:date_from',
            'currency' => 'required',
        ]);

        $accountFrom = $request->gl_account_from;
        $accountTo = $request->gl_account_to;
        $dateFrom = $request->date_from;
        $dateTo = $request->date_to;
        $currencyCode = $request->currency;
        $company = CompanySettings::first();

        $accounts = GeneralLedger::orderBy('code', 'asc')->get();
        $currencies = Currency::orderBy('code')->get();

        // Get transaction data
        $transactionData = $this->getTransactionData($accountFrom, $accountTo, $currencyCode, $dateFrom, $dateTo);

        return view('reports.gl-transaction', compact(
            'transactionData',
            'accountFrom',
            'accountTo',
            'dateFrom',
            'dateTo',
            'currencyCode',
            'accounts',
            'currencies',
            'company'
        ));
    }

    // Download PDF
    public function downloadPdf(Request $request)
    {
        $request->validate([
            'gl_account_from' => 'required',
            'gl_account_to' => 'required',
            'date_from' => 'required|date',
            'date_to' => 'required|date|after_or_equal:date_from',
            'currency' => 'required',
        ]);

        $accountFrom = $request->gl_account_from;
        $accountTo = $request->gl_account_to;
        $dateFrom = $request->date_from;
        $dateTo = $request->date_to;
        $currencyCode = $request->currency;
        $currency = Currency::where('code', $currencyCode)->first();
        $company = CompanySettings::first();

        // Get account names for PDF title
        $fromAccount = GeneralLedger::find($accountFrom);
        $toAccount = GeneralLedger::find($accountTo);

        // Get transaction data
        $transactionData = $this->getTransactionData($accountFrom, $accountTo, $currencyCode, $dateFrom, $dateTo);

        $pdf = PDF::loadView('reports.gl-transaction-pdf', compact(
            'transactionData',
            'dateFrom',
            'dateTo',
            'currency',
            'company',
            'fromAccount',
            'toAccount'
        ));

        return $pdf->download('gl-transactions-' . $fromAccount->account_code . '-to-' . $toAccount->account_code . '.pdf');
    }

    // Retrieve transaction data
    private function getTransactionData($accountFrom, $accountTo, $currencyCode, $dateFrom, $dateTo)
    {
        $transactionData = [];
        $accountTypes = [];

        // Get all accounts in the range
        $accounts = GeneralLedger::whereBetween('id', [$accountFrom, $accountTo])
            ->with('accountType')
            ->orderBy('code')
            ->get();

        // Group accounts by type
        foreach ($accounts as $account) {
            $typeId = $account->account_type;
            if (!isset($accountTypes[$typeId])) {
                $accountType = AccountTypes::find($typeId);
                $accountTypes[$typeId] = [
                    'type' => $accountType,
                    'accounts' => [],
                    'total_opening' => 0,
                    'total_dr' => 0,
                    'total_cr' => 0,
                    'total_closing' => 0
                ];
            }

            // Calculate opening balance (transactions before dateFrom)
            $openingBalance = $this->calculateOpeningBalance($account->id, $currencyCode, $dateFrom);
            
            // Get transactions for this account
            $transactions = $this->getAccountTransactions($account->id, $currencyCode, $dateFrom, $dateTo, $openingBalance);
            
            $accountTypes[$typeId]['accounts'][$account->id] = [
                'account' => $account,
                'opening_balance' => $openingBalance,
                'transactions' => $transactions['transactions'],
                'total_dr' => $transactions['total_dr'],
                'total_cr' => $transactions['total_cr'],
                'closing_balance' => $transactions['closing_balance']
            ];

            // Update type totals
            $accountTypes[$typeId]['total_opening'] += $openingBalance;
            $accountTypes[$typeId]['total_dr'] += $transactions['total_dr'];
            $accountTypes[$typeId]['total_cr'] += $transactions['total_cr'];
            $accountTypes[$typeId]['total_closing'] += $transactions['closing_balance'];
        }

        return $accountTypes;
    }

    // Calculate opening balance for an account
    private function calculateOpeningBalance($accountId, $currencyCode, $dateFrom)
    {
        $balance = 0;

        // Get document transactions before dateFrom
        $documents = DocumentHeader::where('currency_code', $currencyCode)
            ->where('document_date', '<', $dateFrom)
            ->whereIn('type', ['invoice', 'credit_note', 'debit_note'])
            ->whereHas('lines', function($query) use ($accountId) {
                $query->where('module', 'GL')
                    ->where('account_id', $accountId);
            })
            ->get();

        foreach ($documents as $document) {
            if (in_array($document->type, ['invoice', 'debit_note'])) {
                $balance += $document->inclusive_total;
            } elseif ($document->type === 'credit_note') {
                $balance -= $document->inclusive_total;
            }
        }

        // Get cashbook entries before dateFrom
        $cashbookEntries = CashbookEntry::whereHas('currency', function($query) use ($currencyCode) {
                $query->where('code', $currencyCode);
            })
            ->where('date', '<', $dateFrom)
            ->where('module', 'GL')
            ->where('account_id', $accountId)
            ->get();

        foreach ($cashbookEntries as $entry) {
            if ($entry->tr_code === 'Receipt') {
                $balance += $entry->amount;
            } elseif ($entry->tr_code === 'Payment') {
                $balance -= $entry->amount;
            }
        }

        return $balance;
    }

    // Get transactions for a specific account
    private function getAccountTransactions($accountId, $currencyCode, $dateFrom, $dateTo, $openingBalance)
    {
        $transactions = [];
        $balance = $openingBalance;
        $totalDr = 0;
        $totalCr = 0;

        // Get document transactions
        $documents = DocumentHeader::where('currency_code', $currencyCode)
            ->whereBetween('document_date', [$dateFrom, $dateTo])
            ->whereIn('type', ['invoice', 'credit_note', 'debit_note'])
            ->whereHas('lines', function($query) use ($accountId) {
                $query->where('module', 'GL')
                    ->where('account_id', $accountId);
            })
            ->orderBy('document_date')
            ->get();

        foreach ($documents as $document) {
            $dr = 0;
            $cr = 0;
            
            if (in_array($document->type, ['invoice', 'debit_note'])) {
                $dr = $document->inclusive_total;
            } elseif ($document->type === 'credit_note') {
                $cr = $document->inclusive_total;
            }
            
            $balance += ($dr - $cr);
            $totalDr += $dr;
            $totalCr += $cr;

            $transactions[] = [
                'date'        => $document->document_date,
                'description' => ucfirst(str_replace('_', ' ', $document->type)) . ' - ' . $document->document_number,
                'reference'   => $document->document_number,
                'dr'          => $dr,
                'cr'          => $cr,
                'balance'     => $balance,
                'type'        => 'document'
            ];
        }

        // Get cashbook entries
        $cashbookEntries = CashbookEntry::whereHas('currency', function($query) use ($currencyCode) {
                $query->where('code', $currencyCode);
            })
            ->whereBetween('date', [$dateFrom, $dateTo])
            ->where('module', 'GL')
            ->where('account_id', $accountId)
            ->orderBy('date')
            ->get();

        foreach ($cashbookEntries as $entry) {
            $dr = 0;
            $cr = 0;
            
            if ($entry->tr_code === 'Receipt') {
                $dr = $entry->amount;
            } elseif ($entry->tr_code === 'Payment') {
                $cr = $entry->amount;
            }
            
            $balance += ($dr - $cr);
            $totalDr += $dr;
            $totalCr += $cr;

            $transactions[] = [
                'date'        => $entry->date,
                'description' => $entry->description,
                'reference'   => 'CB-' . $entry->id,
                'dr'          => $dr,
                'cr'          => $cr,
                'balance'     => $balance,
                'type'        => 'cashbook'
            ];
        }

        // Sort transactions by date
        usort($transactions, function($a, $b) {
            return strcmp($a['date'], $b['date']);
        });

        return [
            'transactions' => $transactions,
            'total_dr' => $totalDr,
            'total_cr' => $totalCr,
            'closing_balance' => $balance
        ];
    }
}