<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use League\OAuth2\Client\Provider\GenericProvider;
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model\User;
use Illuminate\Support\Facades\Log;
use Session;
use Illuminate\Support\Str;
use Microsoft\Graph\Model\Message;

class OutlookController extends Controller
{
    protected $oauthClient;

    public function __construct(GenericProvider $oauthClient)
    {
        $this->provider = new GenericProvider([
            'clientId'                => env('AZURE_CLIENT_ID'),
            'clientSecret'            => env('AZURE_CLIENT_SECRET'),
            'redirectUri'             => env('AZURE_REDIRECT_URL'),
            'urlAuthorize'            => 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
            'urlAccessToken'          => 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
            'urlResourceOwnerDetails' => '',
            'scopes'                  => 'openid profile offline_access Mail.Read User.Read',
        ]);
    }

    // public function generateCodeVerifier()
    // {
    //     return bin2hex(random_bytes(64));
    // }

    // public function generateCodeChallenge($codeVerifier)
    // {
    //     return rtrim(strtr(base64_encode(hash('sha256', $codeVerifier, true)), '+/', '-_'), '=');
    // }

    public function redirectToProvider()
    {
        // Generate a random state string and store it in the session
        $state = Str::random(40);
        Session::put('oauth2state', $state);
    
        // Prepare the authorization URL
        $authorizationUrl = $this->provider->getAuthorizationUrl([
            'state' => $state
        ]);
    
        // Redirect the user to the authorization URL
        return redirect()->to($authorizationUrl);
    }

 

    public function handleProviderCallback(Request $request)
    {
        // Log the full request data for debugging
        Log::info('Callback Request Data:', $request->all());
    
        // Retrieve the expected state from the session
        $expectedState = session('oauth2state');
        Log::info('Expected State:', ['expectedState' => $expectedState]);
    
        // Check if the state from the request matches the expected state (for CSRF protection)
        if (!$expectedState || $expectedState !== $request->state) {
            session()->forget('oauth2state');
            abort(400, 'Invalid state');
        }
    
        // Get an access token using the authorization code
        try {
            $accessToken = $this->provider->getAccessToken('authorization_code', [
                'code' => $request->code,
            ]);
            
            Log::info('Access Token:', ['accessToken' => $accessToken]);
            Session::put('accessToken', $accessToken->getToken());
    
            // Use the access token to make API requests (e.g., to Microsoft Graph)
            $graph = new Graph();
            $graph->setAccessToken($accessToken->getToken());
    
            // Fetch the user profile from Microsoft Graph
            $user = $graph->createRequest('GET', '/me')
                ->setReturnType(User::class)
                ->execute();
    
            // Fetch user emails from multiple folders
            $inboxMessages = $graph->createRequest('GET', '/me/mailFolders/inbox/messages')
                ->setReturnType(Message::class)
                ->execute();
            
            $sentMessages = $graph->createRequest('GET', '/me/mailFolders/sentitems/messages')
                ->setReturnType(Message::class)
                ->execute();
    
            $draftMessages = $graph->createRequest('GET', '/me/mailFolders/drafts/messages')
                ->setReturnType(Message::class)
                ->execute();
                $deleteditems = $graph->createRequest('GET', '/me/mailFolders/deleteditems/messages')
                ->setReturnType(Message::class)
                ->execute();       
    
    
            // Log email data (for debugging)
            Log::info('User Emails', [
                'inbox' => $inboxMessages,
                'sent' => $sentMessages,
                'drafts' => $draftMessages,
                'delete' => $deleteditems,
            ]);
    
            // Pass data to Blade view
            return view('mailbox_outlook', [
                'inboxMessages' => $inboxMessages,
                'sentMessages' => $sentMessages,
                'draftMessages' => $draftMessages,
                'deleteditems' =>$deleteditems
            ]);
    
        } catch (IdentityProviderException $e) {
            // Log the error if the token retrieval fails
            Log::error('Error during access token retrieval:', ['error' => $e->getMessage()]);
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }
    
    public function listMails()
    {
        $accessToken = session('accessToken');
        if (!$accessToken) {
            Log::warning('No access token found in session');
            return redirect()->route('login');
        }
    
        $graph = new Graph();
        $graph->setAccessToken($accessToken);
     // Get the search query from the request
        try {
            // Fetch emails from different folders
            $inboxMessages = $graph->createRequest('GET', '/me/mailFolders/inbox/messages')
                                   ->setReturnType(Model\Message::class)
                                   ->execute();
    
            $sentMessages = $graph->createRequest('GET', '/me/mailFolders/sentitems/messages')
                                  ->setReturnType(Model\Message::class)
                                  ->execute();
    
            $draftMessages = $graph->createRequest('GET', '/me/mailFolders/drafts/messages')
                                   ->setReturnType(Model\Message::class)
                                   ->execute();
            $deleteditems = $graph->createRequest('GET', '/me/mailFolders/deleteditems/messages')
                                   ->setReturnType(Model\Message::class)
                                   ->execute();
    
            Log::info('Emails fetched successfully', [
                'inbox' => $inboxMessages,
                'sent' => $sentMessages,
                'drafts' => $draftMessages
            ]);
    
            return view('mailbox_outlook', [
                'inboxMessages' => $inboxMessages,
                'sentMessages' => $sentMessages,
                'draftMessages' => $draftMessages,
                'deleteditems'  => $deleteditems
            ]);
    
        } catch (GraphException $e) {
            Log::error('Failed to fetch emails', ['exception' => $e->getMessage()]);
            return redirect()->back()->with('error', 'Failed to fetch emails');
        }
    }
    public function sendMail(Request $request)
    {
        // Validate request input
        $request->validate([
            'to' => 'required|email',
            'subject' => 'required|string',
            'body' => 'required|string',
        ]);

        // Retrieve access token
        $accessToken = session('accessToken');

        Log::info('reached accessToken',['accessToken'=>$accessToken]);

        if (!$accessToken) {
            return redirect()->route('auth.redirect')->with('error', 'Please authenticate first.');
        }

        // Initialize Graph API
        $graph = new Graph();
        $graph->setAccessToken($accessToken);

        // Prepare email data
        $emailData = [
            "message" => [
                "subject" => $request->input('subject'),
                "body" => [
                    "contentType" => "Text",
                    "content" => trim($request->input('body')),
                ],
                "toRecipients" => [
                    [
                        "emailAddress" => [
                            "address" => $request->input('to'),
                        ]
                    ]
                ],
            ],
            "saveToSentItems" => true
        ];
        Log::info('reached graph',['emailData'=>$emailData]);

        try {
            $response=$graph->createRequest("POST", "/me/sendMail")
                ->attachBody($emailData)
                ->setReturnType(Message::class)
                ->execute();
Log::info('reached graph',['graph'=>$graph]);
                
        return response()->json([
            'success' => true,
            'message' => 'Email sent successfully!',
        ]);
            } catch (\Exception $e) {
            Log::error("Microsoft Graph API Error: " . $e->getMessage());
            return response()->json([
                'success' => false,
                'error' => 'Error sending email. Please try again later.',
                'details' => $e->getMessage()
            ], 500);        }
    }
}
