<?php

namespace app\service;

use app\service\GoogleAdsClientService;
use app\model\ThirdUserAdvertiser;
use app\util\Helper;
use app\util\ArgumentNames;
use app\util\ArgumentParser;

use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClient;

use Google\Ads\GoogleAds\Util\FieldMasks;
use Google\Ads\GoogleAds\Util\V18\ResourceNames;
use Google\Ads\GoogleAds\V18\Enums\AdGroupStatusEnum\AdGroupStatus;
use Google\Ads\GoogleAds\V18\Enums\AdGroupTypeEnum\AdGroupType;
use Google\Ads\GoogleAds\V18\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V18\Resources\AdGroup;
use Google\Ads\GoogleAds\V18\Services\AdGroupOperation;
use Google\Ads\GoogleAds\V18\Services\MutateAdGroupsRequest;
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsStreamRequest;
use Google\ApiCore\ApiException;
use think\facade\Db as ThinkDb;
use app\model\AdGroup as AdGroupModel;


class GoogleAdsGroupService extends BaseService
{
    private $googleAdsClient;
    private $customerId;

    public function __construct($customerId = null)
    {

    }


    // 从数据库动态获取 google RefreshToken
//    private function getRefreshTokenFromDatabase($advertiserId)
//    {
//        // 通过 advertiser_id 查询 ThirdUserAdvertiser,联表查询 ThirdUser 数据
//        $userAdvertiser = ThirdUserAdvertiser::with('googleUser')  // 联表查询 user 关联
//        ->where('advertiser_id', $advertiserId)  // 根据 advertiser_id 查询
//        ->find();  // 获取第一个结果
//
//// 如果找到广告主数据
//        if ($userAdvertiser && $userAdvertiser->googleUser) {
//            // 获取关联用户的 access_token
//            return $userAdvertiser->googleUser ? $userAdvertiser->googleUser->access_token : null;
//        } else {
////            return $this->errorResponse('101', '未找到该广告主或关联的用户');
//        }
//    }


    /* @param int $customerId the customer ID
     * @param $options
     * @return mixed
     * @throws ApiException
     */
    public function runListGroups(int $customerId, $options): mixed
    {

//        $googleAdsClient = $this->googleAdsClient;
//        dump($customerId,$options['refresh_token']);
        $googleAdsClient = new GoogleAdsClientService($options['refresh_token'],$options['login_customer_id']);
        // Creates a single shared budget to be used by the campaigns added below.
        $groupsResourceName = self::getGroups($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
//        dump(json_encode($groupsResourceName));
        if (is_array($groupsResourceName)) {
            self::saveGroups($groupsResourceName);
        }

        return $groupsResourceName;
    }


    /**
     *  在数据库中保存广告系列信息
     * @param $groupsResourceName
     * @return void
     */
    public static function saveGroups($groupsResourceName)
    {
        $tableName = 'bps_google_ads_ad_group';
        $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'public' . $tableName;
        foreach ($groupsResourceName as $data) {
            $sql = "INSERT INTO  {$tableName}
        (ad_group_id, campaign_id, customer_id, ad_group_name, status, cpc_bid_micros)
            VALUES (:ad_group_id, :campaign_id, :customer_id, :ad_group_name, :status, :cpc_bid_micros)
            ON CONFLICT (ad_group_id) 
            DO UPDATE SET
                campaign_id = EXCLUDED.campaign_id,
                customer_id = EXCLUDED.customer_id,
                ad_group_name = EXCLUDED.ad_group_name,
                status = EXCLUDED.status,
                cpc_bid_micros = EXCLUDED.cpc_bid_micros,
                update_at = EXCLUDED.update_at";

            ThinkDb::execute($sql, $data);
        }
    }


    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     */
    // [START get_campaigns]

    public static function getGroups(GoogleAdsClient $googleAdsClient, int $customerId)
    {
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        // Creates a query that retrieves all groups.

//            $response = $googleAdsServiceClient->search($customerId, $query);
        $query = "SELECT 
                              ad_group.id, 
                              ad_group.name, 
                              campaign.id, 
                              customer.id, 
                              ad_group.status, 
                              ad_group.cpc_bid_micros 
                            FROM ad_group 
                            WHERE 
                              ad_group.status != 'REMOVED'  ";
        // Issues a search stream request.
        /** @var GoogleAdsServerStreamDecorator $stream */
        $stream        = $googleAdsServiceClient->searchStream(
            SearchGoogleAdsStreamRequest::build($customerId, $query)
        );
        $resourceNames = [];
        // Iterates over all rows in all messages and prints the requested field values for
        // the campaign in each row.
        foreach ($stream->iterateAllElements() as $googleAdsRow) {
            /** @var GoogleAdsRow $googleAdsRow */
//            printf(
//                "Campaign with ID %d and name '%s' was found.BudgetID %s: %d %s",
//                $googleAdsRow->getCampaign()->getId(),
//                $googleAdsRow->getCampaign()->getName(),
//                $googleAdsRow->getCampaignBudget()->getName(),
//                $googleAdsRow->getCampaignBudget()->getAmountMicros(),
//
//                $googleAdsRow->getCampaignBudget()->getName(),
//                PHP_EOL
//            );
            $resourceName['ad_group_id']    = $googleAdsRow->getAdGroup()->getId();
            $resourceName['ad_group_name']  = $googleAdsRow->getAdGroup()->getName();
            $resourceName['cpc_bid_micros'] = $googleAdsRow->getAdGroup()->getCpcBidMicros();
            $resourceName['status']         = $googleAdsRow->getAdGroup()->getStatus();
            $resourceName['campaign_id']    = $googleAdsRow->getCampaign()->getId();
            $resourceName['customer_id']    = $googleAdsRow->getCustomer()->getId();
            $resourceNames[]                = $resourceName;
        }
        return $resourceNames;
    }


    /**
     * This example updates a campaign by setting the status to `PAUSED`. To get campaigns, run
     * GetCampaigns.php.
     */
    /* @param int $customerId the customer ID
     * @param $options
     * @return mixed
     * @throws ApiException
     */
    public function runAddGroup($options): mixed
    {
//        $googleAdsClient = $this->googleAdsClient;
        $googleAdsClient = new GoogleAdsClientService($options['refresh_token']);
        // Creates a single shared budget to be used by the campaigns added below.
        $resourceNames = self::addGroup($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['campaign_id']);

        return $resourceNames;
    }


    /**
     * Runs the addGroup example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param int $campaignId the campaign ID to add ad groups to
     */
    public static function addGroup(
        GoogleAdsClient $googleAdsClient,
        int             $customerId,
        int             $campaignId
    )
    {
        $campaignResourceName = ResourceNames::forCampaign($customerId, $campaignId);

        $operations = [];

        // Constructs an ad group and sets an optional CPC value.
        $adGroup1 = new AdGroup([
            'name' => 'Earth to Mars Cruises #' . Helper::getPrintableDatetime(),
            'campaign' => $campaignResourceName,
            'status' => AdGroupStatus::ENABLED,
            'type' => AdGroupType::SEARCH_STANDARD,
            'cpc_bid_micros' => 10000000
        ]);

        $adGroupOperation1 = new AdGroupOperation();
        $adGroupOperation1->setCreate($adGroup1);
        $operations[] = $adGroupOperation1;

        // Constructs another ad group.
        $adGroup2 = new AdGroup([
            'name' => 'Earth to Venus Cruises #' . Helper::getPrintableDatetime(),
            'campaign' => $campaignResourceName,
            'status' => AdGroupStatus::ENABLED,
            'type' => AdGroupType::SEARCH_STANDARD,
            'cpc_bid_micros' => 20000000
        ]);

        $adGroupOperation2 = new AdGroupOperation();
        $adGroupOperation2->setCreate($adGroup2);
        $operations[] = $adGroupOperation2;

        // Issues a mutate request to add the ad groups.
        $adGroupServiceClient = $googleAdsClient->getAdGroupServiceClient();
        $response             = $adGroupServiceClient->mutateAdGroups(MutateAdGroupsRequest::build(
            $customerId,
            $operations
        ));
        $resourceNames        = [];

        printf("Added %d ad groups:%s", $response->getResults()->count(), PHP_EOL);

        foreach ($response->getResults() as $addedAdGroup) {
            /** @var AdGroup $addedAdGroup */
            print $addedAdGroup->getResourceName() . PHP_EOL;
            $resourceNames[] = $addedAdGroup->getResourceName();
        }
        return $resourceNames;
    }



    /**
     * This example updates the CPC bid and status for a given ad group. To get ad groups, run
     * GetAdGroups.php.
     */
    /* @param int $customerId the customer ID
     * @param $options
     * @return mixed
     * @throws ApiException
     */
    public function runUpdateGroup($options): mixed
    {
//        $googleAdsClient = $this->googleAdsClient;
        $googleAdsClient = new GoogleAdsClientService($options['customer_id']);
        // Creates a single shared budget to be used by the campaigns added below.

//        $resourceNames = self::updateGroup($googleAdsClient, $options['customer_id'], $options['group_id'],  $options['status'], $options['bid_micro_amount'],);
        $resourceNames = self::updateGroup($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['group_id'], $options['status']);

        return $resourceNames;
    }

    /**
     * Runs the updateAdGroup example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param int $adGroupId the ID of ad group to update
     * @param int $bidMicroAmount the bid amount in micros to use for the ad group bid
     */
    // [START update_ad_group]
    public static function updateGroup(
        GoogleAdsClient $googleAdsClient,
        int             $customerId,
        int             $adGroupId,
        int             $status,
        //                        $bidMicroAmount
    )
    {

        // Creates an ad group object with the specified resource name and other changes.
        $adGroup = new AdGroup([
            'resource_name' => ResourceNames::forAdGroup($customerId, $adGroupId),
//            'cpc_bid_micros' => $bidMicroAmount,
//            'status' => AdGroupStatus::PAUSED
            'status' => $status
        ]);

        // Constructs an operation that will update the ad group 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 ad group you want to change.
        $adGroupOperation = new AdGroupOperation();
        $adGroupOperation->setUpdate($adGroup);
        $adGroupOperation->setUpdateMask(FieldMasks::allSetFieldsOf($adGroup));

        // Issues a mutate request to update the ad group.
        $adGroupServiceClient = $googleAdsClient->getAdGroupServiceClient();
        $response             = $adGroupServiceClient->mutateAdGroups(MutateAdGroupsRequest::build(
            $customerId,
            [$adGroupOperation]
        ));

        // Prints the resource name of the updated ad group.
        /** @var AdGroup $updatedAdGroup */
        $updatedAdGroup = $response->getResults()[0];
        printf(
            "Updated ad group with resource name: '%s'%s",
            $updatedAdGroup->getResourceName(),
            PHP_EOL
        );
        return $updatedAdGroup->getResourceName();
    }
    // [END update_ad_group]


    /**
     * 更新广告组状态
     */
    public function updateGroupStatus(int $customerId, int $adGroupId, int $status)
    {
        // 从数据库获取 AdGroup
        $adGroup = AdGroupModel::find($adGroupId);
        if (!$adGroup) {
            return false;
//            throw new ValidateException('AdGroup not found');
        }

        // 更新数据库中的状态
//        $adGroup->updateStatus($status);
        if ($this->modifyDbGroupStatus($adGroupId, $status)) {
            // 更新 Google Ads 上的状态
//            $googleAdsClient = $this->googleAdsClient;
             $googleAdsClient = new GoogleAdsClientService($customerId);

            $resourceName    = self::updateGroup($googleAdsClient->getGoogleAdsClient(), $customerId, $adGroupId, $status);
            return true;
        }

        return false;
    }

    /**
     * 获取广告组状态
     */
//    public function getAdGroupStatus(int $adGroupId)
//    {
//        // 从数据库获取 AdGroup
//        $adGroup = AdGroupModel::find($adGroupId);
//        if (!$adGroup) {
//            throw new ValidateException('AdGroup not found');
//        }
//
//        // 返回广告组状态
//        return $adGroup->getStatusTextAttr(null, $adGroup->toArray());
//    }

    /**
     * 判断广告组是否启用
     */
//    public function isAdGroupEnabled(int $adGroupId)
//    {
//        $adGroup = AdGroup::find($adGroupId);
//        if (!$adGroup) {
//            throw new ValidateException('AdGroup not found');
//        }
//
//        return $adGroup->isEnabled();
//    }

    /**
     * 判断广告组是否暂停
     */
//    public function isAdGroupPaused(int $adGroupId)
//    {
//        $adGroup = AdGroup::find($adGroupId);
//        if (!$adGroup) {
//            throw new ValidateException('AdGroup not found');
//        }
//
//        return $adGroup->isPaused();
//    }

    /**
     * 判断广告组是否停止
     */
//    public function isAdGroupStopped(int $adGroupId)
//    {
//        $adGroup = AdGroup::find($adGroupId);
//        if (!$adGroup) {
//            throw new ValidateException('AdGroup not found');
//        }
//
//        return $adGroup->isStopped();
//    }


}