<?php

namespace App\Services\Integrations\GoogleWorkspace;

use App\Models\ApiCredential;
use Exception;
use Firebase\JWT\JWT;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class GoogleWorkspaceIntegration
{

    /**
     * generate access token by passing JWT to google api
     */
    public function getAccessTokenWithJwt($serviceConfig)
    {
        try {
            $jwt = $this->generateJwt($serviceConfig);
            $response = Http::asForm()->post('https://oauth2.googleapis.com/token', [
                'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
                'assertion' => $jwt,
            ])->throw()->json();

            if ($response) {
                return $response['access_token'] ?? false;
            }
        } catch (Exception $e) {
            Log::channel('daily')->error("Google workspace - $serviceConfig - connection error:- " . $e->getMessage() . ' ' . $e->getLine() . ' ' . $e->getFile());
        }

        return false;
    }

    /**
     * creates JSON Web Token
     */
    public function generateJwt($serviceConfig)
    {
        $now = time();
        $credentialsPath = storage_path('keys/' . $serviceConfig . '_client_secret.json');
        $credentials = json_decode(file_get_contents($credentialsPath), true);
        $privateKey = str_replace('\n', "\n", $credentials['private_key']);
        $adminEmail = optional(ApiCredential::whereSlug(config('services.google_workspace.' . $serviceConfig . '.slug'))->first())->user_name; //The email address of the user for which the application is requesting delegated access.

        $payload = [
            'iss' => $credentials['client_email'],
            'sub' => $adminEmail,
            'aud' => $credentials['token_uri'] ?? 'https://oauth2.googleapis.com/token',
            'iat' => $now,
            'exp' => $now + 3600, // Token valid for 1 hour
            'scope' =>  config('services.google_workspace.' . $serviceConfig . '.scope'),
        ];

        $jwt = JWT::encode($payload, $privateKey, config('services.google_workspace.' . $serviceConfig . '.alg'));

        return $jwt;
    }

    /**
     * Get the Chrome os devices account customer id
     *	
     * @param $client   Google Auth 2 Client
     * @return Mixed
     */
    public function getCustomerId($client)
    {
        $credential = ApiCredential::where('slug', 'google_workspace')->first();
        $token      = $client ? $client->getAccessToken()['access_token'] : '';

        try {
            $response = Http::withToken($token)
                ->retry(3, 3000)
                ->get("https://www.googleapis.com/admin/directory/v1/users/" . $credential->user_name)
                ->throw()
                ->json();

            return $response ? $response['customerId'] : false;
        } catch (Exception $e) {
            return false;
        }

        return false;
    }

    /**
     * Get the Google Directory Users
     *	
     * @param string $token The access token
     * @param string $pageToken The page token
     * @return array|false The list of resources or false if an error occurred
     */
    public function getDirectoryUsers($token, $pageToken)
    {
        $optParams = [
            'pageToken' => '',
            'maxResults' => 200
        ];

        $apiUrl = "https://admin.googleapis.com/admin/directory/v1/users?customer=my_customer&maxResults=" . $optParams['maxResults'];

        if ($pageToken != '') {
            $optParams['pageToken'] = $pageToken;
            $apiUrl .= "&pageToken=" . $optParams['pageToken'];
        }

        $pageToken = '';

        try {
            $response = Http::withToken($token)
                ->retry(3, 3000)
                ->get($apiUrl)
                ->throw()
                ->json();

            return $response;
        } catch (Exception $e) {
            // dd($e->getMessage(), $e->getLine(), $e->getFile());
            Log::channel('daily')->error("Google directory connection error:- " . $e->getMessage());

            return false;
        }
    }

    /**
     * Retrieves the list of Google Workspace resources (gsuite locations)
     *	
     * @param string $token The access token
     * @param string $pageToken The page token
     * @return array|false The list of resources or false if an error occurred
     */
    public function getGsuiteLocations($token, $pageToken)
    {
        $optParams = [
            'orderBy' => 'buildingId',
            'pageToken' => '',
            'query' => '',
            'maxResults' => 100,
        ];

        $apiUrl = "https://admin.googleapis.com/admin/directory/v1/customer/my_customer/resources/calendars?maxResults=" . $optParams['maxResults'];

        if ($pageToken != '') {
            $optParams['pageToken'] = $pageToken;
            $apiUrl .= "&pageToken=" . $optParams['pageToken'];
        }
        $pageToken = '';

        try {
            $response = Http::withToken($token)
                ->retry(3, 3000)
                ->get($apiUrl)
                ->throw()
                ->json();

            return $response;
        } catch (Exception $e) {
            Log::channel('daily')->error("Gsuite locations connection error:- " . $e->getMessage());

            return false;
        }
    }

    /**
     * Retrieves the list of Google Workspace Chrome OS devices
     *	
     * @param string $token The access token
     * @param string $pageToken The page token
     * @return array|false The list of Chrome OS devices or false if an error occurred
     */
    public function getChromeOsdevices($token, $pageToken)
    {
        $optParams = [
            'pageToken' => '',
            'maxResults' => 200
        ];

        $apiUrl = "https://www.googleapis.com/admin/directory/v1/customer/my_customer/devices/chromeos?maxResults=" . $optParams['maxResults'];

        if ($pageToken != '') {
            $optParams['pageToken'] = $pageToken;
            $apiUrl .= "&pageToken=" . $optParams['pageToken'];
        }

        $pageToken = '';

        try {
            $response = Http::withToken($token)
                ->retry(3, 3000)
                ->get($apiUrl)
                ->throw()
                ->json();

            return $response;
        } catch (Exception $e) {
            Log::channel('daily')->error("Chrome OS MDM connection error:- " . $e->getMessage());

            return false;
        }
    }
}
