<?php

namespace PloverCRM\Modules\Integrations\Services;

use Exception;
use WP_Error;

/**
 * Google Ads API Service
 * 
 * Handles interaction with Google Ads API for fetching accounts and conversions.
 * Token management is handled by GoogleTokenService via the PloverCRM backend.
 */
class GoogleAdsService
{
    private const API_BASE = 'https://googleads.googleapis.com/v23/customers';

    private GoogleTokenService $tokenService;

    public function __construct()
    {
        $this->tokenService = new GoogleTokenService();
    }

    /**
     * Get valid access token from token service
     */
    public function getAccessToken(): string
    {
        return $this->tokenService->getValidAccessToken();
    }

    /**
     * List Accessible Customers (Accounts)
     */
    public function listAccessibleCustomers(string $developerToken): array
    {
        $accessToken = $this->getAccessToken();
        $url = self::API_BASE . ':listAccessibleCustomers';

        $response = wp_remote_get($url, [
            'headers' => [
                'Authorization' => 'Bearer ' . $accessToken,
                'developer-token' => $developerToken,
            ]
        ]);

        if (is_wp_error($response)) {
            throw new Exception($response->get_error_message());
        }

        $httpCode = wp_remote_retrieve_response_code($response);
        $rawBody = wp_remote_retrieve_body($response);

        $body = json_decode($rawBody, true);

        if (isset($body['error'])) {
            throw new Exception($body['error']['message'] ?? 'Unknown API Error');
        }

        $customers = [];
        if (!empty($body['resourceNames'])) {
            foreach ($body['resourceNames'] as $resourceName) {
                // Extract ID: customers/1234567890 -> 1234567890
                $id = str_replace('customers/', '', $resourceName);
                $customers[] = [
                    'id' => $id,
                    'name' => 'Account ' . $id // Placeholder until we can fetch details
                ];
            }
        }

        return $customers;
    }

    /**
     * Get Conversion Actions for a Customer
     */
    public function getConversionActions(string $developerToken, string $customerId): array
    {
        $accessToken = $this->getAccessToken();
        $url = str_replace('customers', "customers/{$customerId}/googleAds:search", self::API_BASE);

        $query = "SELECT conversion_action.id, conversion_action.name, conversion_action.type, conversion_action.status FROM conversion_action WHERE conversion_action.status = 'ENABLED'";

        $response = wp_remote_post($url, [
            'headers' => [
                'Authorization' => 'Bearer ' . $accessToken,
                'developer-token' => $developerToken,
                'Content-Type' => 'application/json'
            ],
            'body' => json_encode([
                'query' => $query
            ])
        ]);

        if (is_wp_error($response)) {
            throw new Exception($response->get_error_message());
        }

        $body = json_decode(wp_remote_retrieve_body($response), true);

        if (isset($body['error'])) {
            throw new Exception($body['error']['message'] ?? 'Unknown API Error');
        }

        $actions = [];
        if (!empty($body['results'])) {
            foreach ($body['results'] as $row) {
                $actions[] = [
                    'id' => $row['conversionAction']['id'],
                    'name' => $row['conversionAction']['name'],
                    'type' => $row['conversionAction']['type']
                ];
            }
        }

        return $actions;
    }

    /**
     * Get customer-level lead upload readiness settings from Google Ads.
     *
     * @throws Exception
     */
    public function getLeadUploadSettings(string $developerToken, string $customerId, ?string $managerId = null): array
    {
        $accessToken = $this->getAccessToken();
        $url = str_replace('customers', "customers/{$customerId}/googleAds:search", self::API_BASE);

        $headers = [
            'Authorization' => 'Bearer ' . $accessToken,
            'developer-token' => $developerToken,
            'Content-Type' => 'application/json',
        ];

        if (!empty($managerId)) {
            $headers['login-customer-id'] = $managerId;
        }

        $query = "SELECT customer.conversion_tracking_setting.accepted_customer_data_terms, customer.conversion_tracking_setting.enhanced_conversions_for_leads_enabled FROM customer";

        $response = wp_remote_post($url, [
            'headers' => $headers,
            'body' => wp_json_encode([
                'query' => $query,
            ]),
        ]);

        if (is_wp_error($response)) {
            throw new Exception($response->get_error_message());
        }

        $body = json_decode(wp_remote_retrieve_body($response), true);

        if (isset($body['error'])) {
            $errorMessage = $body['error']['message'] ?? 'Unknown API Error';

            if (isset($body['error']['details'])) {
                $errorMessage .= ' Details: ' . wp_json_encode($body['error']['details']);
            }

            throw new Exception($errorMessage);
        }

        $settings = $body['results'][0]['customer']['conversionTrackingSetting'] ?? null;
        if (!is_array($settings)) {
            throw new Exception('Google Ads did not return conversion tracking settings for this customer.');
        }

        return [
            'accepted_customer_data_terms' => !empty($settings['acceptedCustomerDataTerms']),
            'enhanced_conversions_for_leads_enabled' => !empty($settings['enhancedConversionsForLeadsEnabled']),
        ];
    }

    /**
     * Create an offline conversion action in Google Ads
     * 
     * @param string $developerToken Google Ads developer token
     * @param string $customerId Google Ads customer ID
     * @param string $name Conversion action name (typically stage name)
     * @param string|null $managerId Manager account ID (for login-customer-id header)
     * @return array ['resourceName' => '...', 'isNew' => bool] Conversion action resource name and whether it was newly created
     * @throws Exception
     */
    public function createOfflineConversionAction(string $developerToken, string $customerId, string $name, ?string $managerId = null): array
    {
        $accessToken = $this->getAccessToken();
        $url = self::API_BASE . "/{$customerId}/conversionActions:mutate";

        $headers = [
            'Authorization' => 'Bearer ' . $accessToken,
            'developer-token' => $developerToken,
            'Content-Type' => 'application/json'
        ];

        // Add login-customer-id if manager account is provided
        if (!empty($managerId)) {
            $headers['login-customer-id'] = $managerId;
        }

        $body = [
            'operations' => [
                [
                    'create' => [
                        'name' => $name,
                        'type' => 'UPLOAD_CLICKS',
                        'status' => 'ENABLED',
                        'category' => 'DEFAULT'
                    ]
                ]
            ]
        ];

        $response = wp_remote_post($url, [
            'headers' => $headers,
            'body' => json_encode($body)
        ]);

        if (is_wp_error($response)) {
            throw new Exception($response->get_error_message());
        }

        $httpCode = wp_remote_retrieve_response_code($response);
        $rawBody = wp_remote_retrieve_body($response);
        $responseData = json_decode($rawBody, true);

        if (isset($responseData['error'])) {
            // Check if it's a duplicate name error - check multiple possible structures
            $isDuplicateName = false;
            
            // Try different possible error structure paths
            if (!empty($responseData['error']['details']) && is_array($responseData['error']['details'])) {
                foreach ($responseData['error']['details'] as $detail) {
                    if (!empty($detail['errors']) && is_array($detail['errors'])) {
                        foreach ($detail['errors'] as $err) {
                            if (isset($err['errorCode']['conversionActionError']) && $err['errorCode']['conversionActionError'] === 'DUPLICATE_NAME') {
                                $isDuplicateName = true;
                                break 2;
                            }
                        }
                    }
                }
            }
            
            if ($isDuplicateName) {
                // Try to find existing conversion action with this name
                $existingActions = $this->getConversionActions($developerToken, $customerId);
                foreach ($existingActions as $action) {
                    if ($action['name'] === $name) {
                        return [
                            'resourceName' => "customers/{$customerId}/conversionActions/{$action['id']}",
                            'isNew' => false
                        ];
                    }
                }
            }
            
            $errorMsg = $responseData['error']['message'] ?? 'Failed to create conversion action';
            if (isset($responseData['error']['details'])) {
                $errorMsg .= ' Details: ' . json_encode($responseData['error']['details']);
            }
            throw new Exception($errorMsg);
        }

        // Extract resource name from response
        if (!empty($responseData['results'][0]['resourceName'])) {
            return [
                'resourceName' => $responseData['results'][0]['resourceName'],
                'isNew' => true
            ];
        }

        throw new Exception('Conversion action created but no resource name returned');
    }

    /**
     * Helper to normalize and hash data (SHA-256)
     */
    public static function hashData(string $data): string
    {
        return hash('sha256', strtolower(trim($data)));
    }
}
