<?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 DateTime;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClient;
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\Common\ManualCpc;
use Google\Ads\GoogleAds\V18\Enums\AdvertisingChannelTypeEnum\AdvertisingChannelType;
use Google\Ads\GoogleAds\V18\Enums\BudgetDeliveryMethodEnum\BudgetDeliveryMethod;
use Google\Ads\GoogleAds\V18\Enums\CampaignStatusEnum\CampaignStatus;
use Google\Ads\GoogleAds\V18\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V18\Resources\Campaign;
use Google\Ads\GoogleAds\V18\Resources\Campaign\NetworkSettings;
use Google\Ads\GoogleAds\V18\Resources\CampaignBudget;
use Google\Ads\GoogleAds\V18\Services\CampaignBudgetOperation;
use Google\Ads\GoogleAds\V18\Services\CampaignOperation;
use Google\Ads\GoogleAds\V18\Services\GoogleAdsRow;
use Google\Ads\GoogleAds\V18\Services\MutateCampaignsRequest;
use Google\Ads\GoogleAds\V18\Services\MutateCampaignBudgetsRequest;
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsStreamRequest;
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsRequest;
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsResponse;
use app\model\Campaign as CampaignModel;
use app\model\DayData as DayDataModel;
use Monolog\Handler\NewRelicHandler;
use think\facade\Db as ThinkDb;

use Google\ApiCore\ApiException;

class GoogleAdsCampaignService extends BaseService
{
    private $googleAdsClient;
    private $customerId;
    private const NUMBER_OF_CAMPAIGNS_TO_ADD = 1;

    public function __construct($customerId = null, GoogleAdsClientService $googleAdsClientService = null)
    {
        // 使用 GoogleAdsClientService 来初始化 googleAdsClient
//        $googleAdsClient = new GoogleAdsClientService($customerId);
//         $this->googleAdsClient = $googleAdsClient->getGoogleAdsClient();
    }

    // 从数据库动态获取 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', '未找到该广告主或关联的用户');
//        }
//    }


    /**
     * Runs the example.
     *
     * @param int $customerId the customer ID
     * @param $options
     * @return mixed
     * @throws ApiException
     */
    public function runAddCampaign(int $customerId, $options): mixed
    {
        $googleAdsClient = new GoogleAdsClientService($options['refresh_token']);

        // Creates a single shared budget to be used by the campaigns added below.
        $budgetResourceName = self::addCampaignBudget($googleAdsClient->getGoogleAdsClient(), $customerId, $options);

        // Configures the campaign network options.
        $networkSettings = new NetworkSettings([
            'target_google_search' => true,
            'target_search_network' => true,
            // Enables Display Expansion on Search campaigns. See
            // https://support.google.com/google-ads/answer/7193800 to learn more.
            'target_content_network' => true,
            'target_partner_search_network' => false
        ]);

        $campaignOperations = [];
        for ($i = 0; $i < self::NUMBER_OF_CAMPAIGNS_TO_ADD; $i++) {
            // Creates a campaign.
            // [START add_campaigns_1]
            $campaign = new Campaign([
//                'name' => 'Interplanetary Cruise #' . Helper::getPrintableDatetime(),
                'name' => $options['campaign_name'] . rand(10, 99) . ' #' . Helper::getPrintableDatetime(),
                'advertising_channel_type' => AdvertisingChannelType::SEARCH,
                // Recommendation: Set the campaign to PAUSED when creating it to prevent
                // the ads from immediately serving. Set to ENABLED once you've added
                // targeting and the ads are ready to serve.
                'status' => CampaignStatus::PAUSED,
                // Sets the bidding strategy and budget.
                'manual_cpc' => new ManualCpc(),
                'campaign_budget' => $budgetResourceName,
                // Adds the network settings configured above.
                'network_settings' => $networkSettings,
                // Optional: Sets the start and end dates.
                'start_date' => date('Ymd', strtotime('+1 day')),
                'end_date' => date('Ymd', strtotime('+1 month'))
            ]);
            // [END add_campaigns_1]

            // Creates a campaign operation.
            $campaignOperation = new CampaignOperation();
            $campaignOperation->setCreate($campaign);
            $campaignOperations[] = $campaignOperation;
        }

        // Issues a mutate request to add campaigns.
        $campaignServiceClient = $googleAdsClient->getCampaignServiceClient();
        $response              = $campaignServiceClient->mutateCampaigns(
            MutateCampaignsRequest::build($customerId, $campaignOperations)
        );
//        printf("Added %d campaigns:%s", $response->getResults()->count(), PHP_EOL);
//
        foreach ($response->getResults() as $addedCampaign) {
            /** @var Campaign $addedCampaign */
//            print "{$addedCampaign->getResourceName()}" . PHP_EOL;
            $resourceNames[] = $addedCampaign->getResourceName();
        }
        return $resourceNames;
    }

    /**
     * Runs the example.
     *
     * @param int $customerId the customer ID
     * @param $options
     * @return mixed
     * @throws ApiException
     */
    public function runAddCampaignBudget(int $customerId, $options): mixed
    {
//        if(!$customerId){
//            $customerId = $this->customerId;
//        }
//        $googleAdsClient = $this->googleAdsClient;
        $googleAdsClient = new GoogleAdsClientService($customerId);
        // Creates a single shared budget to be used by the campaigns added below.
        $budgetResourceName = self::addCampaignBudget($googleAdsClient->getGoogleAdsClient(), $customerId, $options);

        return $budgetResourceName;
    }

    /**
     * Creates a new campaign budget in the specified client account.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @return string the resource name of the newly created budget
     * @throws ApiException
     */
    // [START add_campaigns]
    private static function addCampaignBudget(GoogleAdsClient $googleAdsClient, int $customerId, $options)
    {

        // Creates a campaign budget.
        $budget = new CampaignBudget([
//            'name' => 'Interplanetary Cruise Budget #' . Helper::getPrintableDatetime(),
            'name' => $options['name'] . rand(10, 99) . ' #' . Helper::getPrintableDatetime(),
//            'delivery_method' => BudgetDeliveryMethod::STANDARD,
            'amount_micros' => $options['amount'] * 1000000
        ]);

        // Creates a campaign budget operation.
        $campaignBudgetOperation = new CampaignBudgetOperation();
        $campaignBudgetOperation->setCreate($budget);

        // Issues a mutate request.
        $campaignBudgetServiceClient = $googleAdsClient->getCampaignBudgetServiceClient();
        $response                    = $campaignBudgetServiceClient->mutateCampaignBudgets(
            MutateCampaignBudgetsRequest::build($customerId, [$campaignBudgetOperation])
        );

        /** @var CampaignBudget $addedBudget */
        $addedBudget = $response->getResults()[0];
//        printf("Added budget named '%s'%s", $addedBudget->getResourceName(), PHP_EOL);

        return $addedBudget->getResourceName();
    }

    // [END add_campaigns]

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

        $googleAdsClient = new GoogleAdsClientService($options['refresh_token'], $options['login_customer_id']);
//        $campaignsResourceName = self::getCampaigns($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
        $campaignsResourceName = self::getCampaignsNew($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
//        dump(json_encode($campaignsResourceName));
        if (is_array($campaignsResourceName)) {
//            self::saveCampaigns($campaignsResourceName);
            self::saveCampaignsNew($campaignsResourceName);
        }

        return $campaignsResourceName;
    }

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

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

        return $dayResourceName;
    }


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

    public static function getCampaignsNew(GoogleAdsClient $googleAdsClient, int $customerId)
    {
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        // Creates a query that retrieves all campaigns.
//        $query = 'SELECT campaign.id,campaign.name,campaign.status,campaign.campaign_budget,campaign_budget.id,campaign_budget.name,campaign_budget.amount_micros FROM campaign ORDER BY campaign.id';
        $query = "SELECT                   
                  campaign.id, 
                  campaign.name, 
                  campaign.status, 
                  campaign.advertising_channel_type,
                  campaign.start_date,
                  campaign.end_date,
                  campaign_budget.amount_micros,
                  customer.id
                FROM campaign 
                WHERE 
                  campaign.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['campaign_id']   = $googleAdsRow->getCampaign()->getId();
            $resourceName['campaign_name'] = $googleAdsRow->getCampaign()->getName();
            $resourceName['status']        = $googleAdsRow->getCampaign()->getStatus();
            $resourceName['customer_id']   = $googleAdsRow->getCustomer()->getId();
            $resourceNames[]               = $resourceName;
        }
        return $resourceNames;
    }

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

    public static function getCampaigns(GoogleAdsClient $googleAdsClient, int $customerId)
    {
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        // Creates a query that retrieves all campaigns.
//        $query = 'SELECT campaign.id,campaign.name,campaign.status,campaign.campaign_budget,campaign_budget.id,campaign_budget.name,campaign_budget.amount_micros FROM campaign ORDER BY campaign.id';
        $query = "SELECT                   
                  campaign.id, 
                  campaign.name, 
                  campaign.status, 
                  campaign.advertising_channel_type,
                  campaign.start_date,
                  campaign.end_date,
                  campaign_budget.amount_micros,
                  customer.id
                FROM campaign 
                WHERE 
                  campaign.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['campaign_id']              = $googleAdsRow->getCampaign()->getId();
            $resourceName['campaign_name']            = $googleAdsRow->getCampaign()->getName();
            $resourceName['advertising_channel_type'] = $googleAdsRow->getCampaign()->getAdvertisingChannelType();
            $resourceName['status']                   = $googleAdsRow->getCampaign()->getStatus();
            $resourceName['start_date']               = $googleAdsRow->getCampaign()->getStartDate();
            $resourceName['end_date']                 = $googleAdsRow->getCampaign()->getEndDate();
            $resourceName['budget_amount_micros']     = $googleAdsRow->getCampaignBudget()->getAmountMicros();
            $resourceName['customer_id']              = $googleAdsRow->getCustomer()->getId();
            $resourceNames[]                          = $resourceName;
        }
        return $resourceNames;
    }


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

    public static function getDateDatas(GoogleAdsClient $googleAdsClient, int $customerId, $date = '2024-12-19')
    {
        // 调用私有方法提取 year, month, season
        $dateDetails = self::extractDateDetails($date);

        $year   = $dateDetails['year'];
        $month  = $dateDetails['month'];
        $season = $dateDetails['season'];


        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();

        // Creates a query that retrieves all campaigns.
//        $query = "SELECT ad_group_ad.ad.id, ad_group_ad.ad.name, ad_group_ad.ad.resource_name, ad_group.id, campaign.id, customer.id, metrics.clicks, metrics.cost_micros, metrics.conversions, metrics.conversions_value, metrics.impressions FROM ad_group_ad WHERE segments.date = '{$date}' ORDER BY ad_group.id ASC LIMIT 10000";
        $query = "SELECT
                    ad_group_ad.ad.id,
                    ad_group_ad.ad.name,
                    ad_group_ad.ad.resource_name,
                    ad_group.id,
                    campaign.id,
                    customer.id,
                    customer.currency_code,
                    metrics.clicks,
                    metrics.cost_micros,
                    metrics.conversions,
                    metrics.conversions_value,
                    metrics.impressions,
                    metrics.interactions,-- 新增字段
                    metrics.orders,-- 新增字段
                    metrics.revenue_micros,-- 新增字段
                    metrics.value_per_all_conversions,-- 新增字段
                    metrics.value_per_all_conversions_by_conversion_date,-- 新增字段
                    metrics.value_per_conversion,-- 新增字段
                    metrics.value_per_conversions_by_conversion_date,-- 新增字段
                    metrics.video_quartile_p25_rate,-- 新增字段
                    metrics.video_quartile_p50_rate,-- 新增字段
                    metrics.video_quartile_p75_rate,-- 新增字段
                    metrics.video_quartile_p100_rate,-- 新增字段
                    metrics.video_view_rate,-- 新增字段
                    metrics.video_views,-- 新增字段
                    metrics.view_through_conversions -- 新增字段
                FROM
                    ad_group_ad
                WHERE
                    segments.date = '{$date}'
                ORDER BY
                    ad_group.id ASC
                LIMIT 10000
            ";

//        dump($query);return;

        // 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 */
            $resourceName['ad_id']             = $googleAdsRow->getAdGroupAd()->getAd()->getId();
            $resourceName['customer_id']       = $googleAdsRow->getCustomer()->getId();
            $resourceName['currency']       = $googleAdsRow->getCustomer()->getCurrencyCode();
            $resourceName['ad_name']           = $googleAdsRow->getAdGroupAd()->getAd()->getName();
            $resourceName['ad_resource_name']  = $googleAdsRow->getAdGroupAd()->getAd()->getResourceName();
            $resourceName['ad_group_id']       = $googleAdsRow->getAdGroup()->getId();
            $resourceName['campaign_id']       = $googleAdsRow->getCampaign()->getId();
            $resourceName['clicks']            = $googleAdsRow->getMetrics()->getClicks();
            $resourceName['cost_micros']       = $googleAdsRow->getMetrics()->getCostMicros();
            $resourceName['conversions']       = $googleAdsRow->getMetrics()->getConversions();
            $resourceName['conversions_value'] = $googleAdsRow->getMetrics()->getConversionsValue();
            $resourceName['impressions']       = $googleAdsRow->getMetrics()->getImpressions();
            $resourceName['date']              = $date;
            $resourceName['month']             = $month;
            $resourceName['season']            = $season;
            $resourceName['year']              = $year;
            // 新增字段
            $resourceName['interactions']                                 = $googleAdsRow->getMetrics()->getInteractions();
            $resourceName['orders']                                       = $googleAdsRow->getMetrics()->getOrders();
            $resourceName['revenue_micros']                               = $googleAdsRow->getMetrics()->getRevenueMicros();
            $resourceName['value_per_all_conversions']                    = $googleAdsRow->getMetrics()->getValuePerAllConversions();
            $resourceName['value_per_all_conversions_by_conversion_date'] = $googleAdsRow->getMetrics()->getValuePerAllConversionsByConversionDate();
            $resourceName['value_per_conversion']                         = $googleAdsRow->getMetrics()->getValuePerConversion();
            $resourceName['value_per_conversions_by_conversion_date']     = $googleAdsRow->getMetrics()->getValuePerConversionsByConversionDate();
            $resourceName['video_quartile_p25_rate']                      = $googleAdsRow->getMetrics()->getVideoQuartileP25Rate();
            $resourceName['video_quartile_p50_rate']                      = $googleAdsRow->getMetrics()->getVideoQuartileP50Rate();
            $resourceName['video_quartile_p75_rate']                      = $googleAdsRow->getMetrics()->getVideoQuartileP75Rate();
            $resourceName['video_quartile_p100_rate']                     = $googleAdsRow->getMetrics()->getVideoQuartileP100Rate();
            $resourceName['video_view_rate']                              = $googleAdsRow->getMetrics()->getVideoViewRate();
            $resourceName['video_views']                                  = $googleAdsRow->getMetrics()->getVideoViews();
            $resourceName['view_through_conversions']                     = $googleAdsRow->getMetrics()->getViewThroughConversions();

//            $resourceName['budget_id'] = $googleAdsRow->getCampaignBudget()->getId();
            $resourceNames[] = $resourceName;
        }
        return $resourceNames;
    }


    /**
     * 从日期字符串中提取年、月、季节信息,并返回这些信息
     *
     * @param string $date 日期,格式为 'Y-m-d'
     * @return array 包含 year, month 和 season 的数组
     */
    private static function extractDateDetails($date)
    {
        $dateObj = new DateTime($date); // 将日期字符串转换为 DateTime 对象

        // 提取年和月
        $year  = (int)$dateObj->format('Y');
        $month = (int)$dateObj->format('m');

        // 计算季度
        if ($month >= 1 && $month <= 3) {
            $season = (int)$dateObj->format('Y') . '01'; // Q1
        } elseif ($month >= 4 && $month <= 6) {
            $season = (int)$dateObj->format('Y') . '02'; // Q2
        } elseif ($month >= 7 && $month <= 9) {
            $season = (int)$dateObj->format('Y') . '03'; // Q3
        } else {
            $season = (int)$dateObj->format('Y') . '04'; // Q4
        }
        $month = (int)$dateObj->format('Ym');
        return [
            'year' => $year,
            'month' => $month,
            'season' => $season
        ];
    }

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

    /**
     *  在数据库中保存广告系列信息
     * @param $campaignsResourceName
     * @return void
     */
    public static function saveCampaigns($campaignsResourceName)
    {
        $tableName = 'bps_google_ads_campaign';
        $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'public' . $tableName;
//        foreach ($campaignsResourceName as $data) {
//            $sql = "INSERT INTO  {$tableName}
//        (campaign_id, customer_id, campaign_name, status, advertising_channel_type, start_date, end_date, budget_amount_micros)
//        VALUES (:campaign_id, :customer_id, :campaign_name, :status, :advertising_channel_type, :start_date, :end_date, :budget_amount_micros)";
//            ThinkDb::execute($sql, $data);
//        }
        foreach ($campaignsResourceName as $data) {
            $sql = "INSERT INTO {$tableName}
                (campaign_id, customer_id, campaign_name, status, advertising_channel_type, start_date, end_date, budget_amount_micros)
                VALUES (:campaign_id, :customer_id, :campaign_name, :status, :advertising_channel_type, :start_date, :end_date, :budget_amount_micros)
                ON CONFLICT (campaign_id) 
                DO UPDATE SET
                    customer_id = EXCLUDED.customer_id,
                    campaign_name = EXCLUDED.campaign_name,
                    status = EXCLUDED.status,
                    advertising_channel_type = EXCLUDED.advertising_channel_type,
                    start_date = EXCLUDED.start_date,
                    end_date = EXCLUDED.end_date,
                    budget_amount_micros = EXCLUDED.budget_amount_micros,
                    update_at = EXCLUDED.update_at";  // 你可以根据实际情况决定是否需要更新时间戳

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

    /**
     *  在数据库中保存广告系列信息
     * @param $campaignsResourceName
     * @return void
     */
    public static function saveCampaignsNew($campaignsResourceName)
    {
        $tableName = 'bps_ads_campaign';
        $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'public' . $tableName;

        foreach ($campaignsResourceName as $data) {

            $sql = "INSERT INTO {$tableName}
                    (campaign_id, account_id, name, status, platform_type, last_sync_time, update_at)
                    VALUES (:campaign_id, :customer_id, :campaign_name, :status, 2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
                    ON CONFLICT (platform_type,campaign_id)
                    DO UPDATE SET
                        account_id = EXCLUDED.account_id,
                        name = EXCLUDED.name,
                        status = EXCLUDED.status,
                        last_sync_time = CURRENT_TIMESTAMP,  -- 使用当前时间戳
                        update_at = CURRENT_TIMESTAMP        -- 使用当前时间戳
                    WHERE {$tableName}.platform_type = 2";

            ThinkDb::execute($sql, $data);
            // 打印最后执行的 SQL 语句
//            dump(ThinkDb::getLastSql());
        }
    }


    /**
     *  在数据库中保存广告系列信息
     * @param $campaignsResourceName
     * @return void
     */
    public static function saveDateDatas($dayResourceName)
    {
//        dump($campaignsResourceName);

        foreach ($dayResourceName as $data) {
//            $sql = "INSERT INTO bps.bps_google_ad_day_data (ad_id, customer_id, ad_name, ad_resource_name, ad_group_id, campaign_id, clicks, cost_micros, conversions, conversions_value, impressions, date)
//            VALUES (:ad_id, :customer_id, :ad_name, :ad_resource_name, :ad_group_id, :campaign_id, :clicks, :cost_micros, :conversions, :conversions_value, :impressions, :date)";
//            ThinkDb::execute($sql, $data);

            $sql = "INSERT INTO bps.bps_google_ad_day_data 
        (ad_id, customer_id,currency, ad_name, ad_resource_name, ad_group_id, campaign_id, clicks, cost_micros, conversions, conversions_value, impressions, date, month, season, year,interactions, orders, revenue_micros, value_per_all_conversions, 
        value_per_all_conversions_by_conversion_date, value_per_conversion,
        value_per_conversions_by_conversion_date, video_quartile_p25_rate,
        video_quartile_p50_rate, video_quartile_p75_rate, video_quartile_p100_rate,
        video_view_rate, video_views, view_through_conversions)
        VALUES (:ad_id, :customer_id, :currency, :ad_name, :ad_resource_name, :ad_group_id, :campaign_id, :clicks, :cost_micros, :conversions, :conversions_value, :impressions, :date, :month, :season, :year,:interactions, :orders, :revenue_micros, :value_per_all_conversions, 
        :value_per_all_conversions_by_conversion_date, :value_per_conversion, 
        :value_per_conversions_by_conversion_date, :video_quartile_p25_rate, 
        :video_quartile_p50_rate, :video_quartile_p75_rate, :video_quartile_p100_rate, 
        :video_view_rate, :video_views, :view_through_conversions)
        ON CONFLICT (ad_id, date)
        DO UPDATE SET
            customer_id = EXCLUDED.customer_id,
            currency = EXCLUDED.currency,
            ad_name = EXCLUDED.ad_name,
            ad_resource_name = EXCLUDED.ad_resource_name,
            ad_group_id = EXCLUDED.ad_group_id,
            campaign_id = EXCLUDED.campaign_id,
            clicks = EXCLUDED.clicks,
            cost_micros = EXCLUDED.cost_micros,
            conversions = EXCLUDED.conversions,
            conversions_value = EXCLUDED.conversions_value,
            impressions = EXCLUDED.impressions,
            month = EXCLUDED.month,
            season = EXCLUDED.season,
            year = EXCLUDED.year,
            interactions = EXCLUDED.interactions,
            orders = EXCLUDED.orders,
            revenue_micros = EXCLUDED.revenue_micros,
            value_per_all_conversions = EXCLUDED.value_per_all_conversions,
            value_per_all_conversions_by_conversion_date = EXCLUDED.value_per_all_conversions_by_conversion_date,
            value_per_conversion = EXCLUDED.value_per_conversion,
            value_per_conversions_by_conversion_date = EXCLUDED.value_per_conversions_by_conversion_date,
            video_quartile_p25_rate = EXCLUDED.video_quartile_p25_rate,
            video_quartile_p50_rate = EXCLUDED.video_quartile_p50_rate,
            video_quartile_p75_rate = EXCLUDED.video_quartile_p75_rate,
            video_quartile_p100_rate = EXCLUDED.video_quartile_p100_rate,
            video_view_rate = EXCLUDED.video_view_rate,
            video_views = EXCLUDED.video_views,
            view_through_conversions = EXCLUDED.view_through_conversions,
            update_at = EXCLUDED.update_at";  // 更新其他字段和更新时间戳
//        dump($sql, $data);
            ThinkDb::execute($sql, $data);

        }
    }

    /* @param int $customerId the customer ID
     * @param $options
     * @return mixed
     * @throws ApiException
     */
    public function runListCampaignsNext($options): mixed
    {
//        $googleAdsClient = $this->googleAdsClient;
        $googleAdsClient = new GoogleAdsClientService($options['customer_id']);
        // Creates a single shared budget to be used by the campaigns added below.
        $campaigns = self::getCampaignsNext($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['page_token']);

        return $campaigns;
    }

    /**
     * 获取广告系列列表,支持分页
     *
     * @param GoogleAdsClient $googleAdsClient
     * @param string $customerId 客户 ID
     * @param null $pageToken 下一页的令牌
     * @return array 广告系列列表及下一页令牌
     */
    public function getCampaignsNext(GoogleAdsClient $googleAdsClient, $customerId, $pageToken = null)
    {
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();

        // 创建查询,获取广告系列信息
        $query = "SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id";

        // 初始化分页参数
        $pageToken = null;
//        $pageSize = 1000;  // 每页1000条记录
        $allCampaigns             = [];
        $totalResultsCount        = 0;
        $queryResourceConsumption = 0;

        // 创建请求对象
        $request = new SearchGoogleAdsRequest([
            'customer_id' => $customerId,
            'query' => $query,
            'page_token' => $pageToken, // 分页令牌
//            'page_size' => $pageSize,   // 设置每页的大小
        ]);
        // 调用 search 方法进行数据获取
        try {
            // 发起查询请求,返回 PagedListResponse
            $response = $googleAdsServiceClient->search($request);

            // 获取总结果数
            $totalResultsCount = $response->getTotalResultsCount();

            // 获取查询消耗的资源
            $queryResourceConsumption = $response->getQueryResourceConsumption();

            // 获取返回结果(PagedListResponse 类型)
            $this->processSearchGoogleAdsResponse($response, $allCampaigns);

            // 获取下一页的分页令牌
            $pageToken = $response->getNextPageToken();

        } catch (ApiException $e) {
            // 处理异常
            printf("API request failed with message: %s\n", $e->getMessage());
        }

        return [
            'campaigns' => $allCampaigns,
            'totalResultsCount' => $totalResultsCount,
            'queryResourceConsumption' => $queryResourceConsumption
        ];
    }

    /**
     * 处理 SearchGoogleAdsResponse 数据并提取广告系列信息
     *
     * @param SearchGoogleAdsResponse $response 查询响应
     * @param array $allCampaigns 用于存储广告系列的数组
     */
    private function processSearchGoogleAdsResponse(SearchGoogleAdsResponse $response, array &$allCampaigns)
    {
        // 获取查询结果
        foreach ($response->getResults() as $googleAdsRow) {
            /** @var \Google\Ads\GoogleAds\V18\Resources\Campaign $campaign */
            $campaign       = $googleAdsRow->getCampaign();
            $allCampaigns[] = [
                'id' => $campaign->getId(),
                'name' => $campaign->getName(),
            ];
        }

        // 输出分页的总结果数
        printf("Total Results Count: %d\n", $response->getTotalResultsCount());

        // 输出查询资源消耗
        printf("Query Resource Consumption: %d\n", $response->getQueryResourceConsumption());

        // 输出汇总数据(如果存在)
        if ($summaryRow = $response->getSummaryRow()) {
            // 处理汇总行(根据需要)
            printf("Summary Row Metrics: %s\n", $summaryRow);
        }

        // 获取下一页的分页令牌
        $nextPageToken = $response->getNextPageToken();
        if ($nextPageToken) {
            printf("Next Page Token: %s\n", $nextPageToken);
        }
    }


    /* @param int $customerId the customer ID
     * @param $options
     * @return mixed
     * @throws ApiException
     */
    public function runRemoveCampaign($options): mixed
    {
//        $googleAdsClient = $this->googleAdsClient;
        $googleAdsClient = new GoogleAdsClientService($options['customer_id']);

        // Creates a single shared budget to be used by the campaigns added below.
        $resourceName = self::removeCampaign($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['campaign_id']);

        return $resourceName;
    }

    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param int $campaignId the ID of the campaign to remove
     */
    public static function removeCampaign(
        GoogleAdsClient $googleAdsClient,
        int             $customerId,
        int             $campaignId
    )
    {
        // Creates the resource name of a campaign to remove.
        $campaignResourceName = ResourceNames::forCampaign($customerId, $campaignId);

        // Creates a campaign operation.
        $campaignOperation = new CampaignOperation();
        $campaignOperation->setRemove($campaignResourceName);

        // Issues a mutate request to remove the campaign.
        $campaignServiceClient = $googleAdsClient->getCampaignServiceClient();
        $response              = $campaignServiceClient->mutateCampaigns(
            MutateCampaignsRequest::build($customerId, [$campaignOperation])
        );

        /** @var Campaign $removedCampaign */
        $removedCampaign = $response->getResults()[0];
        printf(
            "Removed campaign with resource name '%s'%s",
            $removedCampaign->getResourceName(),
            PHP_EOL
        );
        return $removedCampaign->getResourceName();
    }

    /**
     * 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 runUpdateCampaign($options): mixed
    {

        $googleAdsClient = new GoogleAdsClientService($options['refresh_token'], $options['login_customer_id']);
        // Creates a single shared budget to be used by the campaigns added below.
        $resourceName = self::updateCampaign($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['campaign_id'], $options['status']);

        return $resourceName;
    }

    /**
     * Runs the updateCampaign example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param int $campaignId the ID of campaign to update
     */
    public static function updateCampaign(
        GoogleAdsClient $googleAdsClient,
        int             $customerId,
        int             $campaignId,
        int             $status
    )
    {

        // Creates a campaign object with the specified resource name and other changes.
        $campaign = new Campaign([
//            'resource_name' => ResourceNames::forCampaign($customerId, $campaignId),
//            'status' => CampaignStatus::PAUSED
            'resource_name' => ResourceNames::forCampaign($customerId, $campaignId),
            'status' => $status,
        ]);

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

        // Issues a mutate request to update the campaign.
        $campaignServiceClient = $googleAdsClient->getCampaignServiceClient();
        $response              = $campaignServiceClient->mutateCampaigns(MutateCampaignsRequest::build(
            $customerId,
            [$campaignOperation]
        ));

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


    /**
     * 更新广告系列状态
     */
    public function updateCampaignStatus($options)
    {
        // 从数据库获取 Campaign 对象
        $campaign = CampaignModel::find($options['campaign_id']);
//        dump($campaign);return;
        if (!$campaign) {
//            throw new ValidateException('Campaign not found');
            return false;
        }
        // 更新本地数据库的状态
        if ($this->modifyDbCampaignStatus($options['campaign_id'], $options['status'])) {
            // 更新 Google Ads 上的状态
//            $googleAdsClient = $this->googleAdsClient;
            $googleAdsClient = new GoogleAdsClientService($options['refresh_token'], $options['login_customer_id']);
            $resourceName    = self::updateCampaign($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $options['customer_id'], $options['campaign_id'], $options['status']);
            return true;
        }
        return false;
    }



    /**
     * 获取广告活动状态
     */
//    public function getCampaignStatus(int $campaignId)
//    {
//        // 从本地数据库获取状态
//        $campaign = CampaignModel::find($campaignId);
//        if (!$campaign) {
//            throw new ValidateException('Campaign not found');
//        }
//
//        // 获取 Google Ads 状态
//        $googleAdsStatus = $this->googleAdsClient->getCampaignStatus($campaignId);
//
//        // 返回 Google Ads 的状态
//        return $googleAdsStatus;
//    }


    /**
     * 获取 Google Ads Campaign 状态
     */
//    public function getCampaignStatus(int $campaignId)
//    {
//        try {
//            // 获取 Google Ads 客户端
//            $campaignServiceClient = $this->client->getCampaignServiceClient();
//
//            // 获取 Campaign 资源
//            $resourceName = "customers/{customer_id}/campaigns/{$campaignId}";
//            $campaign = $campaignServiceClient->getCampaign($resourceName);
//
//            return $campaign->getStatus();
//        } catch (ApiException $e) {
//            throw new \Exception("Google Ads API error: " . $e->getMessage());
//        }
//    }

}