<?php

declare(strict_types=1);

namespace Drupal\native_observability\Service;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Database\Connection;

/**
 * Cleans up retained execution span records.
 */
final class SpansCleanupHandler implements ObservabilityCleanupHandlerInterface {

  public function __construct(
    private readonly Connection $database,
    private readonly TimeInterface $time,
  ) {
  }

  /**
   * Gets the cleanup handler identifier.
   */
  public function id(): string {
    return 'spans';
  }

  /**
   * Checks whether the spans table is available for cleanup.
   */
  public function isAvailable(): bool {
    if (!$this->database->schema()->tableExists('native_observability_spans')) {
      return FALSE;
    }

    $schema = $this->database->schema();
    return $schema->fieldExists('native_observability_spans', 'created_at')
      || $schema->fieldExists('native_observability_spans', 'started_at')
      || $schema->fieldExists('native_observability_spans', 'start_time');
  }

  /**
   * Removes stale span records according to the configured retention.
   *
   * @param array<string, mixed> $settings
   *   Cleanup settings.
   *
   * @return int
   *   The number of deleted records.
   */
  public function cleanup(array $settings): int {
    if (!$this->isAvailable()) {
      return 0;
    }

    $hours = max(1, (int) ($settings['spans_retention_hours'] ?? 24));
    $threshold = $this->time->getCurrentTime() - ($hours * 3600);
    $limit = max(1, (int) ($settings['cleanup_batch_limit'] ?? 5000));

    $timestamp_field = 'started_at';
    $schema = $this->database->schema();

    if ($schema->fieldExists('native_observability_spans', 'created_at')) {
      $timestamp_field = 'created_at';
    }
    elseif ($schema->fieldExists('native_observability_spans', 'start_time')) {
      $timestamp_field = 'start_time';
    }

    $ids = $this->database->select('native_observability_spans', 's')
      ->fields('s', ['id'])
      ->condition($timestamp_field, $threshold, '<')
      ->range(0, $limit)
      ->execute()
      ->fetchCol();

    if (!$ids) {
      return 0;
    }

    return (int) $this->database->delete('native_observability_spans')
      ->condition('id', $ids, 'IN')
      ->execute();
  }

  /**
   * Removes all stored spans.
   *
   * @return int
   *   The number of deleted rows.
   */
  public function cleanupAll(): int {
    if (!$this->database->schema()->tableExists('native_observability_spans')) {
      return 0;
    }

    $count = (int) $this->database->select('native_observability_spans', 's')
      ->countQuery()
      ->execute()
      ->fetchField();

    if ($count === 0) {
      return 0;
    }

    $this->database->truncate('native_observability_spans')->execute();

    return $count;
  }

}
