<?php

declare(strict_types=1);

namespace PloverCRM\Modules\Integrations\Endpoints;

use PloverCRM\Common\WebhookContextStore;
use WP_REST_Request;
use WP_REST_Response;
use PloverCRM\Core\Api\AbstractEndpoint;
use PloverCRM\Modules\Integrations\Services\WebhookService;
use PloverCRM\Modules\Integrations\Services\DataSourceService;
use PloverCRM\Modules\Integrations\Services\WebhooksLogger;

/**
 * Incoming Webhook Endpoint
 * 
 * Public endpoint that receives POST data from external systems.
 * URL: /wp-json/plover-crm/v1/webhook/incoming/{token}
 */
class IncomingWebhookEndpoint extends AbstractEndpoint
{
  public function getRoute(): string
  {
    return '/webhook/incoming/(?P<token>[a-f0-9]{32})';
  }

  public function getMethod(): string
  {
    return 'POST';
  }

  /**
   * Public endpoint — no auth required.
   * Security is via the unique token in the URL.
   */
  public function checkPermission(WP_REST_Request $request)
  {
    return true;
  }

  public function handle(WP_REST_Request $request)
  {
    $token = $request->get_param('token');

    // Look up webhook by token
    $webhook = WebhookService::getByToken($token);

    if (!$webhook) {
      return new WP_REST_Response(['error' => 'Invalid webhook'], 404);
    }

    if ($webhook['status'] !== 'active') {
      return new WP_REST_Response(['error' => 'Webhook is inactive'], 403);
    }

    // Get payload from request body
    $payload = $request->get_json_params();

    if (empty($payload) || !is_array($payload)) {
      // Try form-encoded data as fallback
      $payload = $request->get_body_params();
    }

    if (empty($payload)) {
      return new WP_REST_Response(['error' => 'No data provided'], 400);
    }

    // Store last payload for field discovery
    WebhookService::storeLastPayload((int) $webhook['id'], $payload);

    WebhookContextStore::remember(
      WebhookContextStore::buildFromRequest($payload)
    );

    // Flatten nested data for processing
    $flatData = $this->flattenPayload($payload);

    // Log the incoming payload
    $logger = new WebhooksLogger();
    $logger->logPayloadReceived(
      $webhook['name'],
      (string) $webhook['id'],
      count($flatData),
      array_keys($flatData)
    );

    // Process through DataSourceService pipeline
    // This handles integration lookup, field mapping, conditions, CRM creation
    $service = new DataSourceService($this->container);
    $service->handleEvent('webhook', (string) $webhook['id'], $flatData);

    return new WP_REST_Response([
      'success' => true,
      'message' => 'Webhook received',
    ], 200);
  }

  /**
   * Flatten nested payload into dot-notation keys
   * Keeps both nested and flat versions so getNestedValue() works either way
   */
  private function flattenPayload(array $data, string $prefix = ''): array
  {
    $flat = [];

    foreach ($data as $key => $value) {
      $fullKey = $prefix === '' ? (string) $key : $prefix . '.' . $key;

      if (is_array($value) && !$this->isIndexedArray($value)) {
        // Associative array — recurse and flatten
        $flat = array_merge($flat, $this->flattenPayload($value, $fullKey));
      } else {
        $flat[$fullKey] = $value;
      }
    }

    return $flat;
  }

  /**
   * Check if array is numerically indexed
   */
  private function isIndexedArray(array $arr): bool
  {
    if (empty($arr)) return true;
    return array_keys($arr) === range(0, count($arr) - 1);
  }
}
