<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Transaction;
use App\Models\VendorTransactionLog;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;

class ReportController extends Controller
{
    public function exportCsv(Request $request): StreamedResponse
    {
        [$range, $start, $end, $groupBy] = $this->resolveWindow($request);
        $summary = $this->buildSummary($this->transactionRangeQuery($start, $end));
        $timeline = $this->buildTimeline($start, $end, $groupBy);
        $serviceSummary = $this->buildServiceSummary($start, $end);
        $vendorPerformance = $this->buildVendorPerformance($start, $end);

        $filename = sprintf(
            'reports-%s-%s-%s.csv',
            $range,
            $groupBy,
            now()->format('Ymd_His')
        );

        return response()->streamDownload(function () use (
            $range,
            $groupBy,
            $start,
            $end,
            $summary,
            $timeline,
            $serviceSummary,
            $vendorPerformance
        ): void {
            $out = fopen('php://output', 'w');

            fputcsv($out, ['REPORT META']);
            fputcsv($out, ['range', $range]);
            fputcsv($out, ['group_by', $groupBy]);
            fputcsv($out, ['start_date', $start->toDateString()]);
            fputcsv($out, ['end_date', $end->toDateString()]);
            fputcsv($out, []);

            fputcsv($out, ['SUMMARY']);
            fputcsv($out, [
                'total_transactions',
                'gross_sales',
                'vendor_cost_total',
                'realized_profit',
                'failure_impact',
                'net_profit',
                'success_count',
                'pending_count',
                'failed_count',
                'stuck_count',
                'success_rate_percent',
                'profit_margin_percent',
            ]);
            fputcsv($out, [
                $summary['total_transactions'] ?? 0,
                $summary['gross_sales'] ?? 0,
                $summary['vendor_cost_total'] ?? 0,
                $summary['realized_profit'] ?? 0,
                $summary['failure_impact'] ?? 0,
                $summary['net_profit'] ?? 0,
                $summary['success_count'] ?? 0,
                $summary['pending_count'] ?? 0,
                $summary['failed_count'] ?? 0,
                $summary['stuck_count'] ?? 0,
                $summary['success_rate'] ?? 0,
                $summary['profit_margin_percent'] ?? 0,
            ]);
            fputcsv($out, []);

            fputcsv($out, ['TIMELINE']);
            fputcsv($out, ['period_start', 'label', 'total_transactions', 'gross_sales', 'realized_profit', 'failure_impact', 'net_profit']);
            foreach ($timeline as $row) {
                fputcsv($out, [
                    $row['period_start'] ?? '',
                    $row['label'] ?? '',
                    $row['total_transactions'] ?? 0,
                    $row['gross_sales'] ?? 0,
                    $row['realized_profit'] ?? 0,
                    $row['failure_impact'] ?? 0,
                    $row['net_profit'] ?? 0,
                ]);
            }
            fputcsv($out, []);

            fputcsv($out, ['SERVICE SUMMARY']);
            fputcsv($out, ['service', 'total_transactions', 'success_rate_percent', 'gross_sales', 'realized_profit', 'failure_impact', 'net_profit', 'pending_count', 'failed_count', 'stuck_count']);
            foreach ($serviceSummary as $row) {
                fputcsv($out, [
                    $row['label'] ?? '',
                    $row['total_transactions'] ?? 0,
                    $row['success_rate'] ?? 0,
                    $row['gross_sales'] ?? 0,
                    $row['realized_profit'] ?? 0,
                    $row['failure_impact'] ?? 0,
                    $row['net_profit'] ?? 0,
                    $row['pending_count'] ?? 0,
                    $row['failed_count'] ?? 0,
                    $row['stuck_count'] ?? 0,
                ]);
            }
            fputcsv($out, []);

            fputcsv($out, ['VENDOR PERFORMANCE']);
            fputcsv($out, ['vendor_name', 'vendor_type', 'total_transactions', 'success_rate_percent', 'avg_latency_ms', 'gross_sales', 'realized_profit', 'failure_impact', 'net_profit', 'pending_count', 'failed_count', 'stuck_count']);
            foreach ($vendorPerformance as $row) {
                fputcsv($out, [
                    $row['vendor_name'] ?? '',
                    $row['vendor_type'] ?? '',
                    $row['total_transactions'] ?? 0,
                    $row['success_rate'] ?? 0,
                    $row['avg_latency_ms'] ?? 0,
                    $row['gross_sales'] ?? 0,
                    $row['realized_profit'] ?? 0,
                    $row['failure_impact'] ?? 0,
                    $row['net_profit'] ?? 0,
                    $row['pending_count'] ?? 0,
                    $row['failed_count'] ?? 0,
                    $row['stuck_count'] ?? 0,
                ]);
            }

            fclose($out);
        }, $filename, [
            'Content-Type' => 'text/csv',
        ]);
    }

    public function index(Request $request): Response
    {
        [$range, $start, $end, $groupBy, $tab] = $this->resolveWindow($request);
        $base = $this->transactionRangeQuery($start, $end);

        $summary = $this->buildSummary($base);
        $serviceSummary = $this->buildServiceSummary($start, $end);
        $categorySummary = $this->buildCategorySummary($start, $end);
        $vendorPerformance = $this->buildVendorPerformance($start, $end);
        $timeline = $this->buildTimeline($start, $end, $groupBy);
        $reliability = $this->buildReliabilitySummary($start, $end, $base);

        return Inertia::render('Admin/Reports/Index', [
            'summary' => $summary,
            'serviceSummary' => $serviceSummary,
            'categorySummary' => $categorySummary,
            'vendorPerformance' => $vendorPerformance,
            'timeline' => $timeline,
            'reliability' => $reliability,
            'filters' => [
                'range' => $range,
                'group_by' => $groupBy,
                'start_date' => $start->toDateString(),
                'end_date' => $end->toDateString(),
                'tab' => $tab,
            ],
        ]);
    }

    protected function transactionRangeQuery(Carbon $start, Carbon $end): Builder
    {
        return Transaction::query()->whereBetween('created_at', [$start, $end]);
    }

    /**
     * @param  Builder<Transaction>  $base
     * @return array<string, mixed>
     */
    protected function buildSummary(Builder $base): array
    {
        $profitExpr = 'COALESCE(profit, CASE WHEN vendor_cost IS NOT NULL THEN amount_charged - vendor_cost ELSE 0 END)';

        $row = (clone $base)
            ->selectRaw('COUNT(*) as total_transactions')
            ->selectRaw('COALESCE(SUM(amount_charged), 0) as gross_sales')
            ->selectRaw("COALESCE(SUM(CASE WHEN status = 'success' THEN amount_charged ELSE 0 END), 0) as success_sales")
            ->selectRaw('COALESCE(SUM(vendor_cost), 0) as vendor_cost_total')
            ->selectRaw("COALESCE(SUM(CASE WHEN status = 'success' THEN {$profitExpr} ELSE 0 END), 0) as realized_profit")
            ->selectRaw("COALESCE(SUM(CASE WHEN status IN ('failed', 'reversed', 'stuck') THEN {$profitExpr} ELSE 0 END), 0) as failure_impact")
            ->selectRaw("SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as success_count")
            ->selectRaw("SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_count")
            ->selectRaw("SUM(CASE WHEN status IN ('failed', 'reversed') THEN 1 ELSE 0 END) as failed_count")
            ->selectRaw("SUM(CASE WHEN status = 'stuck' THEN 1 ELSE 0 END) as stuck_count")
            ->first();

        $total = (int) ($row->total_transactions ?? 0);
        $gross = round((float) ($row->gross_sales ?? 0), 2);
        $successSales = round((float) ($row->success_sales ?? 0), 2);
        $realizedProfit = round((float) ($row->realized_profit ?? 0), 2);
        $failureImpact = round((float) ($row->failure_impact ?? 0), 2);
        $netProfit = round($realizedProfit + $failureImpact, 2);
        $success = (int) ($row->success_count ?? 0);
        $failed = (int) ($row->failed_count ?? 0);
        $pending = (int) ($row->pending_count ?? 0);
        $stuck = (int) ($row->stuck_count ?? 0);

        return [
            'total_transactions' => $total,
            'gross_sales' => $gross,
            'success_sales' => $successSales,
            'vendor_cost_total' => round((float) ($row->vendor_cost_total ?? 0), 2),
            // Keep total_profit for backward compatibility with existing cards/components.
            'total_profit' => $realizedProfit,
            'realized_profit' => $realizedProfit,
            'failure_impact' => $failureImpact,
            'net_profit' => $netProfit,
            'success_count' => $success,
            'pending_count' => $pending,
            'failed_count' => $failed,
            'stuck_count' => $stuck,
            'success_rate' => $total > 0 ? round(($success / $total) * 100, 2) : 0.0,
            'failure_rate' => $total > 0 ? round(($failed / $total) * 100, 2) : 0.0,
            'avg_order_value' => $total > 0 ? round($gross / $total, 2) : 0.0,
            'profit_margin_percent' => $successSales > 0 ? round(($realizedProfit / $successSales) * 100, 2) : 0.0,
            'net_margin_percent' => $gross > 0 ? round(($netProfit / $gross) * 100, 2) : 0.0,
        ];
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    protected function buildServiceSummary(Carbon $start, Carbon $end): array
    {
        $profitExpr = 'COALESCE(transactions.profit, CASE WHEN transactions.vendor_cost IS NOT NULL THEN transactions.amount_charged - transactions.vendor_cost ELSE 0 END)';

        $serviceCase = "CASE
            WHEN categories.slug IN ('data_sme','data_gifting','data_cg','data_direct') THEN 'data'
            WHEN categories.slug IN ('airtime','airtime_vtu') THEN 'airtime'
            WHEN categories.slug = 'cable' THEN 'cable'
            WHEN categories.slug = 'electricity' THEN 'electricity'
            WHEN categories.slug = 'epin' THEN 'epin'
            ELSE 'other'
        END";

        $rows = Transaction::query()
            ->leftJoin('categories', 'categories.id', '=', 'transactions.category_id')
            ->whereBetween('transactions.created_at', [$start, $end])
            ->selectRaw("{$serviceCase} as service_key")
            ->selectRaw('COUNT(transactions.id) as total_transactions')
            ->selectRaw("SUM(CASE WHEN transactions.status = 'success' THEN 1 ELSE 0 END) as success_count")
            ->selectRaw("SUM(CASE WHEN transactions.status = 'pending' THEN 1 ELSE 0 END) as pending_count")
            ->selectRaw("SUM(CASE WHEN transactions.status IN ('failed', 'reversed') THEN 1 ELSE 0 END) as failed_count")
            ->selectRaw("SUM(CASE WHEN transactions.status = 'stuck' THEN 1 ELSE 0 END) as stuck_count")
            ->selectRaw('COALESCE(SUM(transactions.amount_charged), 0) as gross_sales')
            ->selectRaw('COALESCE(SUM(transactions.vendor_cost), 0) as vendor_cost_total')
            ->selectRaw("COALESCE(SUM(CASE WHEN transactions.status = 'success' THEN {$profitExpr} ELSE 0 END), 0) as realized_profit")
            ->selectRaw("COALESCE(SUM(CASE WHEN transactions.status IN ('failed', 'reversed', 'stuck') THEN {$profitExpr} ELSE 0 END), 0) as failure_impact")
            ->groupBy('service_key')
            ->orderByDesc('gross_sales')
            ->get();

        $labels = [
            'data' => 'Data',
            'airtime' => 'Airtime',
            'cable' => 'Cable',
            'electricity' => 'Electricity',
            'epin' => 'Education Pins',
            'other' => 'Other',
        ];

        return $rows->map(function ($row) use ($labels) {
            $total = (int) ($row->total_transactions ?? 0);

            return [
                'service_key' => (string) $row->service_key,
                'label' => $labels[$row->service_key] ?? ucfirst((string) $row->service_key),
                'total_transactions' => $total,
                'success_count' => (int) ($row->success_count ?? 0),
                'pending_count' => (int) ($row->pending_count ?? 0),
                'failed_count' => (int) ($row->failed_count ?? 0),
                'stuck_count' => (int) ($row->stuck_count ?? 0),
                'gross_sales' => round((float) ($row->gross_sales ?? 0), 2),
                'vendor_cost_total' => round((float) ($row->vendor_cost_total ?? 0), 2),
                'total_profit' => round((float) ($row->realized_profit ?? 0), 2),
                'realized_profit' => round((float) ($row->realized_profit ?? 0), 2),
                'failure_impact' => round((float) ($row->failure_impact ?? 0), 2),
                'net_profit' => round((float) (($row->realized_profit ?? 0) + ($row->failure_impact ?? 0)), 2),
                'success_rate' => $total > 0 ? round(((int) $row->success_count / $total) * 100, 2) : 0.0,
            ];
        })->values()->all();
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    protected function buildCategorySummary(Carbon $start, Carbon $end): array
    {
        $profitExpr = 'COALESCE(transactions.profit, CASE WHEN transactions.vendor_cost IS NOT NULL THEN transactions.amount_charged - transactions.vendor_cost ELSE 0 END)';

        $rows = Transaction::query()
            ->leftJoin('categories', 'categories.id', '=', 'transactions.category_id')
            ->whereBetween('transactions.created_at', [$start, $end])
            ->selectRaw('COALESCE(categories.name, "Unknown") as category_name')
            ->selectRaw('COALESCE(categories.slug, "unknown") as category_slug')
            ->selectRaw('COUNT(transactions.id) as total_transactions')
            ->selectRaw('COALESCE(SUM(transactions.amount_charged), 0) as gross_sales')
            ->selectRaw("COALESCE(SUM(CASE WHEN transactions.status = 'success' THEN {$profitExpr} ELSE 0 END), 0) as realized_profit")
            ->selectRaw("COALESCE(SUM(CASE WHEN transactions.status IN ('failed', 'reversed', 'stuck') THEN {$profitExpr} ELSE 0 END), 0) as failure_impact")
            ->groupBy('categories.name', 'categories.slug')
            ->orderByDesc('total_transactions')
            ->get();

        return $rows->map(fn ($row) => [
            'category_name' => (string) $row->category_name,
            'category_slug' => (string) $row->category_slug,
            'total_transactions' => (int) ($row->total_transactions ?? 0),
            'gross_sales' => round((float) ($row->gross_sales ?? 0), 2),
            'total_profit' => round((float) ($row->realized_profit ?? 0), 2),
            'realized_profit' => round((float) ($row->realized_profit ?? 0), 2),
            'failure_impact' => round((float) ($row->failure_impact ?? 0), 2),
            'net_profit' => round((float) (($row->realized_profit ?? 0) + ($row->failure_impact ?? 0)), 2),
        ])->values()->all();
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    protected function buildVendorPerformance(Carbon $start, Carbon $end): array
    {
        $profitExpr = 'COALESCE(transactions.profit, CASE WHEN transactions.vendor_cost IS NOT NULL THEN transactions.amount_charged - transactions.vendor_cost ELSE 0 END)';

        $latencyByVendor = VendorTransactionLog::query()
            ->whereBetween('created_at', [$start, $end])
            ->whereNotNull('vendor_id')
            ->whereNotNull('duration_ms')
            ->selectRaw('vendor_id, AVG(duration_ms) as avg_latency_ms')
            ->groupBy('vendor_id')
            ->pluck('avg_latency_ms', 'vendor_id');

        $rows = Transaction::query()
            ->join('vendors', 'vendors.id', '=', 'transactions.vendor_id')
            ->whereBetween('transactions.created_at', [$start, $end])
            ->selectRaw('vendors.id as vendor_id, vendors.name as vendor_name, vendors.type as vendor_type')
            ->selectRaw('COUNT(transactions.id) as total_transactions')
            ->selectRaw("SUM(CASE WHEN transactions.status = 'success' THEN 1 ELSE 0 END) as success_count")
            ->selectRaw("SUM(CASE WHEN transactions.status = 'pending' THEN 1 ELSE 0 END) as pending_count")
            ->selectRaw("SUM(CASE WHEN transactions.status IN ('failed', 'reversed') THEN 1 ELSE 0 END) as failed_count")
            ->selectRaw("SUM(CASE WHEN transactions.status = 'stuck' THEN 1 ELSE 0 END) as stuck_count")
            ->selectRaw('COALESCE(SUM(transactions.amount_charged), 0) as gross_sales')
            ->selectRaw('COALESCE(SUM(transactions.vendor_cost), 0) as vendor_cost_total')
            ->selectRaw("COALESCE(SUM(CASE WHEN transactions.status = 'success' THEN {$profitExpr} ELSE 0 END), 0) as realized_profit")
            ->selectRaw("COALESCE(SUM(CASE WHEN transactions.status IN ('failed', 'reversed', 'stuck') THEN {$profitExpr} ELSE 0 END), 0) as failure_impact")
            ->groupBy('vendors.id', 'vendors.name', 'vendors.type')
            ->orderByDesc('total_transactions')
            ->get();

        return $rows->map(function ($row) use ($latencyByVendor) {
            $total = (int) ($row->total_transactions ?? 0);

            return [
                'vendor_id' => (int) $row->vendor_id,
                'vendor_name' => (string) $row->vendor_name,
                'vendor_type' => (string) $row->vendor_type,
                'total_transactions' => $total,
                'success_count' => (int) ($row->success_count ?? 0),
                'pending_count' => (int) ($row->pending_count ?? 0),
                'failed_count' => (int) ($row->failed_count ?? 0),
                'stuck_count' => (int) ($row->stuck_count ?? 0),
                'gross_sales' => round((float) ($row->gross_sales ?? 0), 2),
                'vendor_cost_total' => round((float) ($row->vendor_cost_total ?? 0), 2),
                'total_profit' => round((float) ($row->realized_profit ?? 0), 2),
                'realized_profit' => round((float) ($row->realized_profit ?? 0), 2),
                'failure_impact' => round((float) ($row->failure_impact ?? 0), 2),
                'net_profit' => round((float) (($row->realized_profit ?? 0) + ($row->failure_impact ?? 0)), 2),
                'success_rate' => $total > 0 ? round(((int) $row->success_count / $total) * 100, 2) : 0.0,
                'avg_latency_ms' => round((float) ($latencyByVendor[$row->vendor_id] ?? 0)),
            ];
        })->values()->all();
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    protected function buildTimeline(Carbon $start, Carbon $end, string $groupBy): array
    {
        $profitExpr = 'COALESCE(profit, CASE WHEN vendor_cost IS NOT NULL THEN amount_charged - vendor_cost ELSE 0 END)';

        if ($groupBy === 'week') {
            $groupExpr = 'DATE(DATE_SUB(created_at, INTERVAL WEEKDAY(created_at) DAY))';
            $labelFormat = 'M d, Y';
            $step = 'week';
        } else {
            $groupExpr = 'DATE(created_at)';
            $labelFormat = 'M d';
            $step = 'day';
        }

        $rows = Transaction::query()
            ->whereBetween('created_at', [$start, $end])
            ->selectRaw("{$groupExpr} as period_start")
            ->selectRaw('COUNT(*) as total_transactions')
            ->selectRaw('COALESCE(SUM(amount_charged), 0) as gross_sales')
            ->selectRaw("COALESCE(SUM(CASE WHEN status = 'success' THEN {$profitExpr} ELSE 0 END), 0) as realized_profit")
            ->selectRaw("COALESCE(SUM(CASE WHEN status IN ('failed', 'reversed', 'stuck') THEN {$profitExpr} ELSE 0 END), 0) as failure_impact")
            ->groupBy('period_start')
            ->orderBy('period_start')
            ->get()
            ->keyBy('period_start');

        $periods = [];
        $cursor = $step === 'week'
            ? $start->copy()->startOfWeek(Carbon::MONDAY)
            : $start->copy()->startOfDay();
        $endCursor = $step === 'week'
            ? $end->copy()->startOfWeek(Carbon::MONDAY)
            : $end->copy()->startOfDay();

        while ($cursor->lte($endCursor)) {
            $key = $cursor->toDateString();
            $row = $rows->get($key);

            $periods[] = [
                'period_start' => $key,
                'label' => $cursor->format($labelFormat),
                'total_transactions' => (int) data_get($row, 'total_transactions', 0),
                'gross_sales' => round((float) data_get($row, 'gross_sales', 0), 2),
                'total_profit' => round((float) data_get($row, 'realized_profit', 0), 2),
                'realized_profit' => round((float) data_get($row, 'realized_profit', 0), 2),
                'failure_impact' => round((float) data_get($row, 'failure_impact', 0), 2),
                'net_profit' => round(
                    (float) data_get($row, 'realized_profit', 0) + (float) data_get($row, 'failure_impact', 0),
                    2
                ),
            ];

            $cursor = $step === 'week'
                ? $cursor->addWeek()
                : $cursor->addDay();
        }

        return $periods;
    }

    /**
     * @param  Builder<Transaction>  $base
     * @return array<string, mixed>
     */
    protected function buildReliabilitySummary(Carbon $start, Carbon $end, Builder $base): array
    {
        $pendingNow = Transaction::query()->where('status', 'pending');
        $pendingOver15 = (clone $pendingNow)->where('created_at', '<=', now()->subMinutes(15))->count();
        $pendingOver60 = (clone $pendingNow)->where('created_at', '<=', now()->subMinutes(60))->count();
        $stuckNow = Transaction::query()->where('status', 'stuck')->count();

        $topErrors = (clone $base)
            ->whereNotNull('last_error')
            ->select('last_error', DB::raw('COUNT(*) as total'))
            ->groupBy('last_error')
            ->orderByDesc('total')
            ->limit(5)
            ->get()
            ->map(fn ($row) => [
                'message' => (string) $row->last_error,
                'total' => (int) ($row->total ?? 0),
            ])
            ->values()
            ->all();

        $rangePending = (clone $base)->where('status', 'pending')->count();
        $rangeStuck = (clone $base)->where('status', 'stuck')->count();

        return [
            'pending_now' => (int) (clone $pendingNow)->count(),
            'pending_over_15_minutes' => (int) $pendingOver15,
            'pending_over_60_minutes' => (int) $pendingOver60,
            'stuck_now' => (int) $stuckNow,
            'range_pending' => (int) $rangePending,
            'range_stuck' => (int) $rangeStuck,
            'top_errors' => $topErrors,
            'range_start' => $start->toDateTimeString(),
            'range_end' => $end->toDateTimeString(),
        ];
    }

    /**
     * @return array{0:string,1:Carbon,2:Carbon,3:string,4:string}
     */
    protected function resolveWindow(Request $request): array
    {
        $range = strtolower((string) $request->query('range', 'today'));
        $allowedRanges = ['today', '7d', '30d', 'this_week', 'this_month', 'custom'];
        if (! in_array($range, $allowedRanges, true)) {
            $range = 'today';
        }

        $groupBy = strtolower((string) $request->query('group_by', 'day'));
        if (! in_array($groupBy, ['day', 'week'], true)) {
            $groupBy = 'day';
        }

        $tab = strtolower((string) $request->query('tab', 'overview'));
        if (! in_array($tab, ['overview', 'services', 'vendors', 'reliability'], true)) {
            $tab = 'overview';
        }

        $end = now()->endOfDay();

        try {
            if ($range === 'today') {
                $start = now()->startOfDay();
            } elseif ($range === '7d') {
                $start = now()->subDays(6)->startOfDay();
            } elseif ($range === 'this_week') {
                $start = now()->startOfWeek(Carbon::MONDAY);
            } elseif ($range === 'this_month') {
                $start = now()->startOfMonth();
            } elseif ($range === 'custom') {
                $startInput = (string) $request->query('start_date', now()->subDays(29)->toDateString());
                $endInput = (string) $request->query('end_date', now()->toDateString());
                $start = Carbon::parse($startInput)->startOfDay();
                $end = Carbon::parse($endInput)->endOfDay();

                if ($start->gt($end)) {
                    [$start, $end] = [$end->copy()->startOfDay(), $start->copy()->endOfDay()];
                }

                if ($start->diffInDays($end) > 366) {
                    $start = $end->copy()->subDays(366)->startOfDay();
                }
            } else {
                $start = now()->subDays(29)->startOfDay();
            }
        } catch (\Throwable) {
            $range = 'today';
            $start = now()->startOfDay();
            $end = now()->endOfDay();
        }

        return [$range, $start, $end, $groupBy, $tab];
    }
}
