<?php

namespace App\Http\Controllers\Training;

use App\Http\Controllers\Controller;
use App\Models\TrainingPackage;
use App\Models\TrainingRegistration;
use App\Models\TrainingCertificate;
use App\Models\TrainingSession;
use Illuminate\Http\Request;
use Illuminate\View\View;

/**
 * ReportController
 *
 * Handles training reports and analytics.
 *
 * @package App\Http\Controllers\Training
 */
class ReportController extends Controller
{
    /**
     * Display the reports dashboard.
     *
     * @return \Illuminate\View\View
     */
    public function index(): View
    {
        abort_unless(auth()->user()->can('view training reports'), 403);

        $overview = $this->getOverviewStatistics();

        return view('training.reports.index', compact('overview'));
    }

    /**
     * Display registration reports.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\View\View
     */
    public function registrations(Request $request): View
    {
        abort_unless(auth()->user()->can('view training reports'), 403);

        $dateFrom = $request->get('from', now()->startOfYear()->toDateString());
        $dateTo = $request->get('to', now()->endOfYear()->toDateString());

        // Registration trends
        $registrationTrends = TrainingRegistration::selectRaw('
                DATE_FORMAT(registration_date, "%Y-%m") as month,
                COUNT(*) as total,
                SUM(CASE WHEN status = "approved" THEN 1 ELSE 0 END) as approved,
                SUM(CASE WHEN status = "pending" THEN 1 ELSE 0 END) as pending,
                SUM(CASE WHEN status = "rejected" THEN 1 ELSE 0 END) as rejected,
                SUM(CASE WHEN status = "cancelled" THEN 1 ELSE 0 END) as cancelled
            ')
            ->whereBetween('registration_date', [$dateFrom, $dateTo])
            ->groupBy('month')
            ->orderBy('month')
            ->get();

        // Top packages by registration
        $topPackages = TrainingPackage::withCount(['registrations'])
            ->orderByDesc('registrations_count')
            ->limit(10)
            ->get();

        // Registration by source
        $registrationBySource = TrainingRegistration::selectRaw('
                registration_source,
                COUNT(*) as count
            ')
            ->whereBetween('registration_date', [$dateFrom, $dateTo])
            ->groupBy('registration_source')
            ->get();

        // Registration by category
        $registrationByCategory = TrainingPackage::selectRaw('
                training_categories.name as category_name,
                COUNT(training_registrations.id) as registration_count
            ')
            ->join('training_categories', 'training_packages.category_id', '=', 'training_categories.id')
            ->leftJoin('training_registrations', 'training_packages.id', '=', 'training_registrations.training_package_id')
            ->whereBetween('training_registrations.registration_date', [$dateFrom, $dateTo])
            ->groupBy('training_categories.id', 'training_categories.name')
            ->orderByDesc('registration_count')
            ->get();

        return view('training.reports.registrations', compact(
            'registrationTrends',
            'topPackages',
            'registrationBySource',
            'registrationByCategory',
            'dateFrom',
            'dateTo'
        ));
    }

    /**
     * Display completion reports.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\View\View
     */
    public function completion(Request $request): View
    {
        abort_unless(auth()->user()->can('view training reports'), 403);

        $dateFrom = $request->get('from', now()->startOfYear()->toDateString());
        $dateTo = $request->get('to', now()->endOfYear()->toDateString());

        // Completion rate overall
        $totalRegistrations = TrainingRegistration::whereIn('status', ['approved', 'completed'])
            ->whereBetween('registration_date', [$dateFrom, $dateTo])
            ->count();
        $completedRegistrations = TrainingRegistration::where('status', 'completed')
            ->whereBetween('registration_date', [$dateFrom, $dateTo])
            ->count();

        $completionRate = $totalRegistrations > 0
            ? round(($completedRegistrations / $totalRegistrations) * 100, 1)
            : 0;

        // Completion by package
        $completionByPackage = TrainingPackage::selectRaw('
                training_packages.id,
                training_packages.name,
                COUNT(training_registrations.id) as total_registrations,
                SUM(CASE WHEN training_registrations.status = "completed" THEN 1 ELSE 0 END) as completed
            ')
            ->leftJoin('training_registrations', function ($join) use ($dateFrom, $dateTo) {
                $join->on('training_packages.id', '=', 'training_registrations.training_package_id')
                    ->whereBetween('training_registrations.registration_date', [$dateFrom, $dateTo]);
            })
            ->groupBy('training_packages.id', 'training_packages.name')
            ->orderByDesc('total_registrations')
            ->get();

        // Certificate statistics
        $certificatesIssued = TrainingCertificate::whereBetween('issue_date', [$dateFrom, $dateTo])
            ->count();
        $certificatesRevoked = TrainingCertificate::where('is_revoked', true)
            ->whereBetween('revoked_at', [$dateFrom, $dateTo])
            ->count();

        // Average attendance
        $averageAttendance = TrainingRegistration::whereNotNull('attendance_percentage')
            ->whereBetween('registration_date', [$dateFrom, $dateTo])
            ->avg('attendance_percentage');

        // Average score
        $averageScore = TrainingRegistration::whereNotNull('score')
            ->whereBetween('registration_date', [$dateFrom, $dateTo])
            ->avg('score');

        return view('training.reports.completion', compact(
            'completionRate',
            'completionByPackage',
            'certificatesIssued',
            'certificatesRevoked',
            'averageAttendance',
            'averageScore',
            'dateFrom',
            'dateTo'
        ));
    }

    /**
     * Display revenue reports.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\View\View
     */
    public function revenue(Request $request): View
    {
        abort_unless(auth()->user()->can('view training reports'), 403);

        $dateFrom = $request->get('from', now()->startOfYear()->toDateString());
        $dateTo = $request->get('to', now()->endOfYear()->toDateString());

        // Revenue trends
        $revenueTrends = TrainingRegistration::selectRaw('
                DATE_FORMAT(payment_date, "%Y-%m") as month,
                SUM(amount_paid) as revenue,
                COUNT(*) as payments
            ')
            ->where('payment_status', 'completed')
            ->whereBetween('payment_date', [$dateFrom, $dateTo])
            ->groupBy('month')
            ->orderBy('month')
            ->get();

        // Revenue by package
        $revenueByPackage = TrainingPackage::selectRaw('
                training_packages.id,
                training_packages.name,
                training_packages.fee_amount,
                COUNT(training_registrations.id) as registrations,
                SUM(training_registrations.amount_paid) as total_revenue
            ')
            ->leftJoin('training_registrations', function ($join) use ($dateFrom, $dateTo) {
                $join->on('training_packages.id', '=', 'training_registrations.training_package_id')
                    ->where('training_registrations.payment_status', 'completed')
                    ->whereBetween('training_registrations.payment_date', [$dateFrom, $dateTo]);
            })
            ->where('training_packages.is_free', false)
            ->groupBy('training_packages.id', 'training_packages.name', 'training_packages.fee_amount')
            ->orderByDesc('total_revenue')
            ->get();

        // Total revenue
        $totalRevenue = TrainingRegistration::where('payment_status', 'completed')
            ->whereBetween('payment_date', [$dateFrom, $dateTo])
            ->sum('amount_paid');

        // Pending payments
        $pendingPayments = TrainingRegistration::where('payment_status', 'pending')
            ->whereBetween('registration_date', [$dateFrom, $dateTo])
            ->sum('amount_due');

        // Failed payments
        $failedPayments = TrainingRegistration::where('payment_status', 'failed')
            ->whereBetween('registration_date', [$dateFrom, $dateTo])
            ->count();

        return view('training.reports.revenue', compact(
            'revenueTrends',
            'revenueByPackage',
            'totalRevenue',
            'pendingPayments',
            'failedPayments',
            'dateFrom',
            'dateTo'
        ));
    }

    /**
     * Export a report.
     *
     * @param string $type
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
     */
    public function export(string $type)
    {
        abort_unless(auth()->user()->can('export training reports'), 403);

        $from = request('from', now()->startOfYear()->toDateString());
        $to = request('to', now()->endOfYear()->toDateString());

        $filename = "training_report_{$type}_" . now()->format('Y-m-d') . '.csv';

        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ];

        $callback = match ($type) {
            'registrations' => $this->exportRegistrations($from, $to),
            'completion' => $this->exportCompletion($from, $to),
            'revenue' => $this->exportRevenue($from, $to),
            default => $this->exportOverview(),
        };

        return response()->stream($callback, 200, $headers);
    }

    /**
     * Get overview statistics.
     *
     * @return array
     */
    protected function getOverviewStatistics(): array
    {
        return [
            'packages' => [
                'total' => TrainingPackage::count(),
                'active' => TrainingPackage::where('status', 'active')->count(),
                'free' => TrainingPackage::where('is_free', true)->count(),
                'paid' => TrainingPackage::where('is_free', false)->count(),
            ],
            'sessions' => [
                'total' => TrainingSession::count(),
                'upcoming' => TrainingSession::where('session_date', '>=', now()->toDateString())
                    ->where('status', 'scheduled')
                    ->count(),
                'completed' => TrainingSession::where('status', 'completed')->count(),
            ],
            'registrations' => [
                'total' => TrainingRegistration::count(),
                'pending' => TrainingRegistration::where('status', 'pending')->count(),
                'approved' => TrainingRegistration::where('status', 'approved')->count(),
                'completed' => TrainingRegistration::where('status', 'completed')->count(),
            ],
            'certificates' => [
                'total' => TrainingCertificate::count(),
                'valid' => TrainingCertificate::where('is_revoked', false)->count(),
                'revoked' => TrainingCertificate::where('is_revoked', true)->count(),
            ],
            'revenue' => [
                'total' => TrainingRegistration::where('payment_status', 'completed')
                    ->sum('amount_paid'),
                'pending' => TrainingRegistration::where('payment_status', 'pending')
                    ->sum('amount_due'),
                'this_month' => TrainingRegistration::where('payment_status', 'completed')
                    ->whereMonth('payment_date', now()->month)
                    ->sum('amount_paid'),
            ],
        ];
    }

    /**
     * Export registrations data.
     *
     * @param string $from
     * @param string $to
     * @return \Closure
     */
    protected function exportRegistrations(string $from, string $to): \Closure
    {
        return function () use ($from, $to) {
            $file = fopen('php://output', 'w');

            fputcsv($file, ['Date', 'Participant', 'Email', 'Package', 'Status', 'Payment Status', 'Amount']);

            TrainingRegistration::with(['user', 'trainingPackage'])
                ->whereBetween('registration_date', [$from, $to])
                ->chunk(100, function ($registrations) use ($file) {
                    foreach ($registrations as $reg) {
                        fputcsv($file, [
                            $reg->registration_date->format('Y-m-d'),
                            $reg->user->name,
                            $reg->user->email,
                            $reg->trainingPackage->name,
                            ucfirst($reg->status),
                            ucfirst($reg->payment_status),
                            $reg->amount_paid ?? 0,
                        ]);
                    }
                });

            fclose($file);
        };
    }

    /**
     * Export completion data.
     *
     * @param string $from
     * @param string $to
     * @return \Closure
     */
    protected function exportCompletion(string $from, string $to): \Closure
    {
        return function () use ($from, $to) {
            $file = fopen('php://output', 'w');

            fputcsv($file, ['Participant', 'Package', 'Status', 'Attendance %', 'Score', 'Certificate Issued']);

            TrainingRegistration::with(['user', 'trainingPackage'])
                ->whereBetween('registration_date', [$from, $to])
                ->chunk(100, function ($registrations) use ($file) {
                    foreach ($registrations as $reg) {
                        fputcsv($file, [
                            $reg->user->name,
                            $reg->trainingPackage->name,
                            ucfirst($reg->status),
                            $reg->attendance_percentage ?? 'N/A',
                            $reg->score ?? 'N/A',
                            $reg->certificate_issued ? 'Yes' : 'No',
                        ]);
                    }
                });

            fclose($file);
        };
    }

    /**
     * Export revenue data.
     *
     * @param string $from
     * @param string $to
     * @return \Closure
     */
    protected function exportRevenue(string $from, string $to): \Closure
    {
        return function () use ($from, $to) {
            $file = fopen('php://output', 'w');

            fputcsv($file, ['Date', 'Participant', 'Package', 'Amount', 'Payment Method', 'Reference', 'Status']);

            TrainingRegistration::with(['user', 'trainingPackage'])
                ->whereNotNull('amount_paid')
                ->whereBetween('payment_date', [$from, $to])
                ->chunk(100, function ($registrations) use ($file) {
                    foreach ($registrations as $reg) {
                        fputcsv($file, [
                            $reg->payment_date?->format('Y-m-d'),
                            $reg->user->name,
                            $reg->trainingPackage->name,
                            $reg->amount_paid,
                            $reg->payment_method,
                            $reg->payment_reference,
                            ucfirst($reg->payment_status),
                        ]);
                    }
                });

            fclose($file);
        };
    }

    /**
     * Export overview data.
     *
     * @return \Closure
     */
    protected function exportOverview(): \Closure
    {
        return function () {
            $file = fopen('php://output', 'w');
            $stats = $this->getOverviewStatistics();

            foreach ($stats as $category => $values) {
                fputcsv($file, [strtoupper($category)]);
                foreach ($values as $key => $value) {
                    fputcsv($file, ['  ' . $key, $value]);
                }
                fputcsv($file, []);
            }

            fclose($file);
        };
    }
}
