<?php

namespace PloverCRM\Modules\Integrations\Providers;

/**
 * Gravity Forms Provider
 */
class GravityFormsProvider implements DataSourceProviderInterface
{
  private $eventCallback;

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

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

  public function getIcon(): string
  {
    return 'gravityforms.svg';
  }

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

  public function isAvailable(): bool
  {
    return class_exists('GFAPI') || class_exists('GFForms');
  }

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

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

    $forms = \GFAPI::get_forms(true, false);

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

    return array_map(fn($form) => [
      'id' => (string) $form['id'],
      'title' => $form['title'],
    ], $forms);
  }

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

    $form = \GFAPI::get_form(absint($sourceId));

    if (empty($form) || !isset($form['fields'])) {
      return [];
    }

    $extracted = [];

    foreach ($form['fields'] as $field) {
      $fieldId = $field->id ?? '';
      $fieldType = $field->type ?? '';
      $label = $field->label ?? ucfirst(str_replace('_', ' ', $fieldType));

      // Skip non-data fields
      if (in_array($fieldType, ['html', 'section', 'page', 'captcha', 'honeypot'])) {
        continue;
      }

      // Handle fields with inputs (name, address, etc.)
      if (!empty($field->inputs) && is_array($field->inputs)) {
        // For email fields with confirmation, only show the main email input
        // The confirmation input (x.2) doesn't store data in the entry
        if ($fieldType === 'email') {
          $extracted[] = [
            'key' => (string) $fieldId,
            'label' => $label,
            'type' => 'email',
          ];
          continue;
        }

        foreach ($field->inputs as $input) {
          // Skip hidden inputs
          if (!empty($input['isHidden'])) {
            continue;
          }

          $inputId = $input['id'] ?? '';
          $inputLabel = $input['label'] ?? '';

          if ($inputId && $inputLabel) {
            $extracted[] = [
              'key' => (string) $inputId,
              'label' => $label . ' (' . $inputLabel . ')',
              'type' => 'text',
            ];
          }
        }
        continue;
      }

      // Regular fields
      $extracted[] = [
        'key' => (string) $fieldId,
        'label' => $label,
        'type' => $this->mapFieldType($fieldType),
      ];
    }

    return $extracted;
  }

  public function registerEventListener(callable $callback): void
  {
    $this->eventCallback = $callback;
    add_filter('gform_entry_post_save', [$this, 'handleSubmission'], 20, 2);
  }

  /**
   * Handle Gravity Forms submission
   * 
   * @param array $entry The entry data
   * @param array $form  The form data
   * @return array The entry (unchanged)
   */
  public function handleSubmission($entry, $form): array
  {
    if (!$this->eventCallback) {
      return $entry;
    }

    $formId = $form['id'] ?? '';
    if (empty($formId)) {
      return $entry;
    }

    // Normalize field data for our system
    // Gravity Forms entry has field IDs as keys (e.g., '1', '2.3', '2.6')
    $normalized = [];

    foreach ($entry as $key => $value) {
      // Skip non-field keys (entry meta like id, form_id, date_created, etc.)
      // Field keys are numeric (e.g., '1', '2') or have a dot (e.g., '2.3', '2.6')
      if (!is_numeric($key) && strpos($key, '.') === false) {
        continue;
      }

      // Include all field values (both main fields and sub-fields)
      if ($value !== '' && $value !== null) {
        $normalized[(string) $key] = $value;
      }
    }

    call_user_func($this->eventCallback, $this->getKey(), (string) $formId, $normalized);

    return $entry;
  }

  private function mapFieldType(string $type): string
  {
    $map = [
      'text' => 'text',
      'textarea' => 'textarea',
      'email' => 'email',
      'website' => 'url',
      'number' => 'number',
      'phone' => 'phone',
      'date' => 'date',
      'time' => 'time',
      'select' => 'select',
      'radio' => 'radio',
      'checkbox' => 'checkbox',
      'multiselect' => 'multiselect',
      'fileupload' => 'file',
      'hidden' => 'hidden',
      'list' => 'list',
    ];
    return $map[$type] ?? 'text';
  }
}
