<?php

namespace App\Http\Livewire;

use App\Models\Transaction;
use App\Traits\AccountInfoTrait;
use Barryvdh\DomPDF\Facade\Pdf;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Livewire\Component;

class SingleReport extends Component
{
    use AccountInfoTrait;

    public $reportData;
    public $fromAccountId;
    public $fromDate;
    public $toDate;
    public $isOrganization = false;
    public $decimalFormat = false;

    protected $listeners = [
        'fromAccountId',
        'periodSelected' => 'periodSelectedDispatched',
        'periodCleared' => 'periodClearedDispatched',
        'export-pdf-with-charts' => 'handleExportPdfWithCharts',
    ];

    public function mount($reportData = null)
    {
        $profile = getActiveProfile();

        if (!$profile) {
            abort(403, 'No active profile');
        }

        // CRITICAL SECURITY: Validate user has ownership/access to this profile
        // This prevents unauthorized access to financial report data via session manipulation
        \App\Helpers\ProfileAuthorizationHelper::authorize($profile);

        $this->reportData = $reportData;
        $this->isOrganization = $profile instanceof \App\Models\Organization;

        // Default to previous year on load (matches SelectPeriod default)
        $this->fromDate = Carbon::now()->subYear()->startOfYear()->format('Y-m-d');
        $this->toDate = Carbon::now()->subYear()->endOfYear()->format('Y-m-d');
    }

    public function updatedDecimalFormat()
    {
        // Trigger a re-render with updated format — no additional action needed,
        // render() picks up $decimalFormat automatically.
    }

    public function formatAmount($minutes)
    {
        if ($this->decimalFormat) {
            $isNegative = $minutes < 0;
            $decimal = number_format(abs($minutes) / 60, 2, ',', '.');
            return ($isNegative ? '-' : '') . $decimal . ' ' . __('h.');
        }

        return tbFormat($minutes);
    }

    public function fromAccountId($selectedAccount)
    {
        $this->fromAccountId = $selectedAccount['id'];
    }

    public function periodSelectedDispatched($periodData)
    {
        $fromDate = $periodData['fromDate'];
        $toDate = $periodData['toDate'];

        // Validate date range - ensure fromDate is not after toDate
        if ($fromDate && $toDate && Carbon::parse($fromDate)->gt(Carbon::parse($toDate))) {
            // Invalid date range - swap the dates or use a default range
            Log::warning('Invalid date range detected', [
                'fromDate' => $fromDate,
                'toDate' => $toDate,
                'action' => 'swapping_dates'
            ]);

            // Swap the dates to fix the invalid range
            $this->fromDate = $toDate;
            $this->toDate = $fromDate;

            // Dispatch a warning to the frontend
            $this->dispatch('show-notification', [
                'type' => 'warning',
                'message' => __('Date range was invalid (start date after end date). Dates have been corrected.')
            ]);
        } else {
            $this->fromDate = $fromDate;
            $this->toDate = $toDate;
        }

        // Generate and dispatch the title
        $this->generateAndDispatchTitle($periodData['period'] ?? 'custom');

    }

    /**
     * Handle when period is cleared/deselected
     */
    public function periodClearedDispatched()
    {
        $this->fromDate = null;
        $this->toDate = null;

        // Clear the title when period is cleared
        $this->dispatch('tableTitle', ['header' => '', 'sub' => '']);

    }

    /**
     * Generate period-aware title and dispatch to table-title component
     */
    private function generateAndDispatchTitle($periodType)
    {
        if (!$this->fromDate || !$this->toDate) {
            // Clear title when no period is selected
            $this->dispatch('tableTitle', ['header' => '', 'sub' => '']);
            return;
        }

        // Check if there's actual data to show
        $accountsData = $this->getAccountsWithPeriodBalances();
        if (!$accountsData || $accountsData->count() === 0) {
            // Clear title when no data is available
            $this->dispatch('tableTitle', ['header' => '', 'sub' => '']);
            return;
        }

        $fromDate = Carbon::parse($this->fromDate);
        $toDate = Carbon::parse($this->toDate);

        // Generate main title based on period type
        $mainTitle = $this->generatePeriodTitle($periodType, $fromDate, $toDate);

        // Generate date range subtitle
        $dateRange = $fromDate->format('d-m-Y') . ' - ' . $toDate->format('d-m-Y');

        $title = [
            'header' => $mainTitle,
            'sub' => $dateRange
        ];

        $this->dispatch('tableTitle', $title);
    }

    /**
     * Generate appropriate title based on period type and dates
     */
    private function generatePeriodTitle($periodType, $fromDate, $toDate)
    {
        switch ($periodType) {
            case 'previous_year':
                return __('Financial Overview') . ' ' . $fromDate->year;

            case 'previous_quarter':
                $quarter = $this->getQuarterName($fromDate);
                return __('Financial Overview') . ' ' . $quarter . ' ' . $fromDate->year;

            case 'previous_month':
                return __('Financial Overview') . ' ' . $fromDate->format('F Y');

            case 'custom':
            default:
                // For custom periods, just show "Financial Overview" without date details
                return __('Financial Overview');
        }
    }

    /**
     * Get quarter name from date
     */
    private function getQuarterName($date)
    {
        $quarter = $date->quarter;

        switch ($quarter) {
            case 1:
                return __('1st Quarter');
            case 2:
                return __('2nd Quarter');
            case 3:
                return __('3rd Quarter');
            case 4:
                return __('4th Quarter');
            default:
                return __('Quarter') . ' ' . $quarter;
        }
    }

    /**
     * Calculate balance for an account BEFORE any transactions on the start date
     * This gives the balance at the end of the previous day (start of the period)
     */
    private function calculateStartBalance($accountId, $date)
    {
        if (!$date) {
            return 0;
        }

        $query = Transaction::where(function($q) use ($accountId) {
                $q->where('from_account_id', $accountId)
                  ->orWhere('to_account_id', $accountId);
            })
            ->whereDate('created_at', '<', $date);


        $balance = $query->selectRaw('SUM(CASE WHEN to_account_id = ? THEN amount ELSE -amount END) as balance', [$accountId])
            ->value('balance');


        return $balance ?? 0;
    }

    /**
     * Calculate balance for an account AFTER all transactions on the end date
     * This gives the balance at the end of the target day
     */
    private function calculateEndBalance($accountId, $date)
    {
        if (!$date) {
            return 0;
        }

        $query = Transaction::where(function($q) use ($accountId) {
                $q->where('from_account_id', $accountId)
                  ->orWhere('to_account_id', $accountId);
            })
            ->whereDate('created_at', '<=', $date);


        $balance = $query->selectRaw('SUM(CASE WHEN to_account_id = ? THEN amount ELSE -amount END) as balance', [$accountId])
            ->value('balance');


        return $balance ?? 0;
    }

    /**
     * Get all accounts for active profile with period balances
     */
    public function getAccountsWithPeriodBalances()
    {
        $activeProfile = getActiveProfile();
        if (!$activeProfile || !method_exists($activeProfile, 'accounts')) {
            return collect();
        }

        // Validate date range before processing
        if ($this->fromDate && $this->toDate && Carbon::parse($this->fromDate)->gt(Carbon::parse($this->toDate))) {
            Log::warning('Invalid date range in balance calculation', [
                'fromDate' => $this->fromDate,
                'toDate' => $this->toDate
            ]);
            return collect();
        }

        $accounts = $activeProfile->accounts()->notRemoved()->get();

        return $accounts->map(function ($account) {
            $startBalance = $this->fromDate ? $this->calculateStartBalance($account->id, $this->fromDate) : 0;
            $endBalance = $this->toDate ? $this->calculateEndBalance($account->id, $this->toDate) : $this->getBalance($account->id);
            $difference = $endBalance - $startBalance;

            return [
                'id' => $account->id,
                'name' => __('messages.' . $account->name . '_account'),
                'start_balance' => $startBalance,
                'end_balance' => $endBalance,
                'difference' => $difference,
                'limit_max' => $account->limit_max,
                'start_balance_formatted' => $this->formatAmount($startBalance),
                'end_balance_formatted' => $this->formatAmount($endBalance),
                'difference_formatted' => $this->formatAmount($difference),
            ];
        });
    }
    

    /**
     * Calculate transaction type totals for the period
     */
    public function calculateTransactionTypeTotals()
    {
        if (!$this->fromDate || !$this->toDate) {
            return collect();
        }

        // Validate date range before processing
        if (Carbon::parse($this->fromDate)->gt(Carbon::parse($this->toDate))) {
            Log::warning('Invalid date range in transaction types calculation', [
                'fromDate' => $this->fromDate,
                'toDate' => $this->toDate
            ]);
            return collect();
        }

        $activeProfile = getActiveProfile();
        if (!$activeProfile || !method_exists($activeProfile, 'accounts')) {
            return collect();
        }

        $accountIds = $activeProfile->accounts()->notRemoved()->pluck('id');


        $transactionsQuery = Transaction::with('transactionType')
            ->where(function ($query) use ($accountIds) {
                $query->whereIn('from_account_id', $accountIds)
                    ->orWhereIn('to_account_id', $accountIds);
            })
            ->whereBetween('created_at', [$this->fromDate, $this->toDate]);


        $transactions = $transactionsQuery->get();


        // Group transactions by type, separating known and unknown types
        $knownTypes = collect();
        $unknownTransactions = collect();

        $groupedTransactions = $transactions->groupBy('transaction_type_id');

        foreach ($groupedTransactions as $typeId => $typeTransactions) {
            $typeName = $typeTransactions->first()->transactionType->name ?? null;

            if ($typeName && $typeName !== 'Unknown') {
                // Known transaction type
                $incoming = $typeTransactions->whereIn('to_account_id', $accountIds)->sum('amount');
                $outgoing = $typeTransactions->whereIn('from_account_id', $accountIds)->sum('amount');
                $net = $incoming - $outgoing;

                $knownTypes->put($typeId, [
                    'type_name' => __(ucfirst(strtolower($typeName))),
                    'incoming' => $incoming,
                    'outgoing' => $outgoing,
                    'net' => $net,
                    'incoming_formatted' => $this->formatAmount($incoming),
                    'outgoing_formatted' => $this->formatAmount($outgoing),
                    'net_formatted' => $this->formatAmount($net),
                ]);
            } else {
                // Unknown transaction type - add to collection for grouping
                $unknownTransactions = $unknownTransactions->concat($typeTransactions);
            }
        }

        // If we have unknown transactions, group them into a single "Unknown" entry
        if ($unknownTransactions->count() > 0) {
            $incoming = $unknownTransactions->whereIn('to_account_id', $accountIds)->sum('amount');
            $outgoing = $unknownTransactions->whereIn('from_account_id', $accountIds)->sum('amount');
            $net = $incoming - $outgoing;

            $knownTypes->put('unknown', [
                'type_name' => __('Unknown'),
                'incoming' => $incoming,
                'outgoing' => $outgoing,
                'net' => $net,
                'incoming_formatted' => $this->formatAmount($incoming),
                'outgoing_formatted' => $this->formatAmount($outgoing),
                'net_formatted' => $this->formatAmount($net),
            ]);
        }

        // Only hide the breakdown if there are only unknown types (not if there are no transactions)
        if ($knownTypes->count() === 1 && $knownTypes->has('unknown')) {
            return collect();
        }

        return $knownTypes;
    }

    /**
     * Calculate return ratio data for chart visualization over time periods
     */
    public function calculateReturnRatioTimeline()
    {
        if (!$this->fromDate || !$this->toDate) {
            return [];
        }

        $activeProfile = getActiveProfile();
        if (!$activeProfile || !method_exists($activeProfile, 'accounts')) {
            return [];
        }

        $accountIds = $activeProfile->accounts()->notRemoved()->pluck('id');
        $fromDate = Carbon::parse($this->fromDate);
        $toDate = Carbon::parse($this->toDate);

        // Always use monthly intervals for consistent chart display
        $timelineData = [];
        $currentDate = $fromDate->copy()->startOfMonth();

        while ($currentDate->lte($toDate)) {
            $periodStart = $currentDate->copy();
            $periodEnd = $currentDate->copy()->endOfMonth();

            // Don't go beyond the selected end date
            if ($periodEnd->gt($toDate)) {
                $periodEnd = $toDate->copy()->endOfDay();
            }

            // Don't start before the selected start date
            if ($periodStart->lt($fromDate)) {
                $periodStart = $fromDate->copy();
            }

            // Calculate return ratio for this period
            $periodRatio = $this->calculateReturnRatioForPeriod($accountIds, $periodStart, $periodEnd);

            // Also calculate account balances for this period
            $accounts = $activeProfile->accounts()->notRemoved()->get();
            $accountBalances = [];
            foreach ($accounts as $account) {
                $balance = $this->calculateEndBalance($account->id, $periodEnd->format('Y-m-d'));
                $accountBalances[] = [
                    'account_id' => $account->id,
                    'account_name' => __('messages.' . $account->name . '_account'),
                    'balance' => $balance, // Keep raw value for chart calculations
                    'balance_formatted' => tbFormat($balance) // Add formatted version
                ];
            }

            $timelineData[] = [
                'label' => $periodStart->format('M Y'),
                'date' => $periodStart->format('Y-m-d'),
                'return_ratio' => $periodRatio,
                'accounts' => $accountBalances, // Add account balances data
                'translations' => [
                    'period' => __('Period'),
                    'return_ratio' => __('Reciprocity Rate')
                ]
            ];

            // Move to next month
            $currentDate->addMonth();
        }

        // Calculate trend line using linear regression
        $trendData = $this->calculateTrendLine($timelineData);

        return [
            'timeline' => $timelineData,
            'trend' => $trendData
        ];
    }

    /**
     * Calculate trend line using 4 key data points for better trend analysis
     */
    private function calculateTrendLine($timelineData)
    {
        if (count($timelineData) < 4) {
            return [];
        }

        $n = count($timelineData);

        // Use 4 key points distributed across the timeline for better trend analysis
        $keyPoints = [
            ['index' => 0, 'value' => $timelineData[0]['return_ratio']],
            ['index' => floor($n / 3), 'value' => $timelineData[floor($n / 3)]['return_ratio']],
            ['index' => floor(2 * $n / 3), 'value' => $timelineData[floor(2 * $n / 3)]['return_ratio']],
            ['index' => $n - 1, 'value' => $timelineData[$n - 1]['return_ratio']]
        ];

        // Calculate linear regression using these 4 points
        $sumX = 0;
        $sumY = 0;
        $sumXY = 0;
        $sumXX = 0;
        $pointCount = 4;

        foreach ($keyPoints as $point) {
            $x = $point['index'];
            $y = $point['value'];

            $sumX += $x;
            $sumY += $y;
            $sumXY += $x * $y;
            $sumXX += $x * $x;
        }

        // Calculate slope (m) and y-intercept (b) for y = mx + b
        $denominator = ($pointCount * $sumXX) - ($sumX * $sumX);

        if ($denominator == 0) {
            // Avoid division by zero - return flat line at average
            $average = $sumY / $pointCount;
            $trendData = [];
            foreach ($timelineData as $point) {
                $trendData[] = [
                    'label' => $point['label'],
                    'date' => $point['date'],
                    'trend_value' => $average
                ];
            }
            return $trendData;
        }

        $slope = (($pointCount * $sumXY) - ($sumX * $sumY)) / $denominator;
        $intercept = ($sumY - ($slope * $sumX)) / $pointCount;


        // Generate trend line points for all data points
        $trendData = [];
        foreach ($timelineData as $index => $point) {
            $trendValue = ($slope * $index) + $intercept;
            $trendData[] = [
                'label' => $point['label'],
                'date' => $point['date'],
                'trend_value' => $trendValue
            ];
        }

        return $trendData;
    }

    /**
     * Calculate account balances timeline for chart visualization
     */
    public function calculateAccountBalancesTimeline()
    {
        if (!$this->fromDate || !$this->toDate) {
            return [];
        }

        $activeProfile = getActiveProfile();
        if (!$activeProfile || !method_exists($activeProfile, 'accounts')) {
            return [];
        }

        $accounts = $activeProfile->accounts()->notRemoved()->get();
        $fromDate = Carbon::parse($this->fromDate);
        $toDate = Carbon::parse($this->toDate);

        // Always use monthly intervals for consistent chart display
        $timelineData = [];
        $currentDate = $fromDate->copy()->startOfMonth();

        while ($currentDate->lte($toDate)) {
            $periodStart = $currentDate->copy();
            $periodEnd = $currentDate->copy()->endOfMonth();

            // Don't go beyond the selected end date
            if ($periodEnd->gt($toDate)) {
                $periodEnd = $toDate->copy()->endOfDay();
            }

            // Don't start before the selected start date
            if ($periodStart->lt($fromDate)) {
                $periodStart = $fromDate->copy();
            }

            $monthData = [
                'label' => $periodStart->format('M Y'),
                'date' => $periodStart->format('Y-m-d'),
                'accounts' => [],
                'translations' => [
                    'period' => __('Period'),
                    'balance' => __('Balance')
                ]
            ];

            // Calculate balance for each account at the end of this period
            foreach ($accounts as $account) {
                $balance = $this->calculateEndBalance($account->id, $periodEnd->format('Y-m-d'));
                $monthData['accounts'][] = [
                    'account_id' => $account->id,
                    'account_name' => __('messages.' . $account->name . '_account'),
                    'balance' => $balance
                ];
            }

            $timelineData[] = $monthData;

            // Move to next month
            $currentDate->addMonth();
        }


        return $timelineData;
    }

    /**
     * Calculate return ratio for a specific period
     */
    private function calculateReturnRatioForPeriod($accountIds, $startDate, $endDate)
    {
        $activeProfile = getActiveProfile();
        $activeProfileKey = get_class($activeProfile) . ':' . $activeProfile->id;
        $accountIdsArray = $accountIds->toArray();

        $transactions = Transaction::with(['accountFrom.accountable', 'accountTo.accountable'])
            ->where(function ($query) use ($accountIds) {
                $query->whereIn('from_account_id', $accountIds)
                    ->orWhereIn('to_account_id', $accountIds);
            })
            ->whereBetween('created_at', [$startDate, $endDate])
            ->get();

        $profileRatios = [];

        foreach ($transactions as $transaction) {
            $fromAccountId = $transaction->from_account_id;
            $toAccountId = $transaction->to_account_id;
            $amount = $transaction->amount;

            $fromProfileKey = null;
            $toProfileKey = null;

            if ($transaction->accountFrom && $transaction->accountFrom->accountable) {
                $fromProfileKey = $transaction->accountFrom->accountable_type . ':' . $transaction->accountFrom->accountable_id;
            }
            if ($transaction->accountTo && $transaction->accountTo->accountable) {
                $toProfileKey = $transaction->accountTo->accountable_type . ':' . $transaction->accountTo->accountable_id;
            }

            if (!$fromProfileKey || !$toProfileKey) {
                continue;
            }

            // When the active profile sends money to someone else (helping someone)
            if (in_array($fromAccountId, $accountIdsArray) && $toProfileKey !== $activeProfileKey) {
                if (!isset($profileRatios[$toProfileKey])) {
                    $profileRatios[$toProfileKey] = ['given' => 0, 'received' => 0];
                }
                $profileRatios[$toProfileKey]['given'] += $amount;
            }
            // When the active profile receives money from someone else (being helped back)
            elseif (in_array($toAccountId, $accountIdsArray) && $fromProfileKey !== $activeProfileKey) {
                if (!isset($profileRatios[$fromProfileKey])) {
                    $profileRatios[$fromProfileKey] = ['given' => 0, 'received' => 0];
                }
                $profileRatios[$fromProfileKey]['received'] += $amount;
            }
        }

        $returnRatios = [];
        foreach ($profileRatios as $profileKey => $amounts) {
            if ($amounts['given'] > 0) {
                $ratio = ($amounts['received'] / $amounts['given']) * 100;
                $returnRatios[] = $ratio;
            }
        }

        $averageRatio = count($returnRatios) > 0 ? array_sum($returnRatios) / count($returnRatios) : 0;

        return $averageRatio;
    }

    /**
     * Calculate period statistics
     */
    public function calculatePeriodStatistics()
    {
        if (!$this->fromDate || !$this->toDate) {
            return [
                'transaction_count' => 0,
                'unique_profiles' => 0,
                'profiles_by_type' => collect(),
                'average_return_ratio' => 0,
            ];
        }

        // Validate date range before processing
        if (Carbon::parse($this->fromDate)->gt(Carbon::parse($this->toDate))) {
            Log::warning('Invalid date range in period statistics calculation', [
                'fromDate' => $this->fromDate,
                'toDate' => $this->toDate
            ]);
            return [
                'transaction_count' => 0,
                'unique_profiles' => 0,
                'profiles_by_type' => collect(),
                'average_return_ratio' => 0,
            ];
        }

        $activeProfile = getActiveProfile();
        if (!$activeProfile || !method_exists($activeProfile, 'accounts')) {
            return [
                'transaction_count' => 0,
                'unique_profiles' => 0,
                'profiles_by_type' => collect(),
                'average_return_ratio' => 0,
            ];
        }

        $accountIds = $activeProfile->accounts()->notRemoved()->pluck('id');

        $transactionsQuery = Transaction::where(function ($query) use ($accountIds) {
                $query->whereIn('from_account_id', $accountIds)
                    ->orWhereIn('to_account_id', $accountIds);
            })
            ->whereBetween('created_at', [$this->fromDate, $this->toDate]);

        $transactionCount = $transactionsQuery->count();

        // Get unique profiles involved in transactions (excluding the active profile)
        $transactions = $transactionsQuery->with(['accountFrom.accountable', 'accountTo.accountable'])->get();

        $activeProfileKey = get_class($activeProfile) . ':' . $activeProfile->id;
        $uniqueProfiles = collect();

        foreach ($transactions as $transaction) {
            if ($transaction->accountFrom && $transaction->accountFrom->accountable) {
                $profileKey = $transaction->accountFrom->accountable_type . ':' . $transaction->accountFrom->accountable_id;
                if ($profileKey !== $activeProfileKey) {
                    $uniqueProfiles->push([
                        'key' => $profileKey,
                        'type' => $transaction->accountFrom->accountable_type
                    ]);
                }
            }
            if ($transaction->accountTo && $transaction->accountTo->accountable) {
                $profileKey = $transaction->accountTo->accountable_type . ':' . $transaction->accountTo->accountable_id;
                if ($profileKey !== $activeProfileKey) {
                    $uniqueProfiles->push([
                        'key' => $profileKey,
                        'type' => $transaction->accountTo->accountable_type
                    ]);
                }
            }
        }

        // Get unique profiles and group by type
        $uniqueProfilesData = $uniqueProfiles->unique('key');
        $profilesByType = $uniqueProfilesData->groupBy('type')->map(function ($profiles) {
            return $profiles->count();
        });

        // Calculate return ratio: what percentage of timebank hours you get back from people you've helped
        // Example: You give 10 hours to someone, they give you 4 hours back = 40% return ratio
        // This is averaged across all people you've transacted with during the selected period
        $profileRatios = [];
        $accountIdsArray = $accountIds->toArray();

        // Process each transaction to track giving/receiving amounts per profile
        foreach ($transactions as $transaction) {
            $fromAccountId = $transaction->from_account_id;
            $toAccountId = $transaction->to_account_id;
            $amount = $transaction->amount;

            // Get unique profile identifiers for both sender and receiver
            $fromProfileKey = null;
            $toProfileKey = null;

            if ($transaction->accountFrom && $transaction->accountFrom->accountable) {
                $fromProfileKey = $transaction->accountFrom->accountable_type . ':' . $transaction->accountFrom->accountable_id;
            }
            if ($transaction->accountTo && $transaction->accountTo->accountable) {
                $toProfileKey = $transaction->accountTo->accountable_type . ':' . $transaction->accountTo->accountable_id;
            }

            // Skip transactions where we can't identify both profiles
            if (!$fromProfileKey || !$toProfileKey) {
                continue;
            }

            // Track transactions between active profile and other profiles
            if (in_array($fromAccountId, $accountIdsArray) && $toProfileKey !== $activeProfileKey) {
                // Active profile gave hours to another profile - track as "given"
                if (!isset($profileRatios[$toProfileKey])) {
                    $profileRatios[$toProfileKey] = ['given' => 0, 'received' => 0];
                }
                $profileRatios[$toProfileKey]['given'] += $amount;
            } elseif (in_array($toAccountId, $accountIdsArray) && $fromProfileKey !== $activeProfileKey) {
                // Active profile received hours from another profile - track as "received"
                if (!isset($profileRatios[$fromProfileKey])) {
                    $profileRatios[$fromProfileKey] = ['given' => 0, 'received' => 0];
                }
                $profileRatios[$fromProfileKey]['received'] += $amount;
            }
        }

        // Calculate individual return ratios and compute average
        $returnRatios = [];
        foreach ($profileRatios as $profileKey => $amounts) {
            if ($amounts['given'] > 0) {
                // Return ratio = (hours received back / hours given) × 100
                $ratio = ($amounts['received'] / $amounts['given']) * 100;
                $returnRatios[] = $ratio;
            }
        }

        // Average return ratio across all profiles
        $averageReturnRatio = count($returnRatios) > 0 ? array_sum($returnRatios) / count($returnRatios) : 0;

        return [
            'transaction_count' => $transactionCount,
            'unique_profiles' => $uniqueProfilesData->count(),
            'profiles_by_type' => $profilesByType,
            'average_return_ratio' => $averageReturnRatio,
        ];
    }

    /**
     * Export report as PDF
     */
    public function exportPdf()
    {
        $profile = getActiveProfile();

        if (!$profile) {
            abort(403, 'No active profile');
        }

        // CRITICAL SECURITY: Validate authorization before export
        \App\Helpers\ProfileAuthorizationHelper::authorize($profile);

        // Build URL with current report parameters
        $params = [
            'fromDate' => $this->fromDate,
            'toDate' => $this->toDate,
            'decimal' => $this->decimalFormat ? 1 : 0,
        ];

        $url = route('reports.pdf', $params);

        // Use JavaScript to open PDF in new window/tab
        $this->dispatch('openPdf', $url);
    }

    /**
     * Handle export PDF with charts request
     * This method is triggered by the export button and dispatches a browser event
     * to trigger the JavaScript chart export function
     */
    public function handleExportPdfWithCharts()
    {
        $profile = getActiveProfile();

        if (!$profile) {
            abort(403, 'No active profile');
        }

        // CRITICAL SECURITY: Validate authorization before export
        \App\Helpers\ProfileAuthorizationHelper::authorize($profile);

        // Check if any charts will be rendered (need more than 4 data points)
        $returnRatioData = $this->calculateReturnRatioTimeline();
        $returnRatioTimelineData = $returnRatioData['timeline'] ?? [];
        $hasReturnRatioChart = $this->isOrganization && count($returnRatioTimelineData) > 4;
        $hasBalancesChart = count($returnRatioTimelineData) > 4; // account balances chart uses same timeline data

        Log::info('handleExportPdfWithCharts', [
            'isOrganization' => $this->isOrganization,
            'timelineDataCount' => count($returnRatioTimelineData),
            'hasReturnRatioChart' => $hasReturnRatioChart,
            'hasBalancesChart' => $hasBalancesChart,
            'fromDate' => $this->fromDate,
            'toDate' => $this->toDate,
        ]);

        if ($hasReturnRatioChart || $hasBalancesChart) {
            // Dispatch browser event to trigger JavaScript chart export
            Log::info('Dispatching trigger-chart-export browser event');
            $this->dispatch('trigger-chart-export');
        } else {
            // No charts available, export regular PDF directly
            Log::info('No charts available, calling exportPdf directly');
            $this->exportPdf();
        }
    }

    /**
     * Export report as PDF with chart image
     */
    public function exportPdfWithChart($chartImage, $fromDate = null, $toDate = null)
    {
        $profile = getActiveProfile();

        if (!$profile) {
            abort(403, 'No active profile');
        }

        // CRITICAL SECURITY: Validate authorization before export
        \App\Helpers\ProfileAuthorizationHelper::authorize($profile);

        // Use passed dates if provided, otherwise use component dates
        $actualFromDate = $fromDate ?? $this->fromDate;
        $actualToDate = $toDate ?? $this->toDate;


        // Generate unique filename for temporary chart image
        $chartImageId = uniqid('chart_', true);
        $tempImagePath = storage_path('app/temp/' . $chartImageId . '.png');

        // Ensure temp directory exists
        if (!file_exists(dirname($tempImagePath))) {
            mkdir(dirname($tempImagePath), 0755, true);
        }

        // Extract base64 data and save to temporary file
        $base64Data = explode(',', $chartImage)[1] ?? $chartImage;
        $imageData = base64_decode($base64Data);
        file_put_contents($tempImagePath, $imageData);


        // Store only the chart image ID in session (much smaller)
        session(['chart_image_id' => $chartImageId]);

        // Build URL with current report parameters
        $params = [
            'fromDate' => $actualFromDate,
            'toDate' => $actualToDate,
            'with_chart' => 1,
            'decimal' => $this->decimalFormat ? 1 : 0,
        ];

        $url = route('reports.pdf', $params);

        // Use JavaScript to open PDF in new window/tab
        $this->dispatch('openPdf', $url);
    }

    /**
     * Clean UTF-8 encoding for strings
     */
    private function cleanUtf8String($string)
    {
        if (!is_string($string)) {
            return $string;
        }

        // Remove or replace problematic characters
        $string = mb_convert_encoding($string, 'UTF-8', 'UTF-8');
        $string = preg_replace('/[\x00-\x1F\x7F-\x9F]/u', '', $string);

        return $string;
    }

    /**
     * Clean UTF-8 encoding for arrays/collections
     */
    private function cleanUtf8Data($data)
    {
        if (is_string($data)) {
            return $this->cleanUtf8String($data);
        }

        if (is_array($data) || $data instanceof \Illuminate\Support\Collection) {
            $cleaned = [];
            foreach ($data as $key => $value) {
                $cleanedKey = $this->cleanUtf8String($key);
                $cleanedValue = $this->cleanUtf8Data($value);
                $cleaned[$cleanedKey] = $cleanedValue;
            }
            return $data instanceof \Illuminate\Support\Collection ? collect($cleaned) : $cleaned;
        }

        return $data;
    }




    public function render()
    {
        $profile = getActiveProfile();

        if (!$profile) {
            abort(403, 'No active profile');
        }

        // CRITICAL SECURITY: Re-validate authorization on every render
        // This prevents data exposure after session manipulation between interactions
        \App\Helpers\ProfileAuthorizationHelper::authorize($profile);

        // Update title based on current data state
        $this->generateAndDispatchTitle('custom');

        $returnRatioData = $this->calculateReturnRatioTimeline();
        $returnRatioTimelineData = $returnRatioData['timeline'] ?? [];
        $returnRatioTrendData = $returnRatioData['trend'] ?? [];
        $accountBalancesTimelineData = $returnRatioTimelineData; // Use same data as return ratio chart

        return view('livewire.single-report', [
            'accountsData' => $this->getAccountsWithPeriodBalances(),
            'transactionTypesData' => $this->calculateTransactionTypeTotals(),
            'statisticsData' => $this->calculatePeriodStatistics(),
            'returnRatioTimelineData' => $returnRatioTimelineData,
            'returnRatioTrendData' => $returnRatioTrendData,
            'accountBalancesTimelineData' => $accountBalancesTimelineData,
        ]);
    }

    /**
     * Export report as PDF with both chart images
     */
    public function exportPdfWithCharts($returnRatioChartImage = null, $accountBalancesChartImage = null, $fromDate = null, $toDate = null, $decimalFormat = null)
    {
        $profile = getActiveProfile();

        if (!$profile) {
            abort(403, 'No active profile');
        }

        // CRITICAL SECURITY: Validate authorization before export
        \App\Helpers\ProfileAuthorizationHelper::authorize($profile);

        // Use passed dates if provided, otherwise use component dates
        $actualFromDate = $fromDate ?? $this->fromDate;
        $actualToDate = $toDate ?? $this->toDate;


        $chartImageIds = [];

        // Process Return Ratio Chart image
        if ($returnRatioChartImage) {
            $returnRatioChartImageId = uniqid('return_ratio_chart_', true);
            $tempImagePath = storage_path('app/temp/' . $returnRatioChartImageId . '.png');

            // Ensure temp directory exists
            if (!file_exists(dirname($tempImagePath))) {
                mkdir(dirname($tempImagePath), 0755, true);
            }

            // Extract base64 data and save to temporary file
            $base64Data = explode(',', $returnRatioChartImage)[1] ?? $returnRatioChartImage;
            $imageData = base64_decode($base64Data);
            file_put_contents($tempImagePath, $imageData);

            $chartImageIds['return_ratio_chart_id'] = $returnRatioChartImageId;

        }

        // Process Account Balances Chart image
        if ($accountBalancesChartImage) {
            $accountBalancesChartImageId = uniqid('account_balances_chart_', true);
            $tempImagePath = storage_path('app/temp/' . $accountBalancesChartImageId . '.png');

            // Ensure temp directory exists
            if (!file_exists(dirname($tempImagePath))) {
                mkdir(dirname($tempImagePath), 0755, true);
            }

            // Extract base64 data and save to temporary file
            $base64Data = explode(',', $accountBalancesChartImage)[1] ?? $accountBalancesChartImage;
            $imageData = base64_decode($base64Data);
            file_put_contents($tempImagePath, $imageData);

            $chartImageIds['account_balances_chart_id'] = $accountBalancesChartImageId;

        }

        // Store chart image IDs in session
        session(['chart_image_ids' => $chartImageIds]);

        // Build URL with current report parameters
        // Use explicitly passed decimalFormat if provided, otherwise fall back to component state
        $useDecimal = $decimalFormat !== null ? (bool) $decimalFormat : $this->decimalFormat;
        $params = [
            'fromDate' => $actualFromDate,
            'toDate' => $actualToDate,
            'with_charts' => 1,
            'decimal' => $useDecimal ? 1 : 0,
        ];

        $url = route('reports.pdf', $params);

        // Use JavaScript to open PDF in new window/tab
        $this->dispatch('openPdf', $url);
    }
}