<?php

namespace PloverCRM\Modules\Integrations\Providers;

/**
 * Elementor Forms Provider
 * 
 * Integrates with Elementor Pro Forms
 */
class ElementorFormProvider implements DataSourceProviderInterface
{
  private $eventCallback;

  public function getKey(): string
  {
    return 'elementor_forms';
  }

  public function getName(): string
  {
    return 'Elementor Forms';
  }

  public function getIcon(): string
  {
    return 'elementor-forms.svg';
  }

  public function getCategory(): string
  {
    return 'forms';
  }

  public function isAvailable(): bool
  {
    return defined('ELEMENTOR_PRO_VERSION') && class_exists('\ElementorPro\Modules\Forms\Module');
  }

  public function getSupportedEvents(): array
  {
    return [
      ['key' => 'submission', 'label' => 'Form Submission'],
    ];
  }

  public function getSources(): array
  {
    if (!$this->isAvailable()) {
      return [];
    }

    return $this->findElementorForms();
  }

  public function getSourceFields(string $sourceId): array
  {
    if (!$this->isAvailable()) {
      return [];
    }

    // sourceId format: post_id_element_id
    $parts = explode('_', $sourceId, 2);
    if (count($parts) !== 2) {
      return [];
    }

    $postId = intval($parts[0]);
    $elementId = $parts[1];

    return $this->getFormFields($postId, $elementId);
  }

  public function registerEventListener(callable $callback): void
  {
    $this->eventCallback = $callback;
    add_action('elementor_pro/forms/new_record', [$this, 'handleSubmission'], 20, 2);
  }

  /**
   * Handle Elementor form submission
   */
  public function handleSubmission($record, $handler): void
  {
    unset($handler); // Not used, but required by hook signature

    if (!$this->eventCallback) {
      return;
    }

    $formSettings = $record->get('form_settings');
    $postId = $formSettings['form_post_id'] ?? 0;
    $elementId = $formSettings['id'] ?? '';

    if (!$postId || !$elementId) {
      return;
    }

    // Build source ID
    $sourceId = $postId . '_' . $elementId;

    // Get form data
    $fields = $record->get('fields');
    $normalized = [];

    foreach ($fields as $fieldId => $field) {
      $normalized[$fieldId] = $field['value'] ?? '';
    }

    call_user_func($this->eventCallback, $this->getKey(), $sourceId, $normalized);
  }

  /**
   * Find all Elementor forms across the site
   */
  private function findElementorForms(): array
  {
    $forms = [];

    // Query posts that might contain Elementor forms
    $posts = get_posts([
      'post_type' => ['page', 'post', 'elementor_library'],
      'posts_per_page' => -1,
      'post_status' => 'publish',
      'meta_query' => [
        [
          'key' => '_elementor_data',
          'compare' => 'EXISTS',
        ],
      ],
    ]);

    foreach ($posts as $post) {
      $elementorData = get_post_meta($post->ID, '_elementor_data', true);

      if (empty($elementorData)) {
        continue;
      }

      $elements = json_decode($elementorData, true);

      if (!is_array($elements)) {
        continue;
      }

      $postForms = $this->extractFormsFromElements($elements, $post);

      foreach ($postForms as $form) {
        $forms[] = $form;
      }
    }

    return $forms;
  }

  /**
   * Recursively extract form widgets from Elementor elements
   */
  private function extractFormsFromElements(array $elements, $post): array
  {
    $forms = [];

    foreach ($elements as $element) {
      // Check if this is a form widget
      if (isset($element['widgetType']) && $element['widgetType'] === 'form') {
        $formName = $element['settings']['form_name'] ?? 'Untitled Form';
        $elementId = $element['id'] ?? '';

        if ($elementId) {
          $forms[] = [
            'id' => $post->ID . '_' . $elementId,
            'title' => $formName . ' (' . $post->post_title . ')',
          ];
        }
      }

      // Recursively check nested elements
      if (!empty($element['elements'])) {
        $nestedForms = $this->extractFormsFromElements($element['elements'], $post);
        $forms = array_merge($forms, $nestedForms);
      }
    }

    return $forms;
  }

  /**
   * Get fields from a specific Elementor form
   */
  private function getFormFields(int $postId, string $elementId): array
  {
    $elementorData = get_post_meta($postId, '_elementor_data', true);

    if (empty($elementorData)) {
      return [];
    }

    $elements = json_decode($elementorData, true);

    if (!is_array($elements)) {
      return [];
    }

    $formElement = $this->findFormElement($elements, $elementId);

    if (!$formElement) {
      return [];
    }

    $formFields = $formElement['settings']['form_fields'] ?? [];
    $fields = [];

    foreach ($formFields as $field) {
      $fieldType = $field['field_type'] ?? 'text';

      // Skip non-input fields
      if (in_array($fieldType, ['html', 'recaptcha', 'recaptcha_v3', 'step'])) {
        continue;
      }

      $customId = $field['custom_id'] ?? '';
      $label = $field['field_label'] ?? '';

      if (empty($customId)) {
        continue;
      }

      $fields[] = [
        'key' => $customId,
        'label' => $label ?: ucfirst(str_replace('_', ' ', $customId)),
        'type' => $this->mapFieldType($fieldType),
      ];
    }

    return $fields;
  }

  /**
   * Recursively find a form element by ID
   */
  private function findFormElement(array $elements, string $elementId): ?array
  {
    foreach ($elements as $element) {
      if (isset($element['id']) && $element['id'] === $elementId) {
        return $element;
      }

      if (!empty($element['elements'])) {
        $found = $this->findFormElement($element['elements'], $elementId);
        if ($found) {
          return $found;
        }
      }
    }

    return null;
  }

  /**
   * Map Elementor field types to standard types
   */
  private function mapFieldType(string $elementorType): string
  {
    $map = [
      'text' => 'text',
      'email' => 'email',
      'textarea' => 'textarea',
      'url' => 'url',
      'tel' => 'phone',
      'number' => 'number',
      'date' => 'date',
      'time' => 'time',
      'select' => 'select',
      'radio' => 'radio',
      'checkbox' => 'checkbox',
      'acceptance' => 'checkbox',
      'upload' => 'file',
      'password' => 'text',
      'hidden' => 'hidden',
    ];

    return $map[$elementorType] ?? 'text';
  }
}
