<?php
namespace App\Http\Controllers;
use App\Helper\Helper;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Http\Request;
use Illuminate\Support\MessageBag;
use Session;
use Google\Service\Gmail;
use Illuminate\Support\Facades\Log;
use Webklex\LaravelIMAP\Client;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
use App\User;
use Google_Client;
use Google_Service_Gmail;
use Swift_Message;
use Google_Service_Gmail_Message;
use Google_Service_Gmail_ModifyMessageRequest;
class MailboxController extends Controller
{
   
public function googlepage(){
    Log::info('reached');
    return socialite::driver('google')->redirect();
}
public function googlecallback(Request $request){
    try {
        $user = Socialite::driver('google')->user();
        $user_id=$user->id;
        Log::info('reached',['user'=>$user]);
        $url = env('API_URL').'auth/google/callback';
        $body=array(
            'user_id' => $user_id,
            'id'=>$user->id,
            'email'=>$user->email,
            'token' => Session::get('tokenId'),
        );
        $result = Helper::PostApi($url,$body);
        if($result){
            return redirect('/dashboard');
        }

      
  
  
    } catch (Exception $e) {
        dd($e->getMessage());
    }
}

public function userMailSelect(){
    return view('user-mailbox');
}
public function index(Request $request)
{
    $client = new Google_Client();
    $client->setAuthConfig(public_path("assets/client_secret.json"));
    $client->setScopes(['https://www.googleapis.com/auth/gmail.readonly', 'https://www.googleapis.com/auth/gmail.send','https://www.googleapis.com/auth/gmail.modify','https://mail.google.com/'
]);

    if (session()->has('token')) {
        $accessToken = session('token');
        $client->setAccessToken($accessToken);

        if ($client->isAccessTokenExpired()) {
            if ($client->getRefreshToken()) {
                $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
                session(['token' => $client->getAccessToken()]);
            } else {
                session()->forget('token');
                return redirect()->away($client->createAuthUrl());
            }
        }

        $tokenScopes = $client->getAccessToken()['scope'] ?? '';
        $requiredScopes = [
            'https://www.googleapis.com/auth/gmail.readonly',
            'https://www.googleapis.com/auth/gmail.send',
           'https://www.googleapis.com/auth/gmail.modify',
           'https://mail.google.com/'
        ];

        foreach ($requiredScopes as $scope) {
            if (!in_array($scope, explode(' ', $tokenScopes))) {
                session()->forget('token');
                return redirect()->away($client->createAuthUrl());
            }
        }

        return $this->main($client, $request);
    } else if ($request->has('code')) {
        $accessToken = $client->fetchAccessTokenWithAuthCode($request->input('code'));

        if (isset($accessToken['error'])) {
            return response()->json(['error' => $accessToken['error']], 400);
        }

        session(['token' => $accessToken]);
        $client->setAccessToken($accessToken);

        return $this->main($client, $request);
    } else {
        return redirect()->away($client->createAuthUrl());
    }
}


public function main($client, Request $request)
{
    $service = new Google_Service_Gmail($client);
    $user = 'me';

    $messagesPerPage = 10;
    $query = $request->input('search');

    // Get label counts
    $labelCounts = $this->getLabelCounts($service, $user);
    Log::info('Label counts: ' . json_encode($labelCounts));

    // Get current page number from session or set to 1 if not present
    $inboxCurrentPage = session('inboxCurrentPage', 1);
    $sentCurrentPage = session('sentCurrentPage', 1);
    $draftCurrentPage = session('draftCurrentPage', 1);
    $starredCurrentPage = session('starredCurrentPage', 1);
    $trashCurrentPage = session('trashCurrentPage', 1);

    // Update current page based on request
    if ($request->has('inboxPageToken')) {
        $inboxCurrentPage++;
    } else {
        $inboxCurrentPage = 1;
    }
    if ($request->has('sentPageToken')) {
        $sentCurrentPage++;
    } else {
        $sentCurrentPage = 1;
    }
    if ($request->has('draftPageToken')) {
        $draftCurrentPage++;
    } else {
        $draftCurrentPage = 1;
    }
    if ($request->has('starredPageToken')) {
        $starredCurrentPage++;
    } else {
        $starredCurrentPage = 1;
    }
    if ($request->has('trashPageToken')) {
        $trashCurrentPage++;
    } else {
        $trashCurrentPage = 1;
    }

    // Store current page in session
    session(['inboxCurrentPage' => $inboxCurrentPage]);
    session(['sentCurrentPage' => $sentCurrentPage]);
    session(['draftCurrentPage' => $draftCurrentPage]);
    session(['starredCurrentPage' => $starredCurrentPage]);
    session(['trashCurrentPage' => $trashCurrentPage]);

    // Get messages data
    $inboxData = $this->getMessageData($service, $user, 'INBOX', $request->input('inboxPageToken'), $query);
    //echo "<pre>";print_r($inboxData);die;

    $sentData = $this->getMessageData($service, $user, 'SENT', $request->input('sentPageToken'), $query);
    $draftData = $this->getMessageData($service, $user, 'DRAFT', $request->input('draftPageToken'), $query);
    $starredData = $this->getMessageData($service, $user, 'STARRED', $request->input('starredPageToken'), $query);
    $trashData = $this->getMessageData($service, $user, 'TRASH', $request->input('trashPageToken'), $query);

    // Calculate start and end message ranges
    $calculateMessageRange = function($currentPage, $totalMessages) use ($messagesPerPage) {
        $startMessage = ($currentPage - 1) * $messagesPerPage + 1;
        $endMessage = min($startMessage + $messagesPerPage - 1, $totalMessages);
        return [$startMessage, $endMessage];
    };

    // Calculate ranges for each section
    list($inboxStartMessage, $inboxEndMessage) = $calculateMessageRange($inboxCurrentPage, $labelCounts['INBOX']['messageCount'] ?? 0);
    list($sentStartMessage, $sentEndMessage) = $calculateMessageRange($sentCurrentPage, $labelCounts['SENT']['messageCount'] ?? 0);
    list($draftStartMessage, $draftEndMessage) = $calculateMessageRange($draftCurrentPage, $labelCounts['DRAFT']['messageCount'] ?? 0);
    list($starredStartMessage, $starredEndMessage) = $calculateMessageRange($starredCurrentPage, $labelCounts['STARRED']['messageCount'] ?? 0);
    list($trashStartMessage, $trashEndMessage) = $calculateMessageRange($trashCurrentPage, $labelCounts['TRASH']['messageCount'] ?? 0);

    return view('mailbox', [
        'inboxMessages' => $inboxData['messages'],
        'inboxPreviousPageToken' => session('inboxPreviousPageToken'),
        'inboxNextPageToken' => $inboxData['nextPageToken'],
        'inboxTotal' => $labelCounts['INBOX']['messageCount'] ?? 0,
        'inboxStartMessage' => $inboxStartMessage,
        'inboxEndMessage' => $inboxEndMessage,
        'query' => $query,
        'sentMessages' => $sentData['messages'],
        'sentPreviousPageToken' => session('sentPreviousPageToken'),
        'sentNextPageToken' => $sentData['nextPageToken'],
        'sentTotal' => $labelCounts['SENT']['messageCount'] ?? 0,
        'sentStartMessage' => $sentStartMessage,
        'sentEndMessage' => $sentEndMessage,
        'draftMessages' => $draftData['messages'],
        'draftPreviousPageToken' => session('draftPreviousPageToken'),
        'draftNextPageToken' => $draftData['nextPageToken'],
        'draftTotal' => $labelCounts['DRAFT']['messageCount'] ?? 0,
        'draftStartMessage' => $draftStartMessage,
        'draftEndMessage' => $draftEndMessage,
        'starredMessages' => $starredData['messages'],
        'starredPreviousPageToken' => session('starredPreviousPageToken'),
        'starredNextPageToken' => $starredData['nextPageToken'],
        'starredTotal' => $labelCounts['STARRED']['messageCount'] ?? 0,
        'starredStartMessage' => $starredStartMessage,
        'starredEndMessage' => $starredEndMessage,
        'trashMessages' => $trashData['messages'],
        'trashPreviousPageToken' => session('trashPreviousPageToken'),
        'trashNextPageToken' => $trashData['nextPageToken'],
        'trashTotal' => $labelCounts['TRASH']['messageCount'] ?? 0,
        'trashStartMessage' => $trashStartMessage,
        'trashEndMessage' => $trashEndMessage,
    ]);
}




private function getLabelCounts($service, $userId)
{
    $labelsResponse = $service->users_labels->listUsersLabels($userId);

    // Log the raw labels response
    Log::info('Labels response: ' . json_encode($labelsResponse));

    $labelCounts = [];

    if (!$labelsResponse || empty($labelsResponse->getLabels())) {
        Log::error('No labels found or labels are empty');
        return $labelCounts;
    }

    foreach ($labelsResponse->getLabels() as $label) {
        // Fetch the label details to get the message count
        $labelDetails = $service->users_labels->get($userId, $label->getId());

        // Log the label details object to inspect its structure
        Log::info('Label details: ' . json_encode($labelDetails));

        $labelCounts[$label->getName()] = [
            'id' => $labelDetails->getId(),
            'messageCount' => $labelDetails->getMessagesTotal()
        ];
    }

    return $labelCounts;
}



private function listMessagesInbox($service, $userId, $pageToken = null, $query = null)
{
    return $this->listMessages($service, $userId, 'INBOX', $pageToken, $query);
}

private function listSentMessages($service, $userId, $pageToken = null, $query = null)
{
    return $this->listMessages($service, $userId, 'SENT', $pageToken, $query);
}

private function listDraftMessages($service, $userId, $pageToken = null, $query = null)
{
    return $this->listMessages($service, $userId, 'DRAFT', $pageToken, $query);
}

private function listStarredMessages($service, $userId, $pageToken = null, $query = null)
{
    return $this->listMessages($service, $userId, 'STARRED', $pageToken, $query);
}

private function listTrashMessages($service, $userId, $pageToken = null, $query = null)
{
    return $this->listMessages($service, $userId, 'TRASH', $pageToken, $query);
}



private function getMessageData($service, $userId, $label, $pageToken = null, $query = null)
{
    Log::info('reached');
    $optParams = [
        'labelIds' => $label,
        'maxResults' => 10,
    ];

    if ($pageToken) {
        $optParams['pageToken'] = $pageToken;
    }

    if ($query) {
        $optParams['q'] = $query;
    }

    $messagesResponse = $service->users_messages->listUsersMessages($userId, $optParams);

    $messages = [];
    if ($messagesResponse->getMessages()) {
        $messages = $messagesResponse->getMessages();
    }

    return [
        'messages' => $this->prepareMessageData($service, $userId, $messages),
        'nextPageToken' => $messagesResponse->getNextPageToken(),
    ];
}



private function getMessage($service, $userId, $messageId)
{
    return $service->users_messages->get($userId, $messageId);
}

private function decodeBody($body)
{
    $sanitizedData = strtr($body, '-_', '+/');
    $decodedMessage = base64_decode($sanitizedData);

    return $decodedMessage ? $decodedMessage : false;
}

private function prepareMessageDatao($service, $userId, $messages)
{
    $messageData = [];
    foreach ($messages as $message) {
        $msg = $this->getMessage($service, $userId, $message->getId());
        $payload = $msg->getPayload();
        $headers = $payload->getHeaders();
        $body = $payload->getBody()->getData();
        $parts = $payload->getParts();
        
        // Decode body if needed
        if ($body) {
            $body = $this->decodeBody($body);
        } else {
            $body = '';
            foreach ($parts as $part) {
                if ($part['mimeType'] == 'text/html') {
                    $body = $this->decodeBody($part['body']['data']);
                    break;
                }
            }
        }

        // Extract headers
        $from = '';
        $subject = '';
        $date = '';
        foreach ($headers as $header) {
            if ($header->getName() == 'From') {
                $from = $header->getValue();
            }
            if ($header->getName() == 'Subject') {
                $subject = $header->getValue();
            }
            if ($header->getName() == 'Date') {
                $date = $header->getValue();
            }
        }

        // Handle attachments
        $attachments = [];
        foreach ($parts as $part) {
            if (isset($part['filename']) && $part['filename'] != '') {
                $attachmentId = $part['body']->getAttachmentId();
                $attachment = $this->getAttachment($service, $userId, $message->getId(), $attachmentId);
                $attachments[] = [
                    'filename' => $part['filename'],
                    'size' => $part['size'],
                    'mimeType' => $part['mimeType'],
                 
                    
                    
                ];
            }
        }

        $messageData[] = [
            'id' => $message->getId(),
            'from' => $from,
            'subject' => $subject,
            'body' => $body,
            'date' => $date,
            'attachments' => $attachments,
        ];
    }
    return $messageData;
}
private function prepareMessageData($service, $userId, $messages)
{
    $messageData = [];
    foreach ($messages as $message) {
        $msg = $this->getMessage($service, $userId, $message->getId());
        $payload = $msg->getPayload();
        $headers = $payload->getHeaders();
        $body = $payload->getBody()->getData();
        $parts = $payload->getParts();
        
        // Decode body if needed
        if ($body) {
            $body = $this->decodeBody($body);
        } else {
            $body = '';
            foreach ($parts as $part) {
                if ($part['mimeType'] == 'text/html') {
                    $body = $this->decodeBody($part['body']['data']);
                    break;
                }
            }
        }

        // Extract headers
        $to='';
        $from = '';
        $subject = '';
        $date = '';
        foreach ($headers as $header) {
            if ($header->getName() == 'From') {
                $from = $header->getValue();
            }
            if ($header->getName() == 'Subject') {
                $subject = $header->getValue();
            }
            if ($header->getName() == 'Date') {
                $date = $header->getValue();
            }
            if ($header->getName() == 'To') {
                $to = $header->getValue();
            }
        }

        // Check if the email is starred
        $isStarred = in_array('STARRED', $msg->getLabelIds());

        // Handle attachments
        $attachments = [];
        foreach ($parts as $part) {
            if (isset($part['filename']) && $part['filename'] != '') {
                $attachmentId = $part['body']->getAttachmentId();
                $attachment = $this->getAttachment($service, $userId, $message->getId(), $attachmentId);
                $attachments[] = [
                    'filename' => $part['filename'],
                    'mimeType' => $part['mimeType'],
                    'data' => $attachment['data'],
                ];
            }
        }

        $messageData[] = [
            'id' => $message->getId(),
            'from' => $from,
            'subject' => $subject,
            'body' => $body,
            'date' => $date,
            'attachments' => $attachments,
            'is_starred' => $isStarred, // Add 'is_starred' index
            'to'=>$to,
        ];
    }
    return $messageData;
}

private function getAttachment($service, $userId, $messageId, $attachmentId)
{
    $attachment = $service->users_messages_attachments->get($userId, $messageId, $attachmentId);
    $data = $this->decodeBody($attachment->getData());
    return ['data' => $data];
}
public function sendEmail(Request $request)
{
    $client = new Google_Client();
    $client->setAuthConfig(public_path("assets/client_secret.json"));
    $client->setScopes(['https://www.googleapis.com/auth/gmail.send']);

    if (session()->has('token')) {
        $accessToken = session('token');
        $client->setAccessToken($accessToken);

        if ($client->isAccessTokenExpired()) {
            $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
            session(['token' => $client->getAccessToken()]);
        }

        // Ensure the token has the required scope
        $tokenScopes = $client->getAccessToken()['scope'] ?? '';
        if (!in_array('https://www.googleapis.com/auth/gmail.send', explode(' ', $tokenScopes))) {
            session()->forget('token');
            return redirect()->away($client->createAuthUrl());
        }
    } else {
        return redirect()->away($client->createAuthUrl());
    }

    $service = new Google_Service_Gmail($client);
    $body = trim($request->input('body'));
    try {
        $rawMessage = $this->createMessage($request->input('to'), $request->input('subject'), $body, $request->file('attachment'));
        $email = new Google_Service_Gmail_Message();
        $email->setRaw($rawMessage);

        $sentMessage = $service->users_messages->send('me', $email);
        \Log::info('Sent message response: ' . json_encode($sentMessage));

        return redirect()->back()->with('success', 'Email sent successfully!');
    } catch (\Exception $e) {
        \Log::error('Failed to send email: ' . $e->getMessage());
        return redirect()->back()->with('error', 'Failed to send email: ' . $e->getMessage());
    }
}

private function createMessage($to, $subject, $body,$attachment)
{
    $boundary = uniqid(rand(), true);

    $message = "To: $to\r\n";
    $message .= "Subject: $subject\r\n";
    $message .= "MIME-Version: 1.0\r\n";
    $message .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n\r\n";
    $message .= "--$boundary\r\n";
    $message .= "Content-Type: text/plain; charset=utf-8\r\n";
    $message .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
    $message .= "$body\r\n\r\n";
    $message .= "--$boundary\r\n";

    if ($attachment) {
        $filePath = $attachment->getRealPath();
        $fileName = $attachment->getClientOriginalName();
        $fileData = file_get_contents($filePath);
        $fileType = $attachment->getClientMimeType();

        $message .= "Content-Type: $fileType; name=\"$fileName\"\r\n";
        $message .= "Content-Disposition: attachment; filename=\"$fileName\"\r\n";
        $message .= "Content-Transfer-Encoding: base64\r\n\r\n";
        $message .= chunk_split(base64_encode($fileData));
        $message .= "\r\n\r\n";
        $message .= "--$boundary--";
    }

    \Log::info('Constructed email message with attachment: ' . $message);

    return base64_encode($message);
}

public function deleteEmail(Request $request)
    {
        $messageId = $request->input('message_id');

        if (!$messageId) {
            return redirect()->back()->with(['error' => 'Message ID is required'], 400);
        }

        $client = new Google_Client();
        $client->setAuthConfig(public_path("assets/client_secret.json"));
        $client->setScopes(['https://mail.google.com/']);

        if (session()->has('token')) {
            $accessToken = session('token');
            $client->setAccessToken($accessToken);

            if ($client->isAccessTokenExpired()) {
                $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
                session(['token' => $client->getAccessToken()]);
            }

            $service = new Google_Service_Gmail($client);

            try {
                $service->users_messages->delete('me', $messageId);
                //echo "<pre>";print_r($service);die;

                return redirect()->back()->with(['success' => 'Email deleted successfully']);
            } catch (\Exception $e) {
                \Log::error('Failed to delete email: ' . $e->getMessage());
                return redirect()->back()->with(['error' => 'Failed to delete email: ' . $e->getMessage()], 500);
            }
        } else {
            return redirect()->back()->with(['error' => 'Unauthorized'], 401);
        }
    }

    public function starEmail(Request $request)
    {
        $emailId = $request->input('emailId');
        
        if (!$emailId) {
            return response()->json(['success' => false, 'message' => 'Email ID is required'], 400);
        }
        
        $client = new Google_Client();
        $client->setAuthConfig(public_path("assets/client_secret.json"));
        $client->setScopes(['https://www.googleapis.com/auth/gmail.modify']);
        
        if ($request->session()->has('token')) {
            $accessToken = $request->session()->get('token');
            $client->setAccessToken($accessToken);
    
            if ($client->isAccessTokenExpired()) {
                $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
                $request->session()->put('gmail_token', $client->getAccessToken());
            }
    
            $service = new Google_Service_Gmail($client);
            $mods = new Google_Service_Gmail_ModifyMessageRequest();
            $mods->setAddLabelIds(['STARRED']);
        
            try {
                $service->users_messages->modify('me', $emailId, $mods);
                return response()->json(['success' => true, 'message' => 'Email starred successfully']);
            } catch (\Exception $e) {
                Log::error('Failed to star email: ' . $e->getMessage());
                return response()->json(['success' => false, 'message' => 'Failed to star email: ' . $e->getMessage()], 500);
            }
        } else {
            return response()->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }
    }
    public function unstarEmail(Request $request)
    {
        $emailId = $request->input('emailId');

        if (!$emailId) {
            return response()->json(['success' => false, 'message' => 'Email ID is required'], 400);
        }

        $client = new Google_Client();
        $client->setAuthConfig(public_path("assets/client_secret.json"));
        $client->setScopes(['https://www.googleapis.com/auth/gmail.modify']);

        if ($request->session()->has('token')) {
            $accessToken = $request->session()->get('token');
            $client->setAccessToken($accessToken);

            if ($client->isAccessTokenExpired()) {
                \Log::info('Access Token Expired. Refreshing token...');
                $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
                $request->session()->put('gmail_token', $client->getAccessToken());
                \Log::info('Refreshed Access Token: ' . json_encode($client->getAccessToken()));
            }

            $service = new Google_Service_Gmail($client);
            $mods = new Google_Service_Gmail_ModifyMessageRequest();
            $mods->setRemoveLabelIds(['STARRED']); // Remove the STARRED label

            try {
                $service->users_messages->modify('me', $emailId, $mods);
                return response()->json(['success' => true, 'message' => 'Email unstarred successfully']);
            } catch (\Exception $e) {
                Log::error('Failed to unstar email: ' . $e->getMessage());
                return response()->json(['success' => false, 'message' => 'Failed to unstar email: ' . $e->getMessage()], 500);
            }
        } else {
            return response()->json(['success' => false, 'message' => 'Unauthorized'], 401);
        }
    }
    public function MailboxDataZoho(Request $request){
        return view('mailbox_zoho');

    }
    public function gmailLogout()
{
    // Forget the Gmail session token
    session()->forget('token');

    // Redirect the user to Google's logout URL
    return redirect()->away('https://accounts.google.com/Logout');
}

}    

