<?php

namespace App\Http\Controllers\Admin\Api;

use App\Http\Controllers\Controller;
use Carbon\Carbon;
use DateTime;
use Illuminate\Http\Request;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Cache;

class CalendlyControllerOld extends Controller
{
    protected $clientId = "eOk7Vb-60_l6U4WmAe9y9MThi-WKGzEuyru_B3I2jwk";
    protected $clientSecret = "EYLgGEHLudI65wdqG7Qz1azZwFCFx8kvikXYoM2EbiE";
    protected $redirectUri = 'https://hgh.codelfi.com/calendly/redirect-code/';

    // Generate Calendly authorization URL
    public function getCalendlyAuthUrl()
    {
        $url = 'https://auth.calendly.com/oauth/authorize';
        $url .= '?client_id=' . urlencode($this->clientId);
        $url .= '&response_type=code';
        $url .= '&redirect_uri=' . urlencode($this->redirectUri);

        return response()->json(['url' => $url]);
    }

    // Handle the redirect with authorization code and exchange for access token
    public function getRedirectCode(Request $request)
    {
        // Get the authorization code from the request
        $authorizationCode = $request->input('code');

        if (!$authorizationCode) {
            return response()->json(['error' => 'Authorization code is missing'], 400);
        }
        //return $this->getCalendlyUserAndAvailability();
        // Call method to fetch access token and cache it
        $this->getAccessTokenFromCode($authorizationCode);
        return response()->json(['message' => 'Admin has been authenticated.'], 200);
    }
    // Handle the redirect with authorization code and exchange for access token
    public function getAvailabeSlotDates(Request $request)
    {
        return $this->getCalendlyUserAndAvailability();
        // Call method to fetch access token and cache it
    }

    // Fetch or refresh access token if needed
    public function getAccessToken()
    {
        // Check if the access token exists in cache
        if (Cache::has('calendly_access_token')) {
            return Cache::get('calendly_access_token');
        }

        // If no token is available, return error or trigger refresh
        return response()->json(['error' => 'No valid access token. Please authenticate again.'], 401);
    }

    // Exchange authorization code for access token and store it in cache
    private function getAccessTokenFromCode($authorizationCode)
    {
        $tokenUrl = 'https://auth.calendly.com/oauth/token';

        // Use GuzzleHttp client to make the POST request
        $client = new Client();

        try {
            $response = $client->post($tokenUrl, [
                'form_params' => [
                    'grant_type' => 'authorization_code',
                    'client_id' => $this->clientId,
                    'client_secret' => $this->clientSecret,
                    'redirect_uri' => $this->redirectUri,
                    'code' => $authorizationCode,
                ],
                'headers' => [
                    'Content-Type' => 'application/x-www-form-urlencoded',
                ],
            ]);

            // Decode the JSON response
            $data = json_decode($response->getBody()->getContents(), true);

            // Store access token and refresh token in cache with an expiration
            //Cache::put('calendly_access_token', $data['access_token'], now()->addSeconds($data['expires_in']));
            //Cache::put('calendly_refresh_token', $data['refresh_token'], now()->addDays(30)); // Refresh tokens don't expire until used

            return response()->json([
                'access_token' => $data['access_token'],
                'refresh_token' => $data['refresh_token'],
                'token_type' => $data['token_type'],
                'expires_in' => $data['expires_in']
            ]);
        } catch (\Exception $e) {
            // Handle errors
            return response()->json(['error' => 'Failed to fetch access token: ' . $e->getMessage()], 500);
        }
    }

    // Use refresh token to get a new access token when expired
    private function refreshAccessToken()
    {
        if (!Cache::has('calendly_refresh_token')) {
            return response()->json(['error' => 'Refresh token not available.'], 401);
        }

        $refreshToken = Cache::get('calendly_refresh_token');

        $tokenUrl = 'https://auth.calendly.com/oauth/token';

        $client = new Client();

        try {
            $response = $client->post($tokenUrl, [
                'form_params' => [
                    'grant_type' => 'refresh_token',
                    'client_id' => $this->clientId,
                    'client_secret' => $this->clientSecret,
                    'refresh_token' => $refreshToken,
                ],
                'headers' => [
                    'Content-Type' => 'application/x-www-form-urlencoded',
                ],
            ]);

            // Decode the response
            $data = json_decode($response->getBody()->getContents(), true);

            // Store the new access token and refresh token in cache
            Cache::put('calendly_access_token', $data['access_token'], now()->addSeconds($data['expires_in']));
            Cache::put('calendly_refresh_token', $data['refresh_token'], now()->addDays(30)); // New refresh token

            return $data['access_token'];
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to refresh access token: ' . $e->getMessage()], 500);
        }
    }

    function getCalendlyUserAndAvailability()
    {
        // Get the access token from cache
        $accessToken = Cache::get('calendly_access_token');

        // If the token is not in cache, fetch a new one
        if (!$accessToken) {
            $accessToken = $this->fetchCalendlyAccessToken();
        }

        if (!$accessToken) {
            return response()->json(['error' => 'Token Expired!'], 500);
        }

        // 1. Call the /users/me API to get user information
        $client = new Client();
        try {
            $response = $client->request('GET', 'https://api.calendly.com/users/me', [
                'headers' => [
                    'Authorization' => 'Bearer ' . $accessToken,
                    'Content-Type' => 'application/json',
                ]
            ]);

            $data = json_decode($response->getBody(), true);
            $userUri = $data['resource']['uri'];
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to fetch user details: ' . $e->getMessage()], 500);
        }

        // 2. Use the user URI to fetch availability schedules
        try {
            $availabilityResponse = $client->request('GET', 'https://api.calendly.com/user_availability_schedules', [
                'headers' => [
                    'Authorization' => 'Bearer ' . $accessToken,
                    'Content-Type' => 'application/json',
                ],
                'query' => [
                    'user' => $userUri
                ]
            ]);

            $availabilityData = json_decode($availabilityResponse->getBody(), true);
            // Get the rules from the availability data
            $rules = $availabilityData['collection'][0]['rules'];

            // Map day of the week to the date in the current week
            $weekDates = $this->getCurrentWeekDates();  // Get this week's dates

            // Add the corresponding date to each rule
            $updatedRules = array_map(function ($rule) use ($weekDates) {
                $wday = $rule['wday'];
                // Check if we have a corresponding date for this weekday
                if (isset($weekDates[$wday])) {
                    $rule['date'] = $weekDates[$wday];  // Add date to the rule
                } else {
                    $rule['date'] = null;  // No availability on that day
                }
                return $rule;
            }, $rules);

            // Add the updated rules with dates back to the response
            $availabilityData['collection'][0]['rules'] = $updatedRules; // Get the rules from the availability data
            $rules = $availabilityData['collection'][0]['rules'];

            // Map day of the week to the date in the current week
            $weekDates = $this->getCurrentWeekDates();  // Get this week's dates

            // Add the corresponding date to each rule
            $updatedRules = array_map(function ($rule) use ($weekDates) {
                $wday = $rule['wday'];
                // Check if we have a corresponding date for this weekday
                if (isset($weekDates[$wday])) {
                    $rule['date'] = $weekDates[$wday];  // Add date to the rule
                } else {
                    $rule['date'] = null;  // No availability on that day
                }
                return $rule;
            }, $rules);

            $filteredDates = array_values(array_filter(array_map(function ($rule) {
                return !empty($rule['intervals']) ? $rule['date'] : null;
            }, $updatedRules)));
            // Add the updated rules with dates back to the response
            $availabilityData['collection'][0]['rules'] = $updatedRules;
            return response()->json($availabilityData, 200);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to fetch availability: ' . $e->getMessage()], 500);
        }
    }
    private function getCurrentWeekDates()
    {
        $weekDates = [];

        // Start from Sunday as 0, loop through the week
        for ($day = 0; $day < 7; $day++) {
            $carbonDate = Carbon::now()->startOfWeek()->addDays($day);  // Start on Sunday
            $weekday = strtolower($carbonDate->format('l'));  // Get the day name (sunday, monday, etc.)
            $weekDates[$weekday] = $carbonDate->toDateString();  // Store the date for that day
        }

        return $weekDates;  // Return array of week dates
    }
    // Helper function to fetch access token
    function fetchCalendlyAccessToken()
    {
        $client = new Client();
        try {
            $response = $client->post('https://auth.calendly.com/oauth/token', [
                'form_params' => [
                    'grant_type' => 'authorization_code',
                    'client_id' => $this->clientId,
                    'client_secret' => $this->clientSecret,
                    'redirect_uri' => $this->redirectUri,
                    'code' => request()->input('code'), // Get authorization code from request
                ],
                'headers' => [
                    'Content-Type' => 'application/x-www-form-urlencoded',
                ]
            ]);

            $data = json_decode($response->getBody(), true);
            $accessToken = $data['access_token'];

            // Store access token in cache for 2 hours
            Cache::put('calendly_access_token', $accessToken, 120 * 60);

            return $accessToken;
        } catch (\Exception $e) {
            return null;
        }
    }
    public function getAvailableTimes(Request $request)
    {
        try {
            // Validate start_time and end_time input
            /* $validatedData = $request->validate([
                'start_time' => 'required|date_format:Y-m-d\TH:i:s\Z',
                'end_time' => 'required|date_format:Y-m-d\TH:i:s\Z',
            ]); */

            // Get the access token from cache
            $accessToken = Cache::get('calendly_access_token');

            // If the token is not in cache, fetch a new one
            if (!$accessToken) {
                $accessToken = $this->fetchCalendlyAccessToken();
            }

            if (!$accessToken) {
                return response()->json(['error' => 'Unable to retrieve access token'], 500);
            }

            // 1. Call the /users/me API to get user information
            $client = new Client();
            $response = $client->request('GET', 'https://api.calendly.com/users/me', [
                'headers' => [
                    'Authorization' => 'Bearer ' . $accessToken,
                    'Content-Type' => 'application/json',
                ]
            ]);

            $data = json_decode($response->getBody(), true);
            $userUri = $data['resource']['uri'];

            // 1. Call the /users/me API to get user information
            $client = new Client();
            $responseEvent = $client->request('GET', 'https://api.calendly.com/event_types?user=' . $userUri, [
                'headers' => [
                    'Authorization' => 'Bearer ' . $accessToken,
                    'Content-Type' => 'application/json',
                ]
            ]);

            $dataEvent = json_decode($responseEvent->getBody(), true);
            $even_type_url = $dataEvent['collection'][0]['uri'];
            $userUri = $data['resource']['uri'];


            $client = new Client();

            // Prepare API endpoint with the required parameters
            $eventTypeUrl = 'https://api.calendly.com/event_type_available_times';
            $queryParams = [
                'event_type' => $even_type_url, //'https://api.calendly.com/event_types/60992c14-2f0b-42c2-af7b-95062d065600', // Use your event_type URL
                'start_time' => $request->input('start_time'),
                'end_time' => $request->input('end_time')
            ];
            $str = "event_type=" . urlencode($queryParams['event_type']) . "&" .  "start_time=" . urlencode($queryParams['start_time']) . "&" .  "end_time=" . urlencode($queryParams['end_time']);
            $eventTypeUrl = $eventTypeUrl . "?" . ($str);
            // Send the request to Calendly
            $response = $client->request('GET', $eventTypeUrl, [
                'headers' => [
                    'Authorization' => 'Bearer ' . $accessToken,
                    'Content-Type' => 'application/json',
                ],
                // 'query' => $queryParams
            ]);

            $data = json_decode($response->getBody(), true);
            $processedTimes = array_map(function ($item) {
                $dateTime = new DateTime($item['start_time']);
                $readableTime = $dateTime->format('Y-m-d H:i'); // Format: YYYY-MM-DD h:mm AM/PM

                return [
                    'status' => $item['status'],
                    'start_time' => $readableTime,
                    'invitees_remaining' => $item['invitees_remaining'],
                    'scheduling_url' => $item['scheduling_url']
                ];
            }, $data['collection']);

            // Extract scheduling URLs from available time slots
            $availableTimes = array_map(function ($slot) {
                return $slot['scheduling_url'];
            }, $data['collection']);

            return response()->json([
                'available_times' => $processedTimes
            ], 200);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to fetch available times: ' . $e->getMessage()], 500);
        }
    }
}
