<?php

namespace App\Services\Mentorship;

use App\Models\Mentorship\Session;
use App\Models\Mentorship\Assignment;
use App\Services\MeetService;
use App\Services\EmailService;
use App\Services\SMSService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;

class SessionService
{
    protected MeetService $meetService;
    protected EmailService $emailService;
    protected SMSService $smsService;

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

    /**
     * Create a new session.
     */
    public function create(array $data): Session
    {
        DB::beginTransaction();
        
        try {
            $assignment = Assignment::findOrFail($data['assignment_id']);

            // Set creator
            $data['created_by'] = auth()->id();
            $data['programme_id'] = $assignment->programme_id;

            // Determine session number
            $existingSessions = $assignment->sessions()->count();
            if ($existingSessions === 0) {
                $data['session_number'] = 'first';
            }

            // Create Google Meet link for online sessions
            if ($data['type'] === Session::TYPE_ONLINE && empty($data['meeting_link'])) {
                $meetingData = $this->createOnlineMeeting($data, $assignment);
                $data = array_merge($data, $meetingData);
            }

            $session = Session::create($data);

            DB::commit();

            // Send invitation
            $this->sendSessionInvitation($session);

            Log::info('Mentorship session created', [
                'session_id' => $session->id,
                'assignment_id' => $assignment->id,
                'type' => $session->type,
                'created_by' => auth()->id(),
            ]);

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

    /**
     * Update a session.
     */
    public function update(Session $session, array $data): Session
    {
        DB::beginTransaction();
        
        try {
            // If rescheduling
            $isRescheduling = isset($data['start_time']) && $data['start_time'] != $session->start_time->toIso8601String();
            
            if ($isRescheduling && $session->calendar_event_id) {
                // Update Google Calendar event
                $this->updateCalendarEvent($session, $data);
            }

            $session->update($data);

            DB::commit();

            if ($isRescheduling) {
                $this->sendRescheduleNotification($session);
            }

            Log::info('Mentorship session updated', [
                'session_id' => $session->id,
                'updated_by' => auth()->id(),
            ]);

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

    /**
     * Cancel a session.
     */
    public function cancel(Session $session, string $reason): Session
    {
        DB::beginTransaction();
        
        try {
            $cancelledBy = auth()->id();
            $session->cancel($cancelledBy, $reason);

            // Update assignment progress
            $session->assignment->updateProgress();

            DB::commit();

            // Send cancellation notification
            $this->sendCancellationNotification($session);

            Log::info('Mentorship session cancelled', [
                'session_id' => $session->id,
                'reason' => $reason,
                'cancelled_by' => $cancelledBy,
            ]);

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

    /**
     * Complete a session.
     */
    public function complete(Session $session, array $data): Session
    {
        DB::beginTransaction();
        
        try {
            $session->complete($data);

            // Check if this is the last session
            $assignment = $session->assignment;
            $totalSessions = $assignment->sessions_total;
            $completedSessions = $assignment->sessions()->completed()->count();

            if ($totalSessions > 0 && $completedSessions >= $totalSessions) {
                // Mark as last session
                $session->update(['session_number' => 'last']);
                
                // Assignment is complete
                $assignment->complete('All sessions completed');
            }

            DB::commit();

            Log::info('Mentorship session completed', [
                'session_id' => $session->id,
                'attendance_mentor' => $session->mentor_attended,
                'attendance_mentee' => $session->mentee_attended,
            ]);

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

    /**
     * Reschedule a session.
     */
    public function reschedule(Session $session, array $newData): Session
    {
        DB::beginTransaction();
        
        try {
            // Create new session
            $newSession = $session->reschedule(array_merge($newData, [
                'created_by' => auth()->id(),
                'reschedule_reason' => $newData['reschedule_reason'] ?? null,
            ]));

            if (!$newSession) {
                throw new \Exception('Failed to create new session for reschedule.');
            }

            DB::commit();

            // Send reschedule notification
            $this->sendRescheduleNotification($newSession);

            Log::info('Mentorship session rescheduled', [
                'original_session_id' => $session->id,
                'new_session_id' => $newSession->id,
                'reason' => $newData['reschedule_reason'] ?? null,
            ]);

            return $newSession;
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to reschedule mentorship session', [
                'error' => $e->getMessage(),
                'session_id' => $session->id,
            ]);
            throw $e;
        }
    }

    /**
     * Get sessions with filtering.
     */
    public function getSessions(array $filters = [], int $perPage = 15)
    {
        $query = Session::with(['assignment.mentor', 'assignment.mentee', 'programme', 'creator']);

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

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

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

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

        // Filter by user (mentor or mentee)
        if (!empty($filters['user_id'])) {
            $query->whereHas('assignment', function ($q) use ($filters) {
                $q->where('mentor_id', $filters['user_id'])
                    ->orWhere('mentee_id', $filters['user_id']);
            });
        }

        // Filter by date range
        if (!empty($filters['start_date']) && !empty($filters['end_date'])) {
            $query->dateRange($filters['start_date'], $filters['end_date']);
        }

        // Filter upcoming
        if (!empty($filters['upcoming'])) {
            $query->upcoming();
        }

        // Filter past
        if (!empty($filters['past'])) {
            $query->past();
        }

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

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

    /**
     * Get calendar events for a user.
     */
    public function getCalendarEvents(int $userId, ?string $startDate = null, ?string $endDate = null): array
    {
        $query = Session::with(['assignment.mentor', 'assignment.mentee', 'programme'])
            ->whereHas('assignment', function ($q) use ($userId) {
                $q->where('mentor_id', $userId)
                    ->orWhere('mentee_id', $userId);
            })
            ->whereIn('status', ['scheduled', 'confirmed']);

        if ($startDate && $endDate) {
            $query->dateRange($startDate, $endDate);
        }

        $sessions = $query->get();

        return $sessions->map(function ($session) use ($userId) {
            $assignment = $session->assignment;
            $isMentor = $assignment->mentor_id === $userId;
            $otherPerson = $isMentor ? $assignment->mentee : $assignment->mentor;

            return [
                'id' => $session->id,
                'title' => $session->title,
                'start' => $session->start_time->toIso8601String(),
                'end' => $session->end_time->toIso8601String(),
                'type' => $session->type,
                'status' => $session->status,
                'other_person_name' => $otherPerson->name,
                'meeting_link' => $session->meeting_link,
                'venue' => $session->venue,
                'programme_name' => $session->programme->title,
                'url' => route('mentorship.sessions.show', $session),
            ];
        })->toArray();
    }

    /**
     * Send session reminders.
     */
    public function sendReminders(): int
    {
        $sent = 0;

        // 24-hour reminders
        $sessions24h = Session::with(['assignment.mentor', 'assignment.mentee'])
            ->whereIn('status', ['scheduled', 'confirmed'])
            ->where('reminder_sent_24h', false)
            ->get()
            ->filter(fn($s) => $s->shouldSend24hReminder());

        foreach ($sessions24h as $session) {
            $this->sendReminderNotification($session, '24h');
            $session->markReminder24hSent();
            $sent++;
        }

        // 1-hour reminders
        $sessions1h = Session::with(['assignment.mentor', 'assignment.mentee'])
            ->whereIn('status', ['scheduled', 'confirmed'])
            ->where('reminder_sent_1h', false)
            ->get()
            ->filter(fn($s) => $s->shouldSend1hReminder());

        foreach ($sessions1h as $session) {
            $this->sendReminderNotification($session, '1h');
            $session->markReminder1hSent();
            $sent++;
        }

        return $sent;
    }

    /**
     * Create online meeting using Google Meet.
     */
    protected function createOnlineMeeting(array $data, Assignment $assignment): array
    {
        try {
            $result = $this->meetService->createMeeting(
                summary: $data['title'],
                startTime: $data['start_time'],
                endTime: $data['end_time'],
                attendees: [$assignment->mentor->email, $assignment->mentee->email],
                description: $data['description'] ?? 'Mentorship session between ' . 
                    $assignment->mentor->name . ' and ' . $assignment->mentee->name
            );

            if ($result['success']) {
                return [
                    'meeting_link' => $result['meeting_link'],
                    'meeting_id' => $result['meeting_id'],
                    'calendar_event_id' => $result['calendar_event_id'],
                    'meeting_details' => $result,
                ];
            }

            Log::warning('Failed to create Google Meet meeting', [
                'error' => $result['message'] ?? 'Unknown error',
                'assignment_id' => $assignment->id,
            ]);

            return [];
        } catch (\Exception $e) {
            Log::error('Exception creating Google Meet meeting', [
                'error' => $e->getMessage(),
                'assignment_id' => $assignment->id,
            ]);
            return [];
        }
    }

    /**
     * Update Google Calendar event.
     */
    protected function updateCalendarEvent(Session $session, array $data): void
    {
        try {
            // Implementation depends on MeetService capabilities
            // This would update the existing calendar event with new times
        } catch (\Exception $e) {
            Log::error('Failed to update calendar event', [
                'error' => $e->getMessage(),
                'session_id' => $session->id,
            ]);
        }
    }

    /**
     * Send session invitation.
     */
    protected function sendSessionInvitation(Session $session): void
    {
        $assignment = $session->assignment;

        try {
            // Email invitation
            if ($this->emailService->isReady()) {
                // To mentor
                $this->emailService->sendTemplate(
                    $assignment->mentor->email,
                    'Mentorship Session Scheduled - ' . $session->title,
                    'emails.mentorship.session-invitation',
                    [
                        'userName' => $assignment->mentor->name,
                        'otherName' => $assignment->mentee->name,
                        'sessionTitle' => $session->title,
                        'programmeName' => $session->programme->title,
                        'dateTime' => $session->formatted_date_time,
                        'type' => $session->type_label,
                        'meetingLink' => $session->meeting_link,
                        'venue' => $session->venue,
                        'sessionUrl' => route('mentorship.sessions.show', $session),
                    ]
                );

                // To mentee
                $this->emailService->sendTemplate(
                    $assignment->mentee->email,
                    'Mentorship Session Scheduled - ' . $session->title,
                    'emails.mentorship.session-invitation',
                    [
                        'userName' => $assignment->mentee->name,
                        'otherName' => $assignment->mentor->name,
                        'sessionTitle' => $session->title,
                        'programmeName' => $session->programme->title,
                        'dateTime' => $session->formatted_date_time,
                        'type' => $session->type_label,
                        'meetingLink' => $session->meeting_link,
                        'venue' => $session->venue,
                        'sessionUrl' => route('mentorship.sessions.show', $session),
                    ]
                );
            }
        } catch (\Exception $e) {
            Log::error('Failed to send session invitation', [
                'session_id' => $session->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Send reschedule notification.
     */
    protected function sendRescheduleNotification(Session $session): void
    {
        $assignment = $session->assignment;

        try {
            if ($this->emailService->isReady()) {
                $this->emailService->sendTemplate(
                    $assignment->mentor->email,
                    'Session Rescheduled - ' . $session->title,
                    'emails.mentorship.session-rescheduled',
                    [
                        'userName' => $assignment->mentor->name,
                        'sessionTitle' => $session->title,
                        'newDateTime' => $session->formatted_date_time,
                        'meetingLink' => $session->meeting_link,
                        'sessionUrl' => route('mentorship.sessions.show', $session),
                    ]
                );

                $this->emailService->sendTemplate(
                    $assignment->mentee->email,
                    'Session Rescheduled - ' . $session->title,
                    'emails.mentorship.session-rescheduled',
                    [
                        'userName' => $assignment->mentee->name,
                        'sessionTitle' => $session->title,
                        'newDateTime' => $session->formatted_date_time,
                        'meetingLink' => $session->meeting_link,
                        'sessionUrl' => route('mentorship.sessions.show', $session),
                    ]
                );
            }
        } catch (\Exception $e) {
            Log::error('Failed to send reschedule notification', [
                'session_id' => $session->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Send cancellation notification.
     */
    protected function sendCancellationNotification(Session $session): void
    {
        $assignment = $session->assignment;

        try {
            if ($this->emailService->isReady()) {
                $this->emailService->sendTemplate(
                    $assignment->mentor->email,
                    'Session Cancelled - ' . $session->title,
                    'emails.mentorship.session-cancelled',
                    [
                        'userName' => $assignment->mentor->name,
                        'sessionTitle' => $session->title,
                        'reason' => $session->cancellation_reason,
                    ]
                );

                $this->emailService->sendTemplate(
                    $assignment->mentee->email,
                    'Session Cancelled - ' . $session->title,
                    'emails.mentorship.session-cancelled',
                    [
                        'userName' => $assignment->mentee->name,
                        'sessionTitle' => $session->title,
                        'reason' => $session->cancellation_reason,
                    ]
                );
            }

            // SMS notification
            if ($this->smsService->isAvailable()) {
                if ($assignment->mentor->phone) {
                    $this->smsService->send(
                        $assignment->mentor->phone,
                        "Session \"{$session->title}\" has been cancelled. Reason: {$session->cancellation_reason}"
                    );
                }
                if ($assignment->mentee->phone) {
                    $this->smsService->send(
                        $assignment->mentee->phone,
                        "Session \"{$session->title}\" has been cancelled. Reason: {$session->cancellation_reason}"
                    );
                }
            }
        } catch (\Exception $e) {
            Log::error('Failed to send cancellation notification', [
                'session_id' => $session->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Send reminder notification.
     */
    protected function sendReminderNotification(Session $session, string $type): void
    {
        $assignment = $session->assignment;
        $timeText = $type === '24h' ? 'in 24 hours' : 'in 1 hour';

        try {
            if ($this->smsService->isAvailable()) {
                $message = $session->isOnline()
                    ? "Reminder: Your mentorship session \"{$session->title}\" is {$timeText}. Join at: {$session->meeting_link}"
                    : "Reminder: Your mentorship session \"{$session->title}\" is {$timeText} at {$session->venue}";

                if ($assignment->mentor->phone) {
                    $this->smsService->send($assignment->mentor->phone, $message);
                }
                if ($assignment->mentee->phone) {
                    $this->smsService->send($assignment->mentee->phone, $message);
                }
            }
        } catch (\Exception $e) {
            Log::error('Failed to send reminder notification', [
                'session_id' => $session->id,
                'type' => $type,
                'error' => $e->getMessage(),
            ]);
        }
    }
}
