<?php

namespace App\Http\Controllers\Training;

use App\Http\Controllers\Controller;
use App\Models\TrainingPackage;
use App\Models\TrainingRegistration;
use App\Models\TrainingSession;
use App\Services\RegistrationService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\View\View;

/**
 * PublicController
 *
 * Handles public-facing training pages and application forms.
 *
 * @package App\Http\Controllers\Training
 */
class PublicController extends Controller
{
    /**
     * RegistrationService instance.
     *
     * @var \App\Services\RegistrationService
     */
    protected RegistrationService $registrationService;

    /**
     * Create a new PublicController instance.
     *
     * @param \App\Services\RegistrationService $registrationService
     */
    public function __construct(RegistrationService $registrationService)
    {
        $this->registrationService = $registrationService;
    }

    /**
     * Display the public training programs page.
     *
     * @return \Illuminate\View\View
     */
    public function index(): View
    {
        // Get active public training packages
        $packages = TrainingPackage::with(['category'])
            ->active()
            ->public()
            ->withCount(['sessions', 'registrations'])
            ->when(request('category'), function ($query, $categoryId) {
                $query->where('category_id', $categoryId);
            })
            ->when(request('search'), function ($query, $search) {
                $query->where(function ($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                      ->orWhere('description', 'like', "%{$search}%");
                });
            })
            ->orderBy('created_at', 'desc')
            ->paginate(12);
        
        // Get upcoming sessions for each package
        $packageIds = $packages->pluck('id');
        $upcomingSessions = \App\Models\TrainingSession::whereIn('training_package_id', $packageIds)
            ->where('session_date', '>=', now()->toDateString())
            ->where('status', 'scheduled')
            ->orderBy('session_date')
            ->orderBy('start_time')
            ->get()
            ->groupBy('training_package_id');
        
        // Get all training categories for filter dropdown
        $categories = \App\Models\TrainingCategory::orderBy('name')->get();
        
        // Calculate statistics
        $statistics = [
            'total_programs' => TrainingPackage::active()->public()->count(),
            'total_sessions' => \App\Models\TrainingSession::where('session_date', '>=', now()->toDateString())
                ->where('status', 'scheduled')
                ->count(),
            'total_participants' => \App\Models\TrainingRegistration::whereHas('package', function ($query) {
                $query->active()->public();
            })->where('status', 'approved')->count(),
            'certificates_issued' => \App\Models\TrainingCertificate::count(),
        ];
        
        return view('public.training.index', compact('packages', 'upcomingSessions', 'categories', 'statistics'));
    }

    /**
     * Display a specific training program.
     *
     * @param \App\Models\TrainingPackage $package
     * @return \Illuminate\View\View
     */
    public function show(TrainingPackage $package): View
    {
        if (!$package->is_public || !$package->isActive()) {
            abort(404);
        }
        
        $package->load([
            'category',
            'sessions' => function ($query) {
                $query->where('session_date', '>=', now()->toDateString())
                    ->orderBy('session_date')
                    ->orderBy('start_time');
            },
        ]);
        
        return view('public.training.show', compact('package'));
    }

    /**
     * Show the application form for a training program.
     *
     * @param \App\Models\TrainingPackage $package
     * @return \Illuminate\View\View
     */
    public function apply(TrainingPackage $package): View
    {
        if (!$package->is_public || !$package->isActive()) {
            abort(404);
        }
        
        if (!$package->hasCapacity()) {
            return view('public.training.fully-booked', compact('package'));
        }
        
        $package->load(['sessions']);
        
        return view('public.training.apply', compact('package'));
    }

    /**
     * Submit an application for training.
     *
     * @param \Illuminate\Http\Request $request
     * @param \App\Models\TrainingPackage $package
     * @return \Illuminate\Http\RedirectResponse
     */
    public function submitApplication(Request $request, TrainingPackage $package)
    {
        if (!$package->is_public || !$package->isActive()) {
            abort(404);
        }
        
        // Validate request
        $validated = $request->validate([
            'name' => 'required|string|max:191',
            'email' => 'required|email|max:191',
            'phone' => 'required|string|max:20',
            'organization' => 'nullable|string|max:191',
            'position' => 'nullable|string|max:191',
            'notes' => 'nullable|string|max:1000',
        ], [
            'name.required' => 'Please enter your full name.',
            'email.required' => 'Please enter your email address.',
            'email.email' => 'Please enter a valid email address.',
            'phone.required' => 'Please enter your phone number.',
        ]);
        
        // Check capacity again
        if (!$package->hasCapacity()) {
            return back()->with('error', 'Sorry, this training is now fully booked.');
        }
        
        try {
            // Find or create user
            $user = $this->findOrCreateUser($validated);
            
            // Register user for the package
            $result = $this->registrationService->registerUser($user, $package, [
                'source' => 'public',
                'notes' => $validated['notes'] ?? null,
                'metadata' => [
                    'organization' => $validated['organization'] ?? null,
                    'position' => $validated['position'] ?? null,
                ],
            ]);
            
            if (!$result['success']) {
                return back()->with('error', $result['message'])->withInput();
            }
            
            $registration = $result['registration'];
            
            // If payment is required, redirect to the dedicated payment page
            // where the user can choose Mobile Money or Bank Card
            if ($package->requiresPayment()) {
                return redirect()
                    ->route('public.training.payment', [$package, $registration])
                    ->with('info', 'Registration submitted! Please complete payment to confirm your place.');
            }
            
            // Free or approval-only — go to confirmation
            if ($package->is_free && !$package->requires_approval) {
                return redirect()
                    ->route('public.training.confirmation', [$package, $registration])
                    ->with('success', 'Your registration has been confirmed!');
            }
            
            return redirect()
                ->route('public.training.confirmation', [$package, $registration])
                ->with('success', 'Your application has been submitted successfully!');
                
        } catch (\Exception $e) {
            return back()
                ->with('error', 'An error occurred. Please try again.')
                ->withInput();
        }
    }

    /**
     * Show payment page.
     *
     * @param \App\Models\TrainingPackage $package
     * @param \App\Models\TrainingRegistration $registration
     * @return \Illuminate\View\View
     */
    public function payment(TrainingPackage $package, TrainingRegistration $registration): View
    {
        if ($registration->training_package_id !== $package->id) {
            abort(404);
        }
        
        if ($registration->payment_status === 'completed') {
            return view('public.training.payment-completed', compact('package', 'registration'));
        }
        
        return view('public.training.payment', compact('package', 'registration'));
    }

    /**
     * Process payment for registration.
     *
     * @param \Illuminate\Http\Request $request
     * @param \App\Models\TrainingPackage $package
     * @param \App\Models\TrainingRegistration $registration
     * @return \Illuminate\Http\RedirectResponse
     */
    public function processPayment(Request $request, TrainingPackage $package, TrainingRegistration $registration)
    {
        if ($registration->training_package_id !== $package->id) {
            abort(404);
        }

        $paymentMethod = $request->input('payment_method', 'mobile');

        $rules = ['payment_method' => 'nullable|in:mobile,card'];
        if ($paymentMethod === 'card') {
            $rules['card_number'] = 'required|string';
            $rules['card_expiry'] = ['required', 'regex:/^(0[1-9]|1[0-2])\/\d{2}$/'];
            $rules['card_cvv']    = 'required|digits_between:3,4';
        } else {
            // payment-method-toggle submits 'phone_number'
            $rules['phone_number'] = 'required|string|max:20';
        }

        $validated = $request->validate($rules);

        $result = $this->registrationService->processPayment(
            registration: $registration,
            phoneNumber: $validated['phone_number'] ?? '',
            paymentMethod: $paymentMethod,
            cardNumber: $validated['card_number'] ?? null,
            cardExpiry: $validated['card_expiry'] ?? null,
            cardCvv: $validated['card_cvv'] ?? null,
        );

        if ($result['success']) {
            return back()->with('info', $result['message']);
        }

        return back()->with('error', $result['message']);
    }

    /**
     * Show confirmation page.
     *
     * @param \App\Models\TrainingPackage $package
     * @param \App\Models\TrainingRegistration $registration
     * @return \Illuminate\View\View
     */
    public function confirmation(TrainingPackage $package, TrainingRegistration $registration): View
    {
        if ($registration->training_package_id !== $package->id) {
            abort(404);
        }
        
        return view('public.training.confirmation', compact('package', 'registration'));
    }

    /**
     * Show the certificate verification form page.
     *
     * @return \Illuminate\View\View
     */
    public function verifyCertificatePage(): View
    {
        return view('public.training.certificate-verify-page');
    }

    /**
     * Verify a certificate.
     *
     * @param string $code
     * @return \Illuminate\View\View
     */
    public function verifyCertificate(string $code): View
    {
        $certificate = \App\Models\TrainingCertificate::where('verification_code', $code)->first();
        
        if (!$certificate) {
            return view('public.training.certificate-not-found');
        }
        
        // Record verification
        $certificate->recordVerification();
        
        return view('public.training.certificate-verify', compact('certificate'));
    }

    /**
     * Find or create user based on application data.
     * When a new account is created, sends a welcome/credentials email.
     *
     * @param array $data
     * @return \App\Models\User
     */
    protected function findOrCreateUser(array $data): \App\Models\User
    {
        // Try to find existing user by email
        $user = \App\Models\User::where('email', $data['email'])->first();

        if ($user) {
            // Update phone if provided and different
            if (!empty($data['phone']) && $user->phone !== $data['phone']) {
                $user->update(['phone' => $data['phone']]);
            }
            return $user;
        }

        // Generate a temporary password for the new account
        $temporaryPassword = \Str::random(12);

        // Create new user account
        $user = \App\Models\User::create([
            'name'              => strip_tags($data['name']),
            'email'             => $data['email'],
            'username'          => \App\Models\User::generateUsername($data['email']),
            'phone'             => $data['phone'] ?? null,
            'password'          => bcrypt($temporaryPassword),
            'email_verified_at' => now(),
            'is_active'         => true,
        ]);

        // Assign default trainee role
        $user->assignRole('Trainees');

        // Send welcome email with login credentials
        try {
            \Illuminate\Support\Facades\Mail::send(
                'emails.training.welcome-new-user',
                [
                    'user'              => $user,
                    'temporaryPassword' => $temporaryPassword,
                    'loginUrl'          => route('login'),
                    'resetUrl'          => route('password.request'),
                ],
                function ($message) use ($user) {
                    $message->to($user->email, $user->name)
                            ->subject('Your ' . config('app.name') . ' Account Has Been Created');
                }
            );
        } catch (\Throwable $e) {
            \Illuminate\Support\Facades\Log::error('Failed to send welcome email to new training applicant', [
                'user_id' => $user->id,
                'email'   => $user->email,
                'error'   => $e->getMessage(),
            ]);
            // Do NOT rethrow — account creation succeeded; email failure is non-fatal
        }

        return $user;
    }
}
