<?php

namespace PloverCRM\Modules\ContactEnrichment\Services;

use DeviceDetector\DeviceDetector;
use PloverCRM\Core\Plugin;
use PloverCRM\Core\Services\SystemFieldProvisioner;
use PloverCRM\Core\Services\SystemFieldRegistry;

/**
 * Contact Enricher Service
 * 
 * Enriches contacts with UTM tracking, IP info, device detection, and more
 */
class ContactEnricher
{
    private const FIRST_TOUCH_TEXT_FIELDS = [
        'plover_crm_utm_id' => 'UTM ID',
        'plover_crm_utm_source' => 'UTM Source',
        'plover_crm_utm_medium' => 'UTM Medium',
        'plover_crm_utm_campaign' => 'UTM Campaign',
        'plover_crm_utm_term' => 'UTM Term',
        'plover_crm_utm_content' => 'UTM Content',
        'plover_crm_gclid' => 'Google Click ID',
        'plover_crm_fbclid' => 'Facebook Click ID',
        'plover_crm_msclkid' => 'Microsoft Click ID',
        'plover_crm_ttclid' => 'TikTok Click ID',
        'plover_crm_li_fat_id' => 'LinkedIn Click ID',
        'plover_crm_twclid' => 'Twitter Click ID',
        'plover_crm_referral_domain' => 'Referral Domain',
    ];
    private const LAST_TOUCH_TEXT_FIELDS = [
        'plover_crm_last_utm_source' => 'Last UTM Source',
        'plover_crm_last_utm_medium' => 'Last UTM Medium',
        'plover_crm_last_utm_campaign' => 'Last UTM Campaign',
        'plover_crm_last_utm_term' => 'Last UTM Term',
        'plover_crm_last_utm_content' => 'Last UTM Content',
        'plover_crm_last_referral_domain' => 'Last Referral Domain',
        'plover_crm_last_page_url' => 'Last Page URL',
    ];

    /**
     * Enrich contact with additional data
     */
    public static function enrichContact($subscriber_id, $userIp, $userAgent, $current_url, $tracking_context, string $providerId = ''): void
    {
        $container = Plugin::getInstance()->getContainer();
        $crmManager = $container->get('crm');
        $crm = $crmManager;

        if ($providerId !== '' && method_exists($crmManager, 'getProviderById')) {
            $provider = $crmManager->getProviderById($providerId);
            if ($provider) {
                $crm = $provider;
            }
        }

        if (!$crm->isAvailable()) {
            return;
        }

        // Load subscriber
        $subscriber = $crm->getContact($subscriber_id);

        if (!$subscriber) {
            return;
        }

        $trackingContext = is_array($tracking_context) ? $tracking_context : [];
        $trackingCookies = is_array($trackingContext['cookies'] ?? null) ? $trackingContext['cookies'] : [];
        $referrerDomain = sanitize_text_field($trackingContext['referrer_domain'] ?? '');
        $currentPageUrl = !empty($current_url) ? esc_url_raw($current_url) : '';

        // Provision enrichment-owned system fields only when the capability
        // is actually being used.
        $provisioner = new SystemFieldProvisioner($container);
        $provisioner->ensureCapabilityIfActive(SystemFieldRegistry::CAPABILITY_TRACKING_ENRICHMENT, $crm);

        // Get existing custom field values
        $customFields = self::normalizeExistingCustomFields($crm->getContactCustomFields($subscriber));

        // Base update payload
        $updateData = [
            'id' => $subscriber_id,
            'email' => $subscriber['email'],
            'custom_fields' => []
        ];

        // 1) IP info
        if ($userIp) {
            $ipInfo = self::fetchIpInfo($userIp);
            if ($ipInfo) {
                if (empty($customFields['plover_crm_ip_info'])) {
                    $updateData['custom_fields']['plover_crm_ip_info'] = json_encode($ipInfo, JSON_PRETTY_PRINT);
                }
                if (empty($subscriber['city']) && !empty($ipInfo['city'])) {
                    $updateData['city'] = $ipInfo['city'];
                }
                if (empty($subscriber['country']) && !empty($ipInfo['country_code'])) {
                    $updateData['country'] = $ipInfo['country_code'];
                }
            }
        }

        // 2) Device info via DeviceDetector
        $dd = new DeviceDetector($userAgent);
        $dd->parse();

        $fieldsMap = [
            'plover_crm_device_type' => $dd->getDeviceName(),
            'plover_crm_device_brand' => $dd->getBrandName(),
            'plover_crm_user_os' => $dd->getOs()['name'] ?? '',
            'plover_crm_browser_name' => $dd->getClient()['name'] ?? ''
        ];

        foreach ($fieldsMap as $slug => $value) {
            if ($value) {
                $updateData['custom_fields'][$slug] = $value;
            }
        }

        // 3) Store first-touch attribution fields only once
        self::applyFirstTouchFields($updateData['custom_fields'], $customFields, $trackingCookies);

        // 4) Store the actual submission page URL. This should reflect the
        // latest touch, not only the first one.
        if ($currentPageUrl) {
            $updateData['custom_fields']['plover_crm_submission_url'] = $currentPageUrl;
        }

        // 5) Update last-touch attribution fields whenever new values exist
        self::applyLastTouchFields($updateData['custom_fields'], $trackingCookies, $currentPageUrl, $referrerDomain);

        // Assign first option of stage field only if not already set
        $stageFieldSlug = 'stage-plover-crm';
        if (empty($customFields[$stageFieldSlug])) {
            $stageOptions = $crm->getCustomFieldOptions($stageFieldSlug);

            if (!empty($stageOptions)) {
                $firstOption = reset($stageOptions);
                $updateData['custom_fields'][$stageFieldSlug] = $firstOption;
            }
        }

        // Final update if we have anything to set
        if (!empty($updateData['custom_fields']) || isset($updateData['city']) || isset($updateData['country'])) {
            $updateData = $crm->sanitizeContactData($updateData);
            $crm->createOrUpdateContact($updateData);
        }
    }

    /**
     * Fetch IP information from external API
     */
    private static function fetchIpInfo($ip)
    {
        $response = wp_remote_get("https://ipwho.is/$ip");
        if (is_wp_error($response)) {
            return null;
        }
        $body = wp_remote_retrieve_body($response);
        return json_decode($body, true);
    }

    private static function applyFirstTouchFields(array &$updateCustomFields, array $existingCustomFields, array $trackingCookies): void
    {
        foreach (self::FIRST_TOUCH_TEXT_FIELDS as $slug => $label) {
            unset($label);

            if (!empty($existingCustomFields[$slug])) {
                continue;
            }

            $value = self::sanitizeTrackingValue($slug, $trackingCookies[$slug] ?? '');
            if ($value === '') {
                continue;
            }

            $updateCustomFields[$slug] = $value;
        }

        if (empty($existingCustomFields['plover_crm_landing_page_first_visit'])) {
            $value = self::sanitizeTrackingValue(
                'plover_crm_landing_page_first_visit',
                $trackingCookies['plover_crm_landing_page_first_visit'] ?? ''
            );
            if ($value !== '') {
                $updateCustomFields['plover_crm_landing_page_first_visit'] = $value;
            }
        }

        if (empty($existingCustomFields['plover_crm_landing_datetime_first_visit'])) {
            $value = self::sanitizeTrackingValue(
                'plover_crm_landing_datetime_first_visit',
                $trackingCookies['plover_crm_landing_datetime_first_visit'] ?? ''
            );
            if ($value !== '') {
                $updateCustomFields['plover_crm_landing_datetime_first_visit'] = $value;
            }
        }
    }

    private static function applyLastTouchFields(array &$updateCustomFields, array $trackingCookies, string $currentPageUrl, string $referrerDomain): void
    {
        foreach (self::LAST_TOUCH_TEXT_FIELDS as $slug => $label) {
            unset($label);

            $value = '';

            if ($slug === 'plover_crm_last_page_url') {
                $value = $currentPageUrl ?: ($trackingCookies[$slug] ?? '');
            } elseif ($slug === 'plover_crm_last_referral_domain') {
                $value = $referrerDomain ?: ($trackingCookies[$slug] ?? '');
            } else {
                $value = $trackingCookies[$slug] ?? '';
            }

            $value = self::sanitizeTrackingValue($slug, $value);
            if ($value === '') {
                continue;
            }

            $updateCustomFields[$slug] = $value;
        }

        $lastSeenAt = self::sanitizeTrackingValue(
            'plover_crm_last_seen_at',
            $trackingCookies['plover_crm_last_seen_at'] ?? ''
        );

        if ($lastSeenAt !== '') {
            $updateCustomFields['plover_crm_last_seen_at'] = $lastSeenAt;
        }
    }

    private static function sanitizeTrackingValue(string $slug, $value): string
    {
        if (!is_scalar($value)) {
            return '';
        }

        $value = wp_unslash((string) $value);
        if ($value === '') {
            return '';
        }

        if (str_ends_with($slug, '_url') || str_contains($slug, '_page_')) {
            return esc_url_raw($value);
        }

        if (str_ends_with($slug, '_at') || str_ends_with($slug, '_datetime_first_visit')) {
            return sanitize_text_field($value);
        }

        return sanitize_text_field($value);
    }

    private static function normalizeExistingCustomFields(array $customFields): array
    {
        $normalized = [];

        foreach ($customFields as $key => $value) {
            if (is_string($key)) {
                $normalized[$key] = $value;
                continue;
            }

            if (!is_array($value) || empty($value['key'])) {
                continue;
            }

            $normalized[(string) $value['key']] = $value['value'] ?? '';
        }

        return $normalized;
    }
}
