<?php

namespace App\Services\Mentorship;

use App\Models\Mentorship\Application;
use App\Models\Mentorship\Programme;
use App\Models\User;
use App\Services\EmailService;
use App\Services\SMSService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class RegistrationService
{
    protected EmailService $emailService;
    protected SMSService $smsService;

    public function __construct(EmailService $emailService, SMSService $smsService)
    {
        $this->emailService = $emailService;
        $this->smsService = $smsService;
    }

    /**
     * Submit a new application.
     */
    public function submitApplication(array $data): Application
    {
        DB::beginTransaction();
        
        try {
            $programme = Programme::findOrFail($data['programme_id']);

            // Set payment information if not free
            $data['payment_required'] = !$programme->is_free;
            $data['payment_amount'] = $programme->fee_amount;
            $data['payment_currency'] = $programme->currency;

            // Set consent timestamp
            if (($data['terms_accepted'] ?? false) && ($data['privacy_accepted'] ?? false)) {
                $data['consent_at'] = now();
            }

            // Set initial status
            $data['status'] = $data['payment_required'] ? 'payment_pending' : 'pending';

            $application = Application::create($data);

            DB::commit();

            // Send confirmation notification
            $this->sendConfirmationNotification($application);

            Log::info('Mentorship application submitted', [
                'application_id' => $application->id,
                'programme_id' => $application->programme_id,
                'email' => $application->email,
                'role_preference' => $application->role_preference,
            ]);

            return $application;
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to submit mentorship application', [
                'error' => $e->getMessage(),
                'data' => $data,
            ]);
            throw $e;
        }
    }

    /**
     * Approve an application.
     */
    public function approve(Application $application, int $reviewerId, ?string $notes = null): Application
    {
        DB::beginTransaction();
        
        try {
            // Check if payment is required and completed
            if ($application->requiresPayment()) {
                throw new \Exception('Cannot approve application with pending payment.');
            }

            // Approve the application
            $application->approve($reviewerId, $notes);

            // Create user account if not exists
            $user = $this->createOrUpdateUser($application);

            // Update application with user ID
            $application->update(['user_id' => $user->id]);

            // Assign role
            $this->assignRole($user, $application->role_preference);

            DB::commit();

            // Send approval notification
            $this->sendApprovalNotification($application, $user);

            Log::info('Mentorship application approved', [
                'application_id' => $application->id,
                'user_id' => $user->id,
                'role' => $application->role_preference,
                'reviewer_id' => $reviewerId,
            ]);

            return $application->fresh();
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to approve mentorship application', [
                'error' => $e->getMessage(),
                'application_id' => $application->id,
            ]);
            throw $e;
        }
    }

    /**
     * Reject an application.
     */
    public function reject(Application $application, int $reviewerId, string $reason, ?string $notes = null): Application
    {
        DB::beginTransaction();
        
        try {
            $application->reject($reviewerId, $reason, $notes);

            DB::commit();

            // Send rejection notification
            $this->sendRejectionNotification($application);

            Log::info('Mentorship application rejected', [
                'application_id' => $application->id,
                'reason' => $reason,
                'reviewer_id' => $reviewerId,
            ]);

            return $application->fresh();
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to reject mentorship application', [
                'error' => $e->getMessage(),
                'application_id' => $application->id,
            ]);
            throw $e;
        }
    }

    /**
     * Put application under review.
     */
    public function markUnderReview(Application $application, int $reviewerId): Application
    {
        $application->markAsUnderReview($reviewerId);

        Log::info('Mentorship application marked under review', [
            'application_id' => $application->id,
            'reviewer_id' => $reviewerId,
        ]);

        return $application->fresh();
    }

    /**
     * Withdraw an application.
     */
    public function withdraw(Application $application): Application
    {
        if (!in_array($application->status, ['pending', 'under_review', 'payment_pending'])) {
            throw new \Exception('Cannot withdraw application in current status.');
        }

        $application->withdraw();

        Log::info('Mentorship application withdrawn', [
            'application_id' => $application->id,
        ]);

        return $application->fresh();
    }

    /**
     * Get applications with filtering.
     *
     * @param  array       $filters
     * @param  int|null    $userId  When provided, scope results to this user's own applications only.
     * @param  int         $perPage
     */
    public function getApplications(array $filters = [], ?int $userId = null, int $perPage = 15)
    {
        $query = Application::with(['programme', 'category', 'user', 'reviewer']);

        // Scope to a specific user's own applications (Mentor / Mentee self-view)
        if ($userId !== null) {
            $query->where('user_id', $userId);
        }

        // Filter by status
        if (!empty($filters['status'])) {
            $query->where('status', $filters['status']);
        }

        // Filter by programme
        if (!empty($filters['programme_id'])) {
            $query->where('programme_id', $filters['programme_id']);
        }

        // Filter by role preference
        if (!empty($filters['role_preference'])) {
            $query->where('role_preference', $filters['role_preference']);
        }

        // Filter by payment status
        if (!empty($filters['payment_status'])) {
            $query->where('payment_status', $filters['payment_status']);
        }

        // Search
        if (!empty($filters['search'])) {
            $query->where(function ($q) use ($filters) {
                $q->where('name', 'like', '%' . $filters['search'] . '%')
                    ->orWhere('email', 'like', '%' . $filters['search'] . '%')
                    ->orWhere('phone', 'like', '%' . $filters['search'] . '%');
            });
        }

        // Sort
        $sortBy = $filters['sort_by'] ?? 'created_at';
        $sortOrder = $filters['sort_order'] ?? 'desc';
        $query->orderBy($sortBy, $sortOrder);

        return $query->paginate($perPage);
    }

    /**
     * Get pending applications count.
     */
    public function getPendingCount(): int
    {
        return Application::pending()->count();
    }

    /**
     * Create or update user from application.
     */
    protected function createOrUpdateUser(Application $application): User
    {
        $user = User::where('email', $application->email)->first();

        if ($user) {
            // Update existing user
            $user->update([
                'name' => $application->name,
                'phone' => $application->phone ?? $user->phone,
            ]);
        } else {
            // Create new user
            $user = User::create([
                'name'     => $application->name,
                'email'    => $application->email,
                'username' => User::generateUsername($application->email),
                'phone'    => $application->phone,
                'password' => bcrypt(Str::random(16)),
            ]);

            // Send password setup email
            $this->sendPasswordSetupEmail($user);
        }

        return $user;
    }

    /**
     * Assign role to user.
     */
    protected function assignRole(User $user, string $role): void
    {
        $roleName = ucfirst($role); // 'Mentor' or 'Mentee'
        
        if (!$user->hasRole($roleName)) {
            $user->assignRole($roleName);
        }
    }

    /**
     * Send confirmation notification.
     */
    protected function sendConfirmationNotification(Application $application): void
    {
        try {
            // Send email
            if ($this->emailService->isReady()) {
                $this->emailService->sendTemplate(
                    $application->email,
                    'Application Received - ' . $application->programme->title,
                    'emails.mentorship.application-received',
                    [
                        'applicantName' => $application->name,
                        'programmeName' => $application->programme->title,
                        'applicationId' => $application->id,
                        'statusUrl' => route('mentorship.public.status', $application->id),
                    ]
                );
            }

            // Send SMS
            if ($application->phone && $this->smsService->isAvailable()) {
                $this->smsService->sendTemplate(
                    $application->phone,
                    'Your application for {programme} has been received. Track status at our website.',
                    ['programme' => $application->programme->title]
                );
            }
        } catch (\Exception $e) {
            Log::error('Failed to send confirmation notification', [
                'application_id' => $application->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Send approval notification.
     */
    protected function sendApprovalNotification(Application $application, User $user): void
    {
        try {
            // Send email
            if ($this->emailService->isReady()) {
                $this->emailService->sendTemplate(
                    $application->email,
                    'Application Approved - ' . $application->programme->title,
                    'emails.mentorship.application-approved',
                    [
                        'applicantName' => $application->name,
                        'programmeName' => $application->programme->title,
                        'role' => $application->role_preference,
                        'loginUrl' => route('login'),
                        'dashboardUrl' => route('dashboard'),
                    ]
                );
            }

            // Send SMS
            if ($application->phone && $this->smsService->isAvailable()) {
                $this->smsService->sendTemplate(
                    $application->phone,
                    'Congratulations! Your application for {programme} as {role} has been approved. Login to your dashboard.',
                    [
                        'programme' => $application->programme->title,
                        'role' => $application->role_preference
                    ]
                );
            }
        } catch (\Exception $e) {
            Log::error('Failed to send approval notification', [
                'application_id' => $application->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Send rejection notification.
     */
    protected function sendRejectionNotification(Application $application): void
    {
        try {
            // Send email
            if ($this->emailService->isReady()) {
                $this->emailService->sendTemplate(
                    $application->email,
                    'Application Update - ' . $application->programme->title,
                    'emails.mentorship.application-rejected',
                    [
                        'applicantName' => $application->name,
                        'programmeName' => $application->programme->title,
                        'reason' => $application->rejection_reason,
                    ]
                );
            }
        } catch (\Exception $e) {
            Log::error('Failed to send rejection notification', [
                'application_id' => $application->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Send password setup email.
     */
    protected function sendPasswordSetupEmail(User $user): void
    {
        // Generate password reset token and send email
        // This would integrate with Laravel's password reset functionality
        // Implementation depends on your password setup flow
    }
}
