<?php

namespace App\Classes;

use App\Models\Setting;
use Carbon\Carbon;
use DateTime;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class Calendly
{

    protected $clientId = "1SW4eLp_g-nFim1XOORcAh-2lH2H-dfUVCiB1tLpkvo";
    protected $clientSecret = "qXtkthnPxdCoHzVekWsgKr1QEH2q5nm5B3R81x6IG28";
    //protected $redirectUri = 'https://hgh.codelfi.com/calendly/redirect-code/';
    public function authUrl()
    {
        $url = 'https://auth.calendly.com/oauth/authorize';
        $url .= '?client_id=' . urlencode($this->clientId);
        $url .= '&response_type=code';
        $url .= '&redirect_uri=' . urlencode(route('redirectURI'));
        //$url .= '&redirect_uri=' . urlencode('https://app.example.com/calendly/redirect-code/');

        return $url;
    }
    public function authorize($code)
    {
        $tokenUrl = 'https://auth.calendly.com/oauth/token';

        $client = new Client();

        try {
            $response = $client->post($tokenUrl, [
                'form_params' => [
                    'grant_type' => 'authorization_code',
                    'client_id' => $this->clientId,
                    'client_secret' => $this->clientSecret,
                    'redirect_uri' => route("redirectURI"),
                    //'redirect_uri' => 'https://app.example.com/calendly/redirect-code/',
                    'code' => $code,
                ],
                'headers' => [
                    'Content-Type' => 'application/x-www-form-urlencoded',
                ],
            ]);

            $data = json_decode($response->getBody()->getContents(), true);
            Log::info('Info from function authorize(): ',  $data);
            $setting = Setting::find(1);
            $setting->calendly_access_token = $data['access_token'];
            $setting->calendly_refresh_token = $data['refresh_token'];
            $setting->save();
            Cache::forget('calendly_access_token');
            Cache::put('calendly_access_token', $data['access_token'], now()->addSeconds($data['expires_in']));

            return [
                'access_token' => $data['access_token'],
                'refresh_token' => $data['refresh_token'],
                'token_type' => $data['token_type'],
                'expires_in' => $data['expires_in']
            ];
        } catch (\Exception $e) {
            throw $e;
        }
    }
    public function accessToken()
    {

        if (Cache::has('calendly_access_token')) {
            return Cache::get('calendly_access_token');
        }

        $setting = Setting::find(1);

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

        $client = new Client();

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

        // Decode the response
        $data = json_decode($response->getBody()->getContents(), true);
        Log::info('Info from function accessToken(): ',  $data);
        // Store the new access token and refresh token in cache
        Cache::put('calendly_access_token', $data['access_token'], now()->addSeconds($data['expires_in']));

        return $data['access_token'];
    }
    public function getUserUri()
    {
        // 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 ' . $this->accessToken(),
                    'Content-Type' => 'application/json',
                ]
            ]);

            $data = json_decode($response->getBody(), true);
            return $userUri = $data['resource']['uri'];
        } catch (\Exception $e) {
            return false;
        }
    }
    public function eventTypes()
    {
        // 1. Call the /users/me API to get user information
        $client = new Client();
        $responseEvent = $client->request('GET', 'https://api.calendly.com/event_types?user=' . $this->getUserUri(), [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken(),
                'Content-Type' => 'application/json',
            ]
        ]);
        $dataEvent = json_decode($responseEvent->getBody(), true);
        return  $dataEvent['collection'];
    }
    public function setEventUri($even_type_url)
    {
        $setting = Setting::find(1);
        $setting->event_type = $even_type_url;
        $setting->save();
    }
    public function resetEventUri()
    {
        $setting = Setting::find(1);
        $setting->event_type = null;
        $setting->calendly_access_token = null;
        $setting->calendly_refresh_token = null;

        $setting->save();
    }
    function getAvailableDates($even_type_url, $month, $tz = "UTC")
    {

        try {
            $availableTimes = [];

            $date = Carbon::createFromDate(Carbon::now()->year, $month, 1, $tz);
            $date =    $date->startOfMonth()->tz("UTC");
            $endMonthDate = Carbon::createFromDate(Carbon::now()->year, $month, 1, $tz);
            $endMonthDate =    $endMonthDate->endOfMonth()->tz("UTC");


            while ($date < $endMonthDate) {
                $start_time = $date->startOfDay()->format('Y-m-d\T24:00:00.000000\Z');
                $end_time = $date->addDays(7)->endOfDay()->format('Y-m-d\T24:00:00.000000\Z');


                $client = new Client();
                try {

                    // Prepare API endpoint with the required parameters
                    $eventTypeUrl = 'https://api.calendly.com/event_type_available_times';
                    $queryParams = [
                        'event_type' => $even_type_url,
                        'start_time' => $start_time,
                        'end_time' => $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 ' . $this->accessToken(),
                            'Content-Type' => 'application/json',
                        ],
                        // 'query' => $queryParams
                    ]);


                    $data = json_decode($response->getBody(), true);
                    //$availableTimes += $data['collection'];
                    foreach ($data['collection'] as $slot) {
                        $slotDate = Carbon::parse($slot['start_time'])->tz($tz)->format('Y-m-d');
                        if (!isset($availableTimes[$slotDate])) {
                            $availableTimes[$slotDate] = [];
                        }
                        $slotDateTime = Carbon::parse($slot['start_time'])->tz($tz);
                        $dateKey = $slotDateTime->format('Y-m-d');
                        $slot['formatted_datetime'] = $slotDateTime->format('Y-m-d g:i:00');
                        $availableTimes[$slotDate][] = $slot;
                    }
                } catch (Exception $e) {
                    Log::error('Error from function getAvailableDates(): ' . $e->getMessage(), [
                        'eventTypeUrl' => $eventTypeUrl,
                        'queryParams' => $queryParams,
                        'full_rul' => $eventTypeUrl,

                        'Authorization' => 'Bearer ' . $this->accessToken(),
                    ]);
                    continue;
                }
                $date->addSecond();
            }

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



    // write function to do php get and post request and add json support
    function makeRequest($url, $method = 'GET', $data = [], $headers = [], $json = false, $proxy = "iproyal15202:pb86ljih495_country-us@geo.iproyal.com:12321")
    {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch,  CURLOPT_ENCODING, '',);
        if ($proxy) {
            curl_setopt($ch, CURLOPT_PROXY, 'http://geo.iproyal.com:12321'); // Set the proxy address and port
            curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'iproyal15202:Pb86ljiH495_country-us'); // Set the proxy authentication credentials
        }
        $headers = ['User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36', ...$headers];
        if ($method === 'POST') {

            if ($json) {
                $headers = ['Content-Type: application/json',  ...$headers];
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            } else {
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            }
        }
        if (!empty($headers)) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }

        $response = curl_exec($ch);
        curl_close($ch);

        return $response;
    }


    function getCrfToken($url)
    {
        $response = $this->makeRequest($url);

        // var_dump($response);
        //<meta name="csrf-token" content="mTW6eNk5xiDTzby7yHl_iVTO1_pi-CXZ2U9MYPcXGJGMpksW4iGLJniNxs-T4xrmYlLbXFaLuU8FZ75cuorz8w" />
        preg_match('/<meta name="csrf-token" content="(.*?)" \/>/', $response, $matches);
        return $matches[1];
    }

    function getEventDetails($url)
    {
        $response = $this->makeRequest($url);
        return $response;
    }

    //random string function
    function generateRandomString($length = 10)
    {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, strlen($characters) - 1)];
        }
        return $randomString;
    }


    public function bookEvent($url, $name, $email, $timezone = "UTC")
    {
        $url_parts = explode("/", $url);
        $bookingDate = $url_parts[5];
        $event_type = $url_parts[4];
        $owner_id = $url_parts[3];
        $eventDetailsUrl = "https://calendly.com/api/booking/profiles/$owner_id/event_types/$event_type";
        $eventDetails = json_decode($this->makeRequest($eventDetailsUrl));
        // var_dump($eventDetails);
        $crfToken = $this->getCrfToken($url);

        $eventUuid = $eventDetails->uuid;
        $link_uuid = $eventDetails->scheduling_link->uid;
        $custom_fields_id = $eventDetails->custom_fields[0]->id;
        $booking_request_id = urlencode($this->generateRandomString(36) . "|$bookingDate|$eventUuid|$name");
        //convert to php array
        $bookingData = [
            "analytics" => [
                //php date with 10 sec gap
                "invitee_landed_at" => date("Y-m-d\TH:i:s.uP", strtotime($bookingDate) - 200),
                "browser" => "Chrome 129",
                "device" => "undefined Mac OS X 10.15.7",
                "fields_filled" => 1,
                "fields_presented" => 1,
                "booking_flow" => "v3",
                "seconds_to_convert" => 200
            ],
            "embed" => [],
            "event" => [
                "start_time" => $bookingDate,
                "location_configuration" => [
                    "location" => "",
                    "phone_number" => "",
                    "additional_info" => ""
                ],
                "guests" => []
            ],
            "event_fields" => [
                [
                    "id" => $custom_fields_id,
                    "name" => "Please share anything that will help prepare for our meeting.",
                    "format" => "text",
                    "required" => false,
                    "position" => 0,
                    "answer_choices" => null,
                    "include_other" => false,
                    "value" => ""
                ]
            ],
            "invitee" => [
                "timezone" => $timezone,
                "time_notation" => "24h",
                "full_name" => $name,
                "email" => $email
            ],
            "payment_token" => [],
            "tracking" => [
                "fingerprint" => $this->generateRandomString(32)
            ],
            "scheduling_link_uuid" => $link_uuid,
            "locale" => "en",
            "verification_code" => null,
            "remember_device" => false
        ];


        $response = $this->makeRequest("https://calendly.com/api/booking/invitees", 'POST', $bookingData, [
            'x-csrf-token: ' . $crfToken,
            'x-page-rendered-at: ' . date('Y-m-d\TH:i:s'),
            'x-requested-with: XMLHttpRequest',
            'referer: ' . $url,
            "booking-request-id: $booking_request_id"
        ], true);

        return $response;
    }
}
