<?php

namespace PloverCRM\Modules\ContactEnrichment;

use PloverCRM\Common\Hooks;
use PloverCRM\Common\WebhookContextStore;
use PloverCRM\Core\AbstractModule;

/**
 * Contact Enrichment Module
 * 
 * Enriches contacts with UTM tracking, IP info, device detection, and more
 */
class ContactEnrichmentModule extends AbstractModule
{
    protected $id = 'contact_enrichment';
    protected $dependencies = [];
    private static bool $isEnrichingContact = false;

    /**
     * {@inheritdoc}
     */
    public function getMetadata(): array
    {
        return [
            'name' => 'Contact Enrichment',
            'description' => 'Enriches contacts with UTM tracking, IP info, device detection, and more',
            'version' => '1.0.0',
            'author' => 'WebPlover',
            'required' => false,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function register(): void
    {
        add_action('rest_api_init', [$this, 'registerEndpoints']);
    }

    /**
     * {@inheritdoc}
     */
    public function boot(): void
    {
        Database\PostCreateJobSchema::maybeCreateTable();

        // Hook into CRM contact creation (generic hook)
        add_action('plover_crm/contact_created', [$this, 'handleContactCreated'], 10, 2);
        add_action('plover_crm/contact_touched', [$this, 'handleContactTouched'], 10, 3);

        // Register the post-create processing pipeline
        add_action('plover_crm_after_contact_created_actions', [$this, 'enrichContact'], 10, 6);
    }

    public function registerEndpoints(): void
    {
        $this->registerModuleEndpoint(new Endpoints\PostCreateJobCallbackEndpoint($this->container));
    }

    /**
     * {@inheritdoc}
     */
    public function isEnabled(): bool
    {
        // Only load if CRM is available
        $crm = $this->container->get('crm');
        return $crm->isAvailable();
    }

    /**
     * Handle contact created event
     */
    public function handleContactCreated($subscriber_id, $subscriber): void
    {
        $this->scheduleContactEnrichment($subscriber_id, $subscriber);
    }

    /**
     * Handle contact touch event for repeat form/webhook submissions.
     */
    public function handleContactTouched($subscriber_id, $subscriber, $context): void
    {
        unset($context);
        $this->scheduleContactEnrichment($subscriber_id, $subscriber);
    }

    /**
     * Schedule contact enrichment with the current tracking context.
     */
    private function scheduleContactEnrichment($subscriber_id, $subscriber): void
    {
        // Skip during bulk import (any CRM)
        if (\PloverCRM\Common\Utils::isBulkImporting() || self::$isEnrichingContact) {
            return;
        }

        $crm = $this->container->get('crm');
        $providerId = method_exists($crm, 'getSelectedProviderId')
            ? (string) $crm->getSelectedProviderId()
            : '';
        if ($providerId === '') {
            return;
        }

        $excluded_list_titles = ['App_Leads_Form', 'No_Email'];
        $excluded_list_ids = \PloverCRM\Common\Utils::getCrmListIdsByNames($excluded_list_titles);

        $source = sanitize_text_field((string) ($subscriber['source'] ?? ''));

        $lists = $crm->getContactLists($subscriber);
        $subscriber_list_ids = array_column($lists, 'id');
        if (array_intersect($subscriber_list_ids, $excluded_list_ids)) {
            return;
        }

        $cookieKeys = Hooks::getTrackingCookieKeys();
        $trackingContext = [
            'cookies' => [],
            'referrer_url' => '',
            'referrer_domain' => '',
        ];
        $currentPageUrl = '';

        // Handle webhook vs browser data
        // Only webhook-origin contacts need the webhook context store. Form
        // integrations can use different source labels (for example,
        // "FluentForms") and should still be enriched on creation.
        if ($this->isWebhookSource($source)) {
            $webhookContext = WebhookContextStore::has()
                ? WebhookContextStore::current()
                : WebhookContextStore::buildFromRequest();

            $userIp = $webhookContext['user_ip'] ?? ($subscriber['ip'] ?? null);
            $userAgent = $webhookContext['user_agent'] ?? ($_SERVER['HTTP_USER_AGENT'] ?? '');
            $trackingContext['referrer_url'] = $webhookContext['referrer_url'] ?? Hooks::getRefererUrl();
            $trackingContext['referrer_domain'] = $webhookContext['referrer_domain'] ?? Hooks::getExternalRefererDomain($trackingContext['referrer_url']);
            $currentPageUrl = $webhookContext['current_url'] ?? '';

            $cookieData = [];
            $webhookCookies = is_array($webhookContext['cookies'] ?? null)
                ? $webhookContext['cookies']
                : [];
            foreach ($cookieKeys as $key) {
                $cookieData[$key] = $webhookCookies[$key] ?? '';
            }

            if (empty($currentPageUrl)) {
                $currentPageUrl = $cookieData['plover_crm_last_page_url'] ?? '';
            }

            $trackingContext['cookies'] = $cookieData;
        } else {
            $userIp = !empty($subscriber['ip']) ? $subscriber['ip'] : \PloverCRM\Common\IpHandler::getRealUserIp();
            $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
            $trackingContext['referrer_url'] = Hooks::getRefererUrl();
            $trackingContext['referrer_domain'] = Hooks::getExternalRefererDomain($trackingContext['referrer_url']);

            // Pick only required cookies from browser
            $cookieData = [];
            foreach ($cookieKeys as $key) {
                $cookieData[$key] = $_COOKIE[$key] ?? '';
            }

            $trackingContext['cookies'] = $cookieData;
            $currentPageUrl = $this->resolveBrowserPageUrl(
                Hooks::getCurrentUrl(),
                $trackingContext['referrer_url'],
                $cookieData['plover_crm_last_page_url'] ?? ''
            );
        }

        $payload = [
            'provider_id' => $providerId,
            'subscriber_id' => (int) $subscriber_id,
            'user_ip' => $userIp,
            'user_agent' => $userAgent,
            'current_url' => $currentPageUrl,
            'tracking_context' => $trackingContext,
        ];

        (new Services\PostCreateJobManager($this->container))->schedule($payload);
    }

    /**
     * Enrich contact with additional data
     */
    public function enrichContact($subscriber_id, $userIp, $userAgent, $current_url, $tracking_context, $provider_id = ''): void
    {
        self::$isEnrichingContact = true;

        try {
            Services\ContactEnricher::enrichContact($subscriber_id, $userIp, $userAgent, $current_url, $tracking_context, (string) $provider_id);
        } finally {
            self::$isEnrichingContact = false;
        }
    }

    /**
     * Resolve the actual frontend page URL for browser-originated requests.
     * Form submissions arrive via admin-ajax, so prefer the referring page or
     * the last tracked page cookie over the raw request URL in that case.
     */
    private function resolveBrowserPageUrl(string $requestUrl, string $refererUrl, string $lastTrackedPageUrl): string
    {
        $requestUrl = $this->sanitizeUrl($requestUrl);
        $refererUrl = $this->sanitizeUrl($refererUrl);
        $lastTrackedPageUrl = $this->sanitizeUrl($lastTrackedPageUrl);

        if (
            $requestUrl !== '' &&
            !str_contains($requestUrl, '/wp-admin/admin-ajax.php')
        ) {
            return $requestUrl;
        }

        if ($refererUrl !== '') {
            return $refererUrl;
        }

        return $lastTrackedPageUrl;
    }

    private function isWebhookSource(string $source): bool
    {
        return $source === 'Webhook';
    }

    private function sanitizeUrl(string $url): string
    {
        return $url !== '' ? esc_url_raw($url) : '';
    }
}
