<?php

namespace App\Modules\Office365\Services;

use App\Modules\Office365\Services\Office365ServiceInterface;
use App\Modules\Office365\Services\Office365AuthService;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;

class Office365CalendarService implements Office365ServiceInterface
{
    protected $authService;

    public function __construct(Office365AuthService $authService)
    {
        $this->authService = $authService;
    }

    /**
     * Get calendar events for a date range from ALL calendars
     */
    public function getCalendarEvents($startDate, $endDate, $userId = null)
    {
        $userId = $userId ?: Auth::id();
        $accessToken = $this->authService->getValidToken($userId);

        if (!$accessToken) {
            Log::warning('Office365 calendar access denied - no valid token', ['user_id' => $userId]);
            return [];
        }

        try {
            // First, get all calendars
            $calendarsResponse = Http::withToken($accessToken)
                ->get('https://graph.microsoft.com/v1.0/me/calendars', [
                    '$select' => 'id,name,isDefaultCalendar'
                ]);

            if ($calendarsResponse->failed()) {
                Log::error('Office365 get calendars failed', [
                    'status' => $calendarsResponse->status(),
                    'response' => $calendarsResponse->body(),
                    'user_id' => $userId
                ]);
                return [];
            }

            $calendars = $calendarsResponse->json()['value'] ?? [];
            
            Log::info('Office365 found calendars', [
                'calendars_count' => count($calendars),
                'calendars' => array_map(function($cal) {
                    return ['id' => $cal['id'], 'name' => $cal['name'], 'isDefault' => $cal['isDefaultCalendar'] ?? false];
                }, $calendars),
                'user_id' => $userId
            ]);

            // Get events from all calendars
            $allEvents = [];
            $start = Carbon::parse($startDate)->toISOString();
            $end = Carbon::parse($endDate)->toISOString();


            foreach ($calendars as $calendar) {
                $calendarEvents = [];
                // Use calendarview endpoint which handles recurring events better
                $url = "https://graph.microsoft.com/v1.0/me/calendars/{$calendar['id']}/calendarview";
                
                // CalendarView automatically expands recurring events within the date range
                $params = [
                    '$select' => 'id,subject,start,end,isAllDay,bodyPreview,location,webLink',
                    'startDateTime' => $start,
                    'endDateTime' => $end,
                    '$orderby' => 'start/dateTime',
                    '$top' => 100
                ];

                // Handle pagination to get all events
                do {
                    $response = Http::withToken($accessToken)->get($url, $params);

                    if ($response->successful()) {
                        $responseData = $response->json();
                        $pageEvents = $responseData['value'] ?? [];
                        $calendarEvents = array_merge($calendarEvents, $pageEvents);
                        
                        
                        // Check for next page
                        $nextLink = $responseData['@odata.nextLink'] ?? null;
                        if ($nextLink) {
                            $url = $nextLink;
                            $params = []; // Next link already includes all params
                        } else {
                            $nextLink = false;
                        }
                        
                        
                    } else {
                        Log::warning('Office365 failed to get events from calendar', [
                            'calendar_name' => $calendar['name'],
                            'calendar_id' => $calendar['id'],
                            'status' => $response->status(),
                            'user_id' => $userId
                        ]);
                        break;
                    }
                } while ($nextLink);


                $allEvents = array_merge($allEvents, $calendarEvents);
            }
            
            Log::info('Office365 total events retrieved from all calendars', [
                'total_count' => count($allEvents),
                'user_id' => $userId
            ]);

            return $this->formatEvents($allEvents);

        } catch (\Exception $e) {
            Log::error('Office365 calendar service error', [
                'error' => $e->getMessage(),
                'user_id' => $userId,
                'start_date' => $startDate,
                'end_date' => $endDate
            ]);
            return [];
        }
    }

    /**
     * Format Microsoft Graph events for our calendar
     */
    protected function formatEvents($events)
    {
        $formatted = [];

        foreach ($events as $event) {
            // Parse start and end times
            $start = Carbon::parse($event['start']['dateTime'] ?? $event['start']['date']);
            $end = Carbon::parse($event['end']['dateTime'] ?? $event['end']['date']);
            
            // Check if it's an all-day event
            $isAllDay = $event['isAllDay'] ?? false;
            
            // If all day, adjust end time to prevent spanning to next day
            if ($isAllDay) {
                $end = $end->subSeconds(10);
            }

            $formatted[] = [
                'id' => $event['id'],
                'title' => $event['subject'] ?? 'No Subject',
                'start' => $start->format('Y-m-d H:i:s'),
                'end' => $end->format('Y-m-d H:i:s'),
                'allDay' => $isAllDay,
                'description' => $event['bodyPreview'] ?? '',
                'location' => $event['location']['displayName'] ?? '',
                'webLink' => $event['webLink'] ?? '',
                'source' => 'office365'
            ];
        }

        return $formatted;
    }

    /**
     * Check if user has valid Office 365 authentication
     */
    public function isAuthenticated($userId = null)
    {
        return $this->authService->isAuthenticated($userId);
    }

    /**
     * Get authentication URL for OAuth flow
     */
    public function getAuthUrl()
    {
        return $this->authService->getAuthorizationUrl();
    }

    /**
     * Test Office 365 connection
     */
    public function testConnection($userId = null)
    {
        $userId = $userId ?: Auth::id();
        $accessToken = $this->authService->getValidToken($userId);

        if (!$accessToken) {
            return [
                'success' => false,
                'message' => 'No valid Office 365 token found. Please reconnect.'
            ];
        }

        try {
            // Test connection by getting user profile
            $response = Http::withToken($accessToken)
                ->get('https://graph.microsoft.com/v1.0/me', [
                    '$select' => 'displayName,mail,userPrincipalName'
                ]);

            if ($response->failed()) {
                Log::error('Office365 test connection failed', [
                    'status' => $response->status(),
                    'response' => $response->body(),
                    'user_id' => $userId
                ]);
                
                return [
                    'success' => false,
                    'message' => 'Connection test failed. Please reconnect to Office 365.'
                ];
            }

            $userInfo = $response->json();
            
            // Also fetch calendars in test connection for debugging
            $calendarsResult = $this->getCalendars($userId);
            
            return [
                'success' => true,
                'message' => 'Office 365 connection successful! Connected as: ' . ($userInfo['displayName'] ?? $userInfo['userPrincipalName']),
                'calendars_debug' => $calendarsResult
            ];

        } catch (\Exception $e) {
            Log::error('Office365 test connection exception', [
                'error' => $e->getMessage(),
                'user_id' => $userId
            ]);
            
            return [
                'success' => false,
                'message' => 'Connection test failed: ' . $e->getMessage()
            ];
        }
    }

    /**
     * Get all available calendars for the user
     */
    public function getCalendars($userId = null)
    {
        $userId = $userId ?: Auth::id();
        $accessToken = $this->authService->getValidToken($userId);

        if (!$accessToken) {
            return [
                'success' => false,
                'message' => 'No valid Office 365 token found. Please reconnect.'
            ];
        }

        try {
            $response = Http::withToken($accessToken)
                ->get('https://graph.microsoft.com/v1.0/me/calendars', [
                    '$select' => 'id,name,isDefaultCalendar,canEdit,color'
                ]);

            if ($response->failed()) {
                Log::error('Office365 get calendars failed', [
                    'status' => $response->status(),
                    'response' => $response->body(),
                    'user_id' => $userId
                ]);
                
                return [
                    'success' => false,
                    'message' => 'Failed to fetch calendars'
                ];
            }

            $calendars = $response->json()['value'] ?? [];
            
            return [
                'success' => true,
                'calendars' => $calendars
            ];

        } catch (\Exception $e) {
            Log::error('Office365 get calendars error', [
                'error' => $e->getMessage(),
                'user_id' => $userId
            ]);
            
            return [
                'success' => false,
                'message' => 'Error fetching calendars: ' . $e->getMessage()
            ];
        }
    }

    /**
     * Get calendar events from selected calendars
     */
    public function getCalendarEventsFromSelected($startDate, $endDate, $selectedCalendars = [], $userId = null)
    {
        $userId = $userId ?: Auth::id();
        $accessToken = $this->authService->getValidToken($userId);

        if (!$accessToken) {
            Log::warning('Office365 calendar access denied - no valid token', ['user_id' => $userId]);
            return [];
        }

        // If no calendars selected, use default behavior (primary calendar)
        if (empty($selectedCalendars)) {
            return $this->getCalendarEvents($startDate, $endDate, $userId);
        }

        try {
            $allEvents = [];
            $start = Carbon::parse($startDate)->toISOString();
            $end = Carbon::parse($endDate)->toISOString();
            
            
            foreach ($selectedCalendars as $calendarId) {
                $calendarEvents = [];
                
                // Use calendarview endpoint which handles recurring events better
                $url = "https://graph.microsoft.com/v1.0/me/calendars/{$calendarId}/calendarview";
                $params = [
                    '$select' => 'id,subject,start,end,isAllDay,bodyPreview,location,webLink',
                    'startDateTime' => $start,
                    'endDateTime' => $end,
                    '$orderby' => 'start/dateTime',
                    '$top' => 100
                ];

                // Handle pagination
                do {
                    $response = Http::withToken($accessToken)->get($url, $params);

                    if ($response->successful()) {
                        $responseData = $response->json();
                        $pageEvents = $responseData['value'] ?? [];
                        $calendarEvents = array_merge($calendarEvents, $pageEvents);
                        
                        // Check for next page
                        $nextLink = $responseData['@odata.nextLink'] ?? null;
                        if ($nextLink) {
                            $url = $nextLink;
                            $params = [];
                        } else {
                            $nextLink = false;
                        }
                    } else {
                        Log::warning('Office365 calendar events fetch failed for calendar', [
                            'calendar_id' => $calendarId,
                            'status' => $response->status(),
                            'user_id' => $userId
                        ]);
                        break;
                    }
                } while ($nextLink);

                $allEvents = array_merge($allEvents, $calendarEvents);
                
            }

            Log::debug('Office365 calendar events retrieved from selected calendars', [
                'count' => count($allEvents),
                'calendars' => $selectedCalendars,
                'user_id' => $userId
            ]);

            return $this->formatEvents($allEvents);

        } catch (\Exception $e) {
            Log::error('Office365 selected calendars service error', [
                'error' => $e->getMessage(),
                'user_id' => $userId,
                'calendars' => $selectedCalendars
            ]);
            return [];
        }
    }

    /**
     * Revoke user's Office 365 access
     */
    public function revokeAccess($userId = null)
    {
        return $this->authService->revokeAccess($userId);
    }
}