<?php

namespace PloverCRM\Modules\Integrations\Services;

/**
 * Serializes data source records into app-facing response shapes.
 */
class DataSourceApiSerializer
{
  public static function category(array $category, array $providers = []): array
  {
    $activeProviderCount = 0;

    foreach ($providers as $provider) {
      if (!empty($provider['available'])) {
        $activeProviderCount++;
      }
    }

    return [
      'key' => (string) ($category['key'] ?? ''),
      'label' => (string) ($category['label'] ?? ''),
      'iconUrl' => (string) ($category['icon'] ?? ''),
      'description' => (string) ($category['description'] ?? ''),
      'providerLabel' => (string) ($category['provider_label'] ?? 'Provider'),
      'sourceLabel' => (string) ($category['source_label'] ?? 'Source'),
      'sourcePlaceholder' => (string) ($category['source_placeholder'] ?? 'Select a source...'),
      'hasProviders' => !empty($category['has_providers']),
      'activeProviderCount' => $activeProviderCount,
      'providers' => array_map([self::class, 'provider'], $providers),
    ];
  }

  public static function provider(array $provider): array
  {
    return [
      'key' => (string) ($provider['key'] ?? ''),
      'name' => (string) ($provider['name'] ?? ''),
      'iconUrl' => (string) ($provider['icon'] ?? ''),
      'available' => !empty($provider['available']),
    ];
  }

  public static function integration($integration, DataSourceService $service): array
  {
    $record = is_array($integration) ? $integration : get_object_vars($integration);
    $providerKey = (string) ($record['provider'] ?? '');
    $sourceId = (string) ($record['source_id'] ?? '');

    $provider = $service->getProvider($providerKey);
    $providerInfo = $provider
      ? [
        'name' => $provider->getName(),
        'icon_url' => $service->getIconUrl($provider->getIcon()),
        'available' => true,
      ]
      : $service->getProviderInfo($providerKey);

    return [
      'id' => (int) ($record['id'] ?? 0),
      'name' => (string) ($record['name'] ?? ''),
      'category' => (string) ($record['category'] ?? ''),
      'providerKey' => $providerKey,
      'providerName' => (string) ($providerInfo['name'] ?? 'Unknown'),
      'providerIconUrl' => (string) ($providerInfo['icon_url'] ?? ''),
      'providerAvailable' => !empty($providerInfo['available']),
      'sourceId' => $sourceId,
      'sourceName' => self::resolveSourceName($provider, $sourceId),
      'eventType' => (string) ($record['event_type'] ?? 'default'),
      'fieldMappings' => array_map(function ($mapping) {
        return [
          'sourceField' => (string) ($mapping['source_field'] ?? $mapping['sourceField'] ?? ''),
          'crmField' => (string) ($mapping['crm_field'] ?? $mapping['crmField'] ?? ''),
        ];
      }, self::decodeJsonArray($record['field_mappings'] ?? [])),
      'lists' => array_map('intval', self::decodeJsonArray($record['lists'] ?? [])),
      'tags' => array_map('intval', self::decodeJsonArray($record['tags'] ?? [])),
      'options' => self::decodeJsonArray($record['options'] ?? []),
      'conditions' => self::decodeJsonArray($record['conditions'] ?? []),
      'status' => (string) ($record['status'] ?? 'active'),
      'createdAt' => $record['created_at'] ?? null,
      'updatedAt' => $record['updated_at'] ?? null,
    ];
  }

  public static function webhook(array $webhook): array
  {
    return [
      'id' => (int) ($webhook['id'] ?? 0),
      'name' => (string) ($webhook['name'] ?? ''),
      'status' => (string) ($webhook['status'] ?? 'inactive'),
      'url' => (string) ($webhook['url'] ?? WebhookService::getWebhookUrl((string) ($webhook['token'] ?? ''))),
      'hasPayload' => !empty($webhook['has_payload']) || !empty($webhook['last_payload']),
      'createdAt' => isset($webhook['created_at']) ? (int) $webhook['created_at'] : null,
      'updatedAt' => isset($webhook['updated_at']) ? (int) $webhook['updated_at'] : null,
    ];
  }

  public static function source(array $source): array
  {
    return [
      'id' => (string) ($source['id'] ?? ''),
      'title' => (string) ($source['title'] ?? ''),
      'url' => (string) ($source['url'] ?? ''),
      'status' => (string) ($source['status'] ?? ''),
      'pageId' => (string) ($source['page_id'] ?? ''),
      'pageName' => (string) ($source['page_name'] ?? ''),
      'hasPayload' => !empty($source['has_payload']),
    ];
  }

  public static function event(array $event): array
  {
    return [
      'value' => (string) ($event['key'] ?? ''),
      'label' => (string) ($event['label'] ?? ''),
    ];
  }

  public static function sourceField(array $field): array
  {
    return [
      'key' => (string) ($field['key'] ?? ''),
      'label' => (string) ($field['label'] ?? ''),
      'type' => (string) ($field['type'] ?? 'text'),
      'group' => (string) ($field['group'] ?? ''),
    ];
  }

  public static function crmField(array $field): array
  {
    return [
      'key' => (string) ($field['key'] ?? ''),
      'label' => (string) ($field['label'] ?? ''),
      'type' => (string) ($field['type'] ?? 'text'),
      'group' => (string) ($field['group'] ?? 'standard'),
      'required' => !empty($field['required']),
    ];
  }

  public static function crmItem(array $item): array
  {
    $title = (string) ($item['title'] ?? $item['name'] ?? '');

    return [
      'id' => isset($item['id']) ? (int) $item['id'] : 0,
      'title' => $title,
    ];
  }

  private static function resolveSourceName($provider, string $sourceId): string
  {
    if (!$provider) {
      return 'Plugin Inactive';
    }

    try {
      foreach ($provider->getSources() as $source) {
        if ((string) ($source['id'] ?? '') === $sourceId) {
          return (string) ($source['title'] ?? 'Unknown');
        }
      }
    } catch (\Throwable $e) {
      return 'Unknown';
    }

    return 'Unknown';
  }

  private static function decodeJsonArray($value): array
  {
    if (is_array($value)) {
      return $value;
    }

    if (is_string($value) && $value !== '') {
      $decoded = json_decode($value, true);
      return is_array($decoded) ? $decoded : [];
    }

    return [];
  }
}
