<?php

namespace App\Livewire\Reports;

use App\Domain\Shared\Services\ReportService;
use App\Domain\Shared\Traits\UsesBranchScope;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('عرض التقرير')]
class ReportViewer extends Component
{
    use UsesBranchScope;

    /**
     * Reports that read every branch by definition.
     *
     * Comparing branches to each other is the whole point of these, so the
     * branch scope has to come off — but only for the one call, and only for a
     * user entitled to the cross-branch view. ReportsHub reads this list too,
     * so the card and the page cannot drift apart.
     */
    public const CROSS_BRANCH_REPORTS = ['branch_comparison'];

    #[Url]
    public string $report = '';

    #[Url]
    public string $from = '';

    #[Url]
    public string $to = '';

    #[Url]
    public int $minAbsences = 1;

    public function mount(string $report = ''): void
    {
        $this->authorize('reports.view');
        $this->report = $report ?: request('report', '');
        $this->from = request('from', now()->startOfMonth()->format('Y-m-d'));
        $this->to = request('to', now()->format('Y-m-d'));

        $this->resolveConfig();
    }

    public function getReportConfig(): array
    {
        return [
            'daily_revenue' => [
                'name' => 'الإيرادات اليومية',
                'method' => 'dailyRevenue',
                'headers' => ['التاريخ', 'المبلغ', 'عدد العمليات'],
                'columns' => ['date', 'total', 'count'],
                'money_cols' => ['total'],
                'uses_dates' => true,
            ],
            'outstanding_balances' => [
                'name' => 'الأرصدة المعلقة',
                'method' => 'outstandingBalances',
                'headers' => ['رقم الفاتورة', 'المشترك', 'الهاتف', 'الإجمالي', 'المدفوع', 'المستحق', 'الحالة', 'تاريخ الاستحقاق', 'أيام التأخير'],
                'columns' => ['invoice_number', 'participant', 'phone', 'total', 'paid', 'due', 'status', 'due_date', 'days_overdue'],
                'money_cols' => ['total', 'paid', 'due'],
                'uses_dates' => true,
            ],
            'payment_methods' => [
                'name' => 'طرق الدفع',
                'method' => 'paymentMethodBreakdown',
                'headers' => ['طريقة الدفع', 'المبلغ', 'عدد العمليات'],
                'columns' => ['method', 'total', 'count'],
                'money_cols' => ['total'],
                'uses_dates' => true,
            ],
            'refunds' => [
                'name' => 'المرتجعات',
                'method' => 'refundReport',
                'headers' => ['التاريخ', 'المشترك', 'المبلغ', 'الطريقة', 'الفاتورة', 'بواسطة', 'المرجع'],
                'columns' => ['date', 'participant', 'amount', 'method', 'invoice', 'processed_by', 'reference'],
                'money_cols' => ['amount'],
                'uses_dates' => true,
            ],
            'installments_due' => [
                'name' => 'الأقساط المستحقة',
                'method' => 'installmentsDue',
                'headers' => ['المشترك', 'الهاتف', 'المبلغ', 'المدفوع', 'تاريخ الاستحقاق', 'الحالة', 'الفاتورة'],
                'columns' => ['participant', 'phone', 'amount', 'paid', 'due_date', 'status', 'invoice'],
                'money_cols' => ['amount', 'paid'],
                'uses_dates' => true,
            ],
            'cash_sessions' => [
                'name' => 'ملخص الورديات',
                'method' => 'cashSessionSummary',
                'headers' => ['الموظف', 'الفرع', 'الفتح', 'الإغلاق', 'رصيد الافتتاح', 'الوارد', 'الصادر', 'المتوقع', 'الفعلي', 'الفرق', 'الحالة'],
                'columns' => ['user', 'branch', 'opened_at', 'closed_at', 'opening_balance', 'cash_in', 'cash_out', 'expected_balance', 'actual_balance', 'variance', 'status'],
                'money_cols' => ['opening_balance', 'cash_in', 'cash_out', 'expected_balance', 'actual_balance', 'variance'],
                'uses_dates' => true,
            ],
            'overdue_aging' => [
                'name' => 'تقادم الفواتير',
                'method' => 'overdueInvoicesAging',
                'headers' => ['الفاتورة', 'المشترك', 'الهاتف', 'الإجمالي', 'المستحق', 'تاريخ الاستحقاق', 'أيام التأخير', 'الفئة'],
                'columns' => ['invoice', 'participant', 'phone', 'total', 'due', 'due_date', 'days_overdue', 'aging_bucket'],
                'money_cols' => ['total', 'due'],
                'uses_dates' => false,
            ],
            'revenue_by_activity' => [
                'name' => 'الإيرادات حسب النشاط',
                'method' => 'revenueByActivity',
                'headers' => ['النشاط', 'الإيرادات', 'عدد الفواتير'],
                'columns' => ['activity', 'revenue', 'invoices_count'],
                'money_cols' => ['revenue'],
                'uses_dates' => true,
            ],
            'new_registrations' => [
                'name' => 'التسجيلات الجديدة',
                'method' => 'newRegistrations',
                'headers' => ['الاسم', 'الهاتف', 'العمر', 'الجنس', 'النشاط', 'الفرع', 'المصدر', 'التاريخ', 'الحالة'],
                'columns' => ['name', 'phone', 'age', 'gender', 'activity', 'branch', 'source', 'date', 'status'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'by_status' => [
                'name' => 'المشتركون حسب الحالة',
                'method' => 'participantsByStatus',
                'headers' => ['الحالة', 'العدد'],
                'columns' => ['status', 'count'],
                'money_cols' => [],
                'uses_dates' => false,
            ],
            'by_age' => [
                'name' => 'المشتركون حسب الفئة العمرية',
                'method' => 'participantsByAge',
                'headers' => ['الفئة العمرية', 'العدد'],
                'columns' => ['range', 'count'],
                'money_cols' => [],
                'uses_dates' => false,
            ],
            'by_gender' => [
                'name' => 'المشتركون حسب الجنس',
                'method' => 'participantsByGender',
                'headers' => ['الجنس', 'العدد'],
                'columns' => ['gender', 'count'],
                'money_cols' => [],
                'uses_dates' => false,
            ],
            'expired_memberships' => [
                'name' => 'العضويات المنتهية',
                'method' => 'expiredMemberships',
                'headers' => ['الاسم', 'الهاتف', 'رقم العضوية', 'تاريخ الانتهاء', 'الحالة', 'الفرع', 'الأيام'],
                'columns' => ['name', 'phone', 'membership_id', 'expires_at', 'status', 'branch', 'days_until'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'without_medical_clearance' => [
                'name' => 'مشتركون بدون شهادة طبية',
                'method' => 'withoutMedicalClearance',
                'headers' => ['الاسم', 'الهاتف', 'الحالة', 'الفرع', 'تاريخ التسجيل', 'انتهاء الشهادة'],
                'columns' => ['name', 'phone', 'status', 'branch', 'registration_date', 'clearance_expires'],
                'money_cols' => [],
                'uses_dates' => false,
            ],
            'frozen_suspended' => [
                'name' => 'المجمدون والموقوفون',
                'method' => 'frozenAndSuspended',
                'headers' => ['الاسم', 'الهاتف', 'الحالة', 'السبب', 'منذ', 'الفرع', 'الرصيد المعلق'],
                'columns' => ['name', 'phone', 'status', 'reason', 'since', 'branch', 'balance'],
                'money_cols' => ['balance'],
                'uses_dates' => false,
            ],
            'attendance_by_group' => [
                'name' => 'الحضور حسب المجموعة',
                'method' => 'attendanceByGroup',
                'headers' => ['المجموعة', 'البرنامج', 'إجمالي السجلات', 'حاضر', 'غائب', 'النسبة %'],
                'columns' => ['group', 'program', 'total_records', 'present', 'absent', 'rate'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'absentees' => [
                'name' => 'أكثر الغائبين',
                'method' => 'absenteeReport',
                'headers' => ['الاسم', 'الهاتف', 'مرات الغياب', 'المجموعات', 'آخر غياب'],
                'columns' => ['name', 'phone', 'absent_count', 'groups', 'last_absence'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'absent_by_trainer' => [
                'name' => 'المتغيبون حسب المدرب',
                'method' => 'absentParticipantsByTrainer',
                'headers' => ['الاسم', 'الهاتف', 'عدد الغيابات', 'المجموعة', 'المدرب', 'آخر غياب'],
                'columns' => ['name', 'phone', 'absent_count', 'group', 'trainer', 'last_absence'],
                'money_cols' => [],
                'uses_dates' => true,
                'has_min_absences_filter' => true,
            ],
            'trainer_attendance' => [
                'name' => 'حضور المدربين',
                'method' => 'trainerAttendance',
                'headers' => ['المدرب', 'الهاتف', 'إجمالي الحصص', 'حضر', 'غاب', 'النسبة %'],
                'columns' => ['name', 'phone', 'total_sessions', 'attended', 'absent', 'rate'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'enrollments_by_program' => [
                'name' => 'التسجيلات حسب البرنامج',
                'method' => 'enrollmentsByProgram',
                'headers' => ['البرنامج', 'عدد المسجلين', 'الحالة'],
                'columns' => ['program', 'enrollments', 'status'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'group_capacity' => [
                'name' => 'نسبة امتلاء المجموعات',
                'method' => 'groupCapacity',
                'headers' => ['المجموعة', 'البرنامج', 'الفرع', 'الحالي', 'الأقصى', 'النسبة %', 'المتاح'],
                'columns' => ['group', 'program', 'branch', 'current', 'max', 'fill_rate', 'available'],
                'money_cols' => [],
                'uses_dates' => false,
            ],
            'cancellations' => [
                'name' => 'الإلغاءات',
                'method' => 'cancellationsReport',
                'headers' => ['المشترك', 'الهاتف', 'البرنامج', 'المجموعة', 'تاريخ التسجيل', 'تاريخ الإلغاء', 'السبب'],
                'columns' => ['participant', 'phone', 'program', 'group', 'enrolled_at', 'cancelled_at', 'reason'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'retention' => [
                'name' => 'الاستمرارية',
                'method' => 'retentionReport',
                'headers' => ['المؤشر', 'القيمة'],
                'columns' => ['metric', 'value'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'session_completion' => [
                'name' => 'الحصص المنجزة',
                'method' => 'sessionCompletionReport',
                'headers' => ['الحالة', 'العدد'],
                'columns' => ['status', 'count'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'branch_comparison' => [
                'name' => 'مقارنة الفروع',
                'method' => 'branchComparison',
                'headers' => ['الفرع', 'مشتركون نشطون', 'الإيرادات', 'تسجيلات جديدة'],
                'columns' => ['branch', 'active_participants', 'revenue', 'new_enrollments'],
                'money_cols' => ['revenue'],
                'uses_dates' => true,
                // Cross-branch by definition, so it is gated on the same
                // permission as the every-branch view and its query runs with
                // the scope explicitly lifted. See CROSS_BRANCH_REPORTS.
                'cross_branch' => true,
                'permission' => config('branch_lock.permission'),
            ],
            'trainer_workload' => [
                'name' => 'عبء المدربين',
                'method' => 'trainerWorkload',
                'headers' => ['المدرب', 'الهاتف', 'إجمالي الحصص', 'مكتملة', 'ملغاة', 'عدد المجموعات'],
                'columns' => ['name', 'phone', 'total_sessions', 'completed', 'cancelled', 'groups_count'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'wallet_balances' => [
                'name' => 'أرصدة المحافظ',
                'method' => 'walletBalances',
                'headers' => ['المشترك', 'الهاتف', 'الرصيد', 'المجمد', 'المتاح', 'آخر حركة'],
                'columns' => ['participant', 'phone', 'balance', 'frozen', 'available', 'last_transaction'],
                'money_cols' => ['balance', 'frozen', 'available'],
                'uses_dates' => false,
            ],
            'low_stock' => [
                'name' => 'المنتجات المنخفضة',
                'method' => 'lowStockReport',
                'headers' => ['المنتج', 'SKU', 'التصنيف', 'الكمية', 'حد إعادة الطلب', 'الحالة'],
                'columns' => ['product', 'sku', 'category', 'on_hand', 'reorder_point', 'status'],
                'money_cols' => [],
                'uses_dates' => false,
            ],
            'inventory_movements' => [
                'name' => 'حركات المخزون',
                'method' => 'inventoryMovementReport',
                'headers' => ['التاريخ', 'المنتج', 'المستودع', 'النوع', 'الاتجاه', 'الكمية', 'قبل', 'بعد', 'المرجع'],
                'columns' => ['date', 'product', 'warehouse', 'type', 'direction', 'quantity', 'before', 'after', 'reference'],
                'money_cols' => [],
                'uses_dates' => true,
            ],
            'product_sales' => [
                'name' => 'مبيعات المنتجات',
                'method' => 'productSalesReport',
                'headers' => ['المنتج', 'SKU', 'الكمية المباعة', 'الإيرادات'],
                'columns' => ['product', 'sku', 'units_sold', 'revenue'],
                'money_cols' => ['revenue'],
                'uses_dates' => true,
            ],
            'pos_transactions' => [
                'name' => 'عمليات نقاط البيع',
                'method' => 'posTransactionReport',
                'headers' => ['التاريخ', 'الرقم', 'الإجمالي', 'الخصم', 'عدد الأصناف', 'طريقة الدفع', 'الكاشير', 'الفرع'],
                'columns' => ['date', 'number', 'total', 'discount', 'items_count', 'payment_method', 'cashier', 'branch'],
                'money_cols' => ['total', 'discount'],
                'uses_dates' => true,
            ],
            'pos_daily_summary' => [
                'name' => 'ملخص POS اليومي',
                'method' => 'posDailySummary',
                'headers' => ['التاريخ', 'الإجمالي', 'الخصومات', 'عدد العمليات'],
                'columns' => ['date', 'total', 'discounts', 'transactions'],
                'money_cols' => ['total', 'discounts'],
                'uses_dates' => true,
            ],
            'expense_summary' => [
                'name' => 'تقرير المصروفات',
                'method' => 'expenseSummary',
                'headers' => ['التاريخ', 'الفئة', 'الوصف', 'المبلغ', 'المستلم', 'طريقة الدفع', 'بواسطة'],
                'columns' => ['date', 'category', 'description', 'amount', 'recipient', 'payment_method', 'created_by'],
                'money_cols' => ['amount'],
                'uses_dates' => true,
            ],
            'facility_rent_summary' => [
                'name' => 'تقرير إيجارات المنشآت',
                'method' => 'facilityRentSummary',
                'headers' => ['المنشأة', 'الشهر', 'المبلغ', 'طريقة الدفع', 'رقم الشيك', 'تاريخ الدفع', 'بواسطة'],
                'columns' => ['facility', 'period', 'amount', 'payment_method', 'cheque_number', 'payment_date', 'created_by'],
                'money_cols' => ['amount'],
                'uses_dates' => true,
            ],
        ];
    }

    /**
     * The config of the report being viewed, once it is known to exist and the
     * user is known to be allowed it.
     *
     * `$report` is a public Livewire property, so the browser can change it on
     * every round-trip — the check in mount() only covers the first request.
     * This runs again in render(), where the query is actually built.
     */
    protected function resolveConfig(): array
    {
        $config = $this->getReportConfig()[$this->report] ?? null;

        if (! $config) {
            abort(404);
        }

        if (! empty($config['permission'])) {
            $this->authorize($config['permission']);
        }

        return $config;
    }

    public function render(ReportService $reportService)
    {
        $config = $this->resolveConfig();
        $branchId = $this->getActiveBranchId();

        $method = $config['method'];
        $usesDates = $config['uses_dates'] ?? true;

        if (! empty($config['cross_branch'])) {
            // A deliberate hole in the isolation, narrowed to this one call:
            // branchComparison() reports on every branch and takes no branch
            // argument, and without lifting the scope its per-branch revenue
            // and enrolment queries would return zero for every branch but the
            // selected one. The permission was checked in resolveConfig().
            $from = $this->from ?: now()->startOfMonth()->format('Y-m-d');
            $to = $this->to ?: now()->format('Y-m-d');

            $data = $this->acrossBranches(fn () => $reportService->$method($from, $to));
        } elseif ($usesDates) {
            $from = $this->from ?: now()->startOfMonth()->format('Y-m-d');
            $to = $this->to ?: now()->format('Y-m-d');
            if ($method === 'absentParticipantsByTrainer') {
                $data = $reportService->$method($from, $to, $branchId, $this->minAbsences);
            } else {
                $data = $reportService->$method($from, $to, $branchId);
            }
        } else {
            $data = $reportService->$method($branchId);
        }

        return view('livewire.reports.report-viewer', [
            'config' => $config,
            'data' => $data,
            'exportUrl' => route('export.report', ['report' => $this->report, 'from' => $this->from, 'to' => $this->to]),
        ]);
    }
}
