<?php

namespace app\service;

use app\util\Helper;
use app\util\ArgumentNames;
use app\util\ArgumentParser;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsException;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsServerStreamDecorator;
use Google\Ads\GoogleAds\Util\FieldMasks;
use Google\Ads\GoogleAds\Util\V18\ResourceNames;
use Google\Ads\GoogleAds\V18\Enums\AccessRoleEnum\AccessRole;
use Google\Ads\GoogleAds\V18\Enums\ManagerLinkStatusEnum\ManagerLinkStatus;
use Google\Ads\GoogleAds\V18\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V18\Resources\CustomerClient;
use Google\Ads\GoogleAds\V18\Resources\CustomerUserAccess;
use Google\Ads\GoogleAds\V18\Services\Client\CustomerServiceClient;

//use Google\Ads\GoogleAds\V18\Services\CustomerServiceClient;
use Google\Ads\GoogleAds\V18\Services\CustomerUserAccessOperation;
use Google\Ads\GoogleAds\V18\Services\GoogleAdsRow;
use Google\Ads\GoogleAds\V18\Services\ListAccessibleCustomersRequest;
use Google\Ads\GoogleAds\V18\Services\MutateCustomerUserAccessRequest;
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsStreamRequest;
use Google\Ads\GoogleAds\V18\Resources\CustomerClientLink;
use Google\Ads\GoogleAds\V18\Resources\CustomerManagerLink;
use Google\Ads\GoogleAds\V18\Services\CustomerClientLinkOperation;
use Google\Ads\GoogleAds\V18\Services\CustomerManagerLinkOperation;
use Google\Ads\GoogleAds\V18\Services\MutateCustomerClientLinkRequest;
use Google\Ads\GoogleAds\V18\Services\MutateCustomerManagerLinkRequest;
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsRequest;
use Google\ApiCore\ApiException;

class GoogleAdsAccountService extends BaseService
{
//    private $googleAdsClient;
//    private $customerId;
//    private const NUMBER_OF_CAMPAIGNS_TO_ADD = 1;
//    private $loginCustomerId; // 增加 login-customer-id 属性

    // Stores the mapping from the root customer IDs (the ones that will be used as a start point
    // for printing each hierarchy) to their `CustomerClient` objects.
    private static array $rootCustomerClients = []; //必须在入口初始化空数组

    public function __construct()
    {
//        $this->customerId = getenv('GOOGLE_ADS_CUSTOMER_ID');
//
//        // OAuth2 Token Authentication
//        $oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();
//
//        // Google Ads Client initialization
//        $this->googleAdsClient = (new GoogleAdsClientBuilder())
//            ->fromFile()
//            ->withOAuth2Credential($oAuth2Credential)
//            ->build();
    }

    /**
     * Runs the example.
     *
     * @param $options
     *  This example assumes that the same credentials will work for both customers,
     *   but that may not be the case. If you need to use different credentials
     *   for each customer, then you may either update the client configuration or
     *   instantiate the clients accordingly, one for each set of credentials. Always make
     *   sure to update the configuration before fetching any services you need to use.
     * //     * @return mixed
     * @throws ApiException
     */
    public function runLinkManagerToClient($options)
    {

        // Extends an invitation to the client while authenticating as the manager.
        $managerCustomerId = $options['manager_customer_id'];
        $clientCustomerId  = $options['client_customer_id'];


        // Extends an invitation to the client while authenticating as the manager.
        $customerClientLinkResourceName = self::createInvitation(
            $managerCustomerId,
            $clientCustomerId

        );

        // Retrieves the manager link information.
        $managerLinkResourceName = self::getManagerLinkResourceName(
            $managerCustomerId,
            $clientCustomerId,
            $customerClientLinkResourceName
        );

        // Accepts the manager's invitation while authenticating as the client.
        return self::acceptInvitation($clientCustomerId, $managerLinkResourceName);


    }

    /**
     * Extends an invitation from a manager customer to a client customer.
     *
     * @param int $managerCustomerId the manager customer ID
     * @param int $clientCustomerId the customer ID
     * @return string the resource name of the customer client link created for the invitation
     */
    public function createInvitation(
        int $managerCustomerId,
        int $clientCustomerId
    )
    {

        // Creates a client with the manager customer ID as login customer ID.
        $googleAdsClient = $this->createGoogleAdsClient($managerCustomerId);

        // Creates a customer client link.
        $customerClientLink = new CustomerClientLink([
            // Sets the client customer to invite.
            'client_customer' => ResourceNames::forCustomer($clientCustomerId),
            'status' => ManagerLinkStatus::PENDING
        ]);

        // Creates a customer client link operation for creating the one above.
        $customerClientLinkOperation = new CustomerClientLinkOperation();
        $customerClientLinkOperation->setCreate($customerClientLink);

        // Issues a mutate request to create the customer client link.
        $customerClientLinkServiceClient = $googleAdsClient->getCustomerClientLinkServiceClient();
        $response                        = $customerClientLinkServiceClient->mutateCustomerClientLink(
            MutateCustomerClientLinkRequest::build(
                $managerCustomerId,
                $customerClientLinkOperation
            )
        );

        // Prints the result.
        $customerClientLinkResourceName = $response->getResult()->getResourceName();
        printf(
            "An invitation has been extended from the manager customer %d" .
            " to the client customer %d with the customer client link resource name '%s'.%s",
            $managerCustomerId,
            $clientCustomerId,
            $customerClientLinkResourceName,
            PHP_EOL
        );

        // Returns the resource name of the created customer client link.
        return $customerClientLinkResourceName;
    }

    /**
     * Retrieves the manager link resource name of a customer client link given its resource name.
     *
     * @param int $managerCustomerId the manager customer ID
     * @param int $clientCustomerId the customer ID
     * @param string $customerClientLinkResourceName the customer client link resource name
     * @return string the manager link resource name
     */
    public function getManagerLinkResourceName(
        int    $managerCustomerId,
        int    $clientCustomerId,
        string $customerClientLinkResourceName
    )
    {
        // Creates a client with the manager customer ID as login customer ID.
        $googleAdsClient = $this->createGoogleAdsClient($managerCustomerId);

        // Creates the query.
        $query = "SELECT customer_client_link.manager_link_id FROM customer_client_link" .
            " WHERE customer_client_link.resource_name = '$customerClientLinkResourceName'";

        // Issues a search request.
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        $response               = $googleAdsServiceClient->search(
            SearchGoogleAdsRequest::build($managerCustomerId, $query)
        );

        // Gets the ID and resource name associated to the manager link found.
        $managerLinkId           = $response->getIterator()->current()
            ->getCustomerClientLink()
            ->getManagerLinkId();
        $managerLinkResourceName = ResourceNames::forCustomerManagerLink(
            $clientCustomerId,
            $managerCustomerId,
            $managerLinkId
        );

        // Prints the result.
        printf(
            "Retrieved the manager link of the customer client link:" .
            " its ID is %d and its resource name is '%s'.%s",
            $managerLinkId,
            $managerLinkResourceName,
            PHP_EOL
        );

        // Returns the resource name of the manager link found.
        return $managerLinkResourceName;
    }

    /**
     * Accepts an invitation.
     *
     * @param int $clientCustomerId the customer ID
     * @param string $managerLinkResourceName the resource name of the manager link to accept
     */
    public function acceptInvitation(
        int    $clientCustomerId,
        string $managerLinkResourceName
    )
    {
        // Creates a client with the client customer ID as login customer ID.
        $googleAdsClient = $this->createGoogleAdsClient($clientCustomerId);

        // Creates the customer manager link with the updated status.
        $customerManagerLink = new CustomerManagerLink();
        $customerManagerLink->setResourceName($managerLinkResourceName);
        $customerManagerLink->setStatus(ManagerLinkStatus::ACTIVE);

        // Creates a customer manager link operation for updating the one above.
        $customerManagerLinkOperation = new CustomerManagerLinkOperation();
        $customerManagerLinkOperation->setUpdate($customerManagerLink);
        $customerManagerLinkOperation->setUpdateMask(
            FieldMasks::allSetFieldsOf($customerManagerLink)
        );

        // Issues a mutate request to update the customer manager link.
        $customerManagerLinkServiceClient =
            $googleAdsClient->getCustomerManagerLinkServiceClient();
        $response                         = $customerManagerLinkServiceClient->mutateCustomerManagerLink(
            MutateCustomerManagerLinkRequest::build(
                $clientCustomerId,
                [$customerManagerLinkOperation]
            )
        );

        // Prints the result.
        printf(
            "The client %d accepted the invitation with the resource name '%s'.%s",
            $clientCustomerId,
            $response->getResults()[0]->getResourceName(),
            PHP_EOL
        );
        return $response->getResults()[0]->getResourceName();
    }
    // [END link_manager_to_client]

    /**
     * Creates a Google Ads client based on the default configuration file
     * and a given login customer id.
     *
     * @param int $thirdUserId thirdUser
     * @return GoogleAdsClient the created client
     */
//    public function createGoogleAdsClient(int $thirdUserId)
    public function createGoogleAdsClient($refreshToken)
    {

        // 从数据库获取 access_token
//        $refreshToken = $this->getRefreshTokenFromDatabase($thirdUserId);

        if (!$refreshToken) {
            throw new \Exception("Access token not found for advertiserId: " . $refreshToken);
        }

        // OAuth2 Token Authentication
        $oAuth2Credential = (new OAuth2TokenBuilder())
            ->fromFile() // 如果需要从文件获取其他配置,可以继续使用 fromFile()
            ->withRefreshToken($refreshToken) // 使用动态获取的 access_token
            ->build();


        // Builds and returns the Google Ads client
        return (new GoogleAdsClientBuilder())
            // Sets the properties based on the default properties file
            ->fromFile()
            // eUses the OAuth2 credentials crated above.
            ->withOAuth2Credential($oAuth2Credential)
            // Overrides the login customer ID with the given one.
            ->build();


    }

    /**
     * Creates a Google Ads client based on the default configuration file
     * and a given login customer id.
     *
     * @param int $loginCustomerId the login customer ID
     * @return GoogleAdsClient the created client
     */
//    public function createGoogleAdsClientWithloginCustomerId(int $thirdUserId,int $loginCustomerId)
    public function createGoogleAdsClientWithloginCustomerId($refreshToken, int $loginCustomerId)
    {
//        $advertiserId = getenv('GOOGLE_ADS_CUSTOMER_ID');

        // 从数据库获取 access_token
//        $refreshToken = $this->getRefreshTokenFromDatabase($thirdUserId);

        if (!$refreshToken) {
            throw new \Exception("Access token not found for advertiserId: " . $refreshToken);
        }
        // OAuth2 Token Authentication
        $oAuth2Credential = (new OAuth2TokenBuilder())
            ->fromFile() // 如果需要从文件获取其他配置,可以继续使用 fromFile()
            ->withRefreshToken($refreshToken) // 使用动态获取的 access_token
            ->build();

        // Builds and returns the Google Ads client
        return (
        new GoogleAdsClientBuilder())
            // Sets the properties based on the default properties file
            ->fromFile()
            // eUses the OAuth2 credentials crated above.
            ->withOAuth2Credential($oAuth2Credential)
            // Overrides the login customer ID with the given one.
            ->withLoginCustomerId($loginCustomerId)
            ->build();
    }

    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     */
    // [START list_accessible_customers]
    public function runListAccessibleCustomers($option)
    {
//        $loginCustomerId = $option['customer_id'];
        $refreshToken = $option['refresh_token'];
        // Creates a client with the manager customer ID as login customer ID.
        $googleAdsClient = $this->createGoogleAdsClient($refreshToken);

        $customerServiceClient = $googleAdsClient->getCustomerServiceClient();

        // Issues a request for listing all accessible customers.
        $accessibleCustomers =
            $customerServiceClient->listAccessibleCustomers(new ListAccessibleCustomersRequest());

        $accessibleCustomerIds = [];
        foreach ($accessibleCustomers->getResourceNames() as $customerResourceName) {
            $customer = CustomerServiceClient::parseName($customerResourceName)['customer_id'];
            print $customer . PHP_EOL;
            $accessibleCustomerIds[] = intval($customer);
        }
        return $accessibleCustomerIds;

//        print 'Total results: ' . count($accessibleCustomers->getResourceNames()) . PHP_EOL;

//        $resourceNameArray = [];
//        // Iterates over all accessible customers' resource names and prints them.
//        foreach ($accessibleCustomers->getResourceNames() as $resourceName) {
//            /** @var string $resourceName */
//            printf("Customer resource name: '%s'%s", $resourceName, PHP_EOL);
//            $resourceNameArray[] = $resourceName;
//        }
//        return $resourceNameArray;
    }
    // [END list_accessible_customers]


    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $emailAddress the email address of the user whose access role should be updated
     * @param string $accessRole the updated access role
     */
    public function runGetAccountAccess(
        $option)
    {
        $managerCustomerId = isset($option['manager_customer_id']) ? (int)$option['manager_customer_id'] : null;
        $loginCustomerId   = isset($option['login_customer_id']) ? (int)$option['login_customer_id'] : null;
        $refreshToken      = isset($option['refresh_token']) ? $option['refresh_token'] : null;
//        $thirdUserId   = (int)$option['third_user_id'];

        // Creates a client with the manager customer ID as login customer ID.
        $googleAdsClient = $this->createGoogleAdsClientWithloginCustomerId($refreshToken,$loginCustomerId);

        $customerId = 8452924576;
        $userId = $this->getUserAccess($googleAdsClient, $customerId,'s5O0z@example.com');
//        if (!is_null($userId)) {
//            $this->modifyUserAccess($googleAdsClient, $customerId, $userId, $accessRole);
//        }
        return $userId;
    }

    /**
     * Gets the customer user access given an email address.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $emailAddress the email address of the user whose access role should be updated
     * @return int|null the user ID if a customer is found, or null if no matching customers were
     *     found
     */
    public function getUserAccess(
        GoogleAdsClient $googleAdsClient,
        int             $customerId,
        string          $emailAddress
    )
    {
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        // Creates a query that retrieves all customer user accesses.
        // Use the LIKE query for filtering to ignore the text case for email address when
        // searching for a match.
//        $query = "SELECT customer_user_access.user_id, "
//            . "customer_user_access.email_address, customer_user_access.access_role,"
//            . "customer_user_access.access_creation_date_time FROM customer_user_access "
//            . "WHERE customer_user_access.email_address LIKE '$emailAddress'";
        $query = "SELECT customer_user_access.user_id, "
            . "customer_user_access.email_address, customer_user_access.access_role,"
            . "customer_user_access.access_creation_date_time FROM customer_user_access "
            . "WHERE customer_user_access.user_id = $customerId";
        // Issues a search request by to retrieve the customer user accesses.
        $response =
            $googleAdsServiceClient->search(SearchGoogleAdsRequest::build($customerId, $query));
        if (iterator_count($response) > 0) {
            /** @var CustomerUserAccess $customerUserAccess */
            $customerUserAccess = $response->getIterator()->current()->getCustomerUserAccess();
            printf(
                "Customer user access with User ID = %d, Email Address = "
                . "'%s', Access Role = '%s' and Creation Time = %s was found in "
                . "Customer ID: %d.%s",
                $customerUserAccess->getUserId(),
                $customerUserAccess->getEmailAddress(),
                AccessRole::name($customerUserAccess->getAccessRole()),
                $customerUserAccess->getAccessCreationDateTime(),
                $customerId,
                PHP_EOL
            );
            return $customerUserAccess->getUserId();
        } else {
            print 'No customer user access with requested email was found.' . PHP_EOL;
            return null;
        }
    }

    /**
     * Modifies the user access role to a specified value.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param int $userId ID of the user whose access role is modified
     * @param string $accessRole the updated access role
     */
    public function modifyUserAccess(
        GoogleAdsClient $googleAdsClient,
        int             $customerId,
        int             $userId,
        string          $accessRole
    )
    {
        // Creates the modified user access.
        $customerUserAccess = new CustomerUserAccess([
            'resource_name' => ResourceNames::forCustomerUserAccess($customerId, $userId),
            'access_role' => AccessRole::value($accessRole)
        ]);

        // Constructs an operation that will update the customer user access with the specified
        // resource name, using the FieldMasks utility to derive the update mask. This mask tells
        // the Google Ads API which attributes of the customer user access you want to change.
        $customerUserAccessOperation = new CustomerUserAccessOperation();
        $customerUserAccessOperation->setUpdate($customerUserAccess);
        $customerUserAccessOperation->setUpdateMask(
            FieldMasks::allSetFieldsOf($customerUserAccess)
        );

        // Issues a mutate request to update the customer user access.
        $customerUserAccessServiceClient = $googleAdsClient->getCustomerUserAccessServiceClient();
        $response                        = $customerUserAccessServiceClient->mutateCustomerUserAccess(
            MutateCustomerUserAccessRequest::build($customerId, $customerUserAccessOperation)
        );

        // Prints the resource name of the updated customer user access.
        printf(
            "Successfully modified customer user access with resource name: '%s'%s",
            $response->getResult()->getResourceName(),
            PHP_EOL
        );
    }


    /**
     * 层级账号信息
     *
     */
    public function runGetAccountHierarchy(
        $option
    )
    {

        self::$rootCustomerClients = []; //初始化静态变量

        $managerCustomerId = isset($option['manager_customer_id']) ? (int)$option['manager_customer_id'] : null;
        $loginCustomerId   = isset($option['login_customer_id']) ? (int)$option['login_customer_id'] : null;
        $refreshToken      = isset($option['refresh_token']) ? $option['refresh_token'] : null;
//        $thirdUserId   = (int)$option['third_user_id'];

        // Creates a client with the manager customer ID as login customer ID.
        $googleAdsClient = $this->createGoogleAdsClient($refreshToken);

//        $customerServiceClient = $googleAdsClient->getCustomerServiceClient();


        $rootCustomerIds = [];
        if (is_null($managerCustomerId)) {
            // We will get the account hierarchies for all accessible customers.
            $rootCustomerIds = $this->getAccessibleCustomers($googleAdsClient);
        } else {
            // We will get only the hierarchy for the provided manager customer ID when it's
            // provided.
            $rootCustomerIds[] = $managerCustomerId;
        }

        $allHierarchies     = [];
        $accountsWithNoInfo = [];

        // Constructs a map of account hierarchies.
        foreach ($rootCustomerIds as $rootCustomerId) {
            $customerClientToHierarchy =
                $this->createCustomerClientToHierarchy($refreshToken, $loginCustomerId, $rootCustomerId);
            if (is_null($customerClientToHierarchy)) {
                $accountsWithNoInfo[] = $rootCustomerId;
            } else {
                $allHierarchies += $customerClientToHierarchy;
            }
        }

        // Prints the IDs of any accounts that did not produce hierarchy information.
        if (!empty($accountsWithNoInfo)) {
            print
                'Unable to retrieve information for the following accounts which are likely '
                . 'either test accounts or accounts with setup issues. Please check the logs for '
                . 'details:' . PHP_EOL;
            foreach ($accountsWithNoInfo as $accountId) {
                print $accountId . PHP_EOL;
            }
            print PHP_EOL;
        }
        $allAccounts = [];
        // Prints the hierarchy information for all accounts for which there is hierarchy info
        // available.
        foreach ($allHierarchies as $rootCustomerId => $customerIdsToChildAccounts) {
//            printf(
//                "The hierarchy of customer ID %d is printed below:%s",
//                $rootCustomerId,
//                PHP_EOL
//            );
            // 获取所有账户的数组(包括根账户及其子账户)
            $accounts = [];
            self::getAccountHierarchy(
                self::$rootCustomerClients[$rootCustomerId],
                $customerIdsToChildAccounts,
                0,
                $accounts);
            $allAccounts[$rootCustomerId] = $accounts;

//            self::printAccountHierarchy(
//                self::$rootCustomerClients[$rootCustomerId],
//                $customerIdsToChildAccounts,
//                0
//            );
//            print PHP_EOL;
        }
//         dump($allAccounts);
        return $allAccounts;
    }

    /**
     * Creates a map between a customer client and each of its managers' mappings.
     *
     * @param int|null $loginCustomerId the login customer ID used to create the GoogleAdsClient
     * @param int $rootCustomerId the ID of the customer at the root of the tree
     * @return array|null a map between a customer client and each of its managers' mappings if the
     *     account hierarchy can be retrieved. If the account hierarchy cannot be retrieved, returns
     *     null
     */
    public function createCustomerClientToHierarchy(
        string $refreshToken,
        ?int   $loginCustomerId,
        int    $rootCustomerId
    ): ?array
    {


        // Creates a client with the manager customer ID as login customer ID.
        $googleAdsClient = $this->createGoogleAdsClientWithloginCustomerId($refreshToken, $loginCustomerId ?? $rootCustomerId);

        // Creates the Google Ads Service client.
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        // Creates a query that retrieves all child accounts of the manager specified in search
        // calls below.
        $query = 'SELECT customer_client.client_customer, customer_client.level,'
            . ' customer_client.manager,customer_client.test_account, customer_client.descriptive_name,'
            . ' customer_client.currency_code, customer_client.time_zone,'
            . ' customer_client.id FROM customer_client WHERE customer_client.level <= 1';

        $rootCustomerClient = null;
        // Adds the root customer ID to the list of IDs to be processed.
        $managerCustomerIdsToSearch = [$rootCustomerId];

        // Performs a breadth-first search algorithm to build an associative array mapping
        // managers to their child accounts ($customerIdsToChildAccounts).
        $customerIdsToChildAccounts = [];

        while (!empty($managerCustomerIdsToSearch)) {
            $customerIdToSearch = array_shift($managerCustomerIdsToSearch);
            // Issues a search request.
            /** @var GoogleAdsServerStreamDecorator $stream */
            $stream = $googleAdsServiceClient->searchStream(SearchGoogleAdsStreamRequest::build(
                $customerIdToSearch,
                $query
            ));

            // Iterates over all elements to get all customer clients under the specified customer's
            // hierarchy.
            foreach ($stream->iterateAllElements() as $googleAdsRow) {
                /** @var GoogleAdsRow $googleAdsRow */
                $customerClient = $googleAdsRow->getCustomerClient();

                // Gets the CustomerClient object for the root customer in the tree.
                if ($customerClient->getId() === $rootCustomerId) {
                    $rootCustomerClient                         = $customerClient;
                    self::$rootCustomerClients[$rootCustomerId] = $rootCustomerClient;
                }

                // The steps below map parent and children accounts. Continue here so that managers
                // accounts exclude themselves from the list of their children accounts.
                if ($customerClient->getId() === $customerIdToSearch) {
                    continue;
                }

                // For all level-1 (direct child) accounts that are a manager account, the above
                // query will be run against them to create an associative array of managers to
                // their child accounts for printing the hierarchy afterwards.
                $customerIdsToChildAccounts[$customerIdToSearch][] = $customerClient;
                // Checks if the child account is a manager itself so that it can later be processed
                // and added to the map if it hasn't been already.
                if ($customerClient->getManager()) {
                    // A customer can be managed by multiple managers, so to prevent visiting
                    // the same customer multiple times, we need to check if it's already in the
                    // map.
                    $alreadyVisited = array_key_exists(
                        $customerClient->getId(),
                        $customerIdsToChildAccounts
                    );
                    if (!$alreadyVisited && $customerClient->getLevel() === 1) {
                        array_push($managerCustomerIdsToSearch, $customerClient->getId());
                    }
                }
            }
        }

        return is_null($rootCustomerClient) ? null
            : [$rootCustomerClient->getId() => $customerIdsToChildAccounts];
    }

    /**
     * Retrieves a list of accessible customers with the provided set up credentials.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @return int[] the list of customer IDs
     */
    public function getAccessibleCustomers(GoogleAdsClient $googleAdsClient): array
    {
        $accessibleCustomerIds = [];
        // Issues a request for listing all customers accessible by this authenticated Google
        // account.
        $customerServiceClient = $googleAdsClient->getCustomerServiceClient();
        $accessibleCustomers   =
            $customerServiceClient->listAccessibleCustomers(new ListAccessibleCustomersRequest());

        print 'No manager customer ID is specified. The example will print the hierarchies of'
            . ' all accessible customer IDs:' . PHP_EOL;
        foreach ($accessibleCustomers->getResourceNames() as $customerResourceName) {
            $customer = CustomerServiceClient::parseName($customerResourceName)['customer_id'];
            print $customer . PHP_EOL;
            $accessibleCustomerIds[] = intval($customer);
        }
        print PHP_EOL;

        return $accessibleCustomerIds;
    }

    /**
     * Prints the specified account's hierarchy using recursion.
     *
     * @param CustomerClient $customerClient the customer client whose info will be printed and
     *     its child accounts will be processed if it's a manager
     * @param array $customerIdsToChildAccounts a map from customer IDs to child
     *     accounts
     * @param int $depth the current depth we are printing from in the
     *     account hierarchy
     */
    private static function printAccountHierarchy(
        CustomerClient $customerClient,
        array          $customerIdsToChildAccounts,
        int            $depth
    )
    {
        if ($depth === 0) {
            print 'Customer ID (Descriptive Name, Currency Code, Time Zone, Manager, Test Account)' . PHP_EOL;
        }
        $customerId = $customerClient->getId();
        print str_repeat('-', $depth * 2);
        printf(
            " %d ('%s', '%s', '%s', '%s', '%s')%s",
            $customerId,
            $customerClient->getDescriptiveName(),
            $customerClient->getCurrencyCode(),
            $customerClient->getTimeZone(),
            $customerClient->getManager(),
            $customerClient->getTestAccount(),
            PHP_EOL
        );

        // Recursively call this function for all child accounts of $customerClient.
        if (array_key_exists($customerId, $customerIdsToChildAccounts)) {
            foreach ($customerIdsToChildAccounts[$customerId] as $childAccount) {
                self::printAccountHierarchy($childAccount, $customerIdsToChildAccounts, $depth + 1);
            }
        }
    }

    private static function getAccountHierarchy(
        CustomerClient $customerClient,
        array          $customerIdsToChildAccounts,
        int            $depth,
        array          &$result = []  // 这里使用引用传递
    )
    {
        // Store the current customer ID and descriptive name in the result array
        $customerId = $customerClient->getId();
        $result[]   = [
            'customer_id' => $customerId,
            'descriptive_name' => $customerClient->getDescriptiveName(),
            'manager' => $customerClient->getManager(),
            'test_account' => $customerClient->getTestAccount(),
        ];

        // Recursively call this function for all child accounts of $customerClient.
        if (array_key_exists($customerId, $customerIdsToChildAccounts)) {
            foreach ($customerIdsToChildAccounts[$customerId] as $childAccount) {
                // Recursively add the child account information
                $result = self::getAccountHierarchy($childAccount, $customerIdsToChildAccounts, $depth + 1, $result);
            }
        }

        return $result;
    }


}