<?php

declare(strict_types=1);

namespace Drupal\flowdrop_trigger\Plugin\FlowDropEventType;

use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\flowdrop_trigger\Attribute\FlowDropEventType;
use Drupal\flowdrop_trigger\Enum\EventCategory;
use Drupal\flowdrop_trigger\Enum\TriggerExecutionMode;
use Drupal\flowdrop_trigger\FlowDropEventTypeInterface;

/**
 * Event type for cron run events.
 *
 * Triggers when Drupal's cron runs. This allows workflows to be scheduled
 * for periodic execution without relying on external cron services.
 *
 * Use cases:
 * - Periodic data synchronization
 * - Scheduled content publishing/unpublishing
 * - Automated cleanup tasks
 * - Report generation
 * - Cache warming
 *
 * Note: Cron events don't have an associated entity, so the trigger data
 * contains system-level information about the cron run.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
#[FlowDropEventType(
  id: "cron.run",
  label: new TranslatableMarkup("Cron Run"),
  description: new TranslatableMarkup("Triggered when Drupal cron runs"),
  category: EventCategory::Cron,
  defaultOrchestrator: "flowdrop_runtime:asynchronous",
  defaultExecutionMode: TriggerExecutionMode::Async,
  supportedEntityTypes: [],
)]
class CronRun extends PluginBase implements FlowDropEventTypeInterface {

  /**
   * {@inheritdoc}
   */
  public function getEventId(): string {
    return $this->getPluginId();
  }

  /**
   * {@inheritdoc}
   */
  public function getLabel(): string {
    $definition = $this->getPluginDefinition();
    $label = $definition["label"] ?? $this->getPluginId();
    return (string) $label;
  }

  /**
   * {@inheritdoc}
   */
  public function getDescription(): string {
    $definition = $this->getPluginDefinition();
    $description = $definition["description"] ?? "";
    return (string) $description;
  }

  /**
   * {@inheritdoc}
   */
  public function getCategory(): EventCategory {
    return EventCategory::Cron;
  }

  /**
   * {@inheritdoc}
   */
  public function getDefaultOrchestrator(): string {
    $definition = $this->getPluginDefinition();
    return $definition["defaultOrchestrator"] ?? "flowdrop_runtime:asynchronous";
  }

  /**
   * {@inheritdoc}
   */
  public function getDefaultExecutionMode(): TriggerExecutionMode {
    $definition = $this->getPluginDefinition();
    $mode = $definition["defaultExecutionMode"] ?? "async";
    if ($mode instanceof TriggerExecutionMode) {
      return $mode;
    }
    return TriggerExecutionMode::from($mode);
  }

  /**
   * {@inheritdoc}
   */
  public function getSupportedEntityTypes(): array {
    // Cron events don't have associated entity types.
    return [];
  }

  /**
   * {@inheritdoc}
   */
  public function supportsEntityType(string $entityType): bool {
    // Cron events are not entity-specific.
    return FALSE;
  }

  /**
   * {@inheritdoc}
   *
   * Extracts trigger data for cron events.
   *
   * Since cron events don't have an associated entity, this method
   * returns system-level information about the cron execution.
   *
   * @param \Drupal\Core\Entity\EntityInterface|null $entity
   *   Always NULL for cron events.
   * @param \Drupal\Core\Entity\EntityInterface|null $originalEntity
   *   Always NULL for cron events.
   * @param array<string, mixed> $context
   *   Additional context data including:
   *   - cron_key: The cron key used (if any)
   *   - last_run: Timestamp of last cron run
   *   - trigger_config_id: The trigger configuration ID
   *   - trigger_node_id: The trigger node ID.
   *
   * @return array<string, mixed>
   *   The extracted trigger data.
   */
  public function extractTriggerData(
    ?EntityInterface $entity,
    ?EntityInterface $originalEntity = NULL,
    array $context = [],
  ): array {
    $timestamp = time();

    return [
      "event_type" => $this->getEventId(),
      "timestamp" => $timestamp,
      "operation" => "cron_run",
      "cron_key" => $context["cron_key"] ?? NULL,
      "last_run" => $context["last_run"] ?? NULL,
      "trigger_config_id" => $context["trigger_config_id"] ?? "",
      "trigger_node_id" => $context["trigger_node_id"] ?? "",
      "trigger_execution" => TRUE,
      "execution_source" => "cron_trigger",
      "trigger_timestamp" => $timestamp,
      "trigger_type" => "cron",
    ];
  }

  /**
   * {@inheritdoc}
   *
   * Returns the parameter schema for cron triggers.
   *
   * Includes comprehensive scheduling configuration for both simple
   * (interval-based) and advanced (cron expression) modes.
   */
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "title" => "Cron Trigger Configuration",
      "description" => "Configuration for cron-based workflow triggers with scheduling options.",
      "properties" => [
        "description" => [
          "type" => "string",
          "title" => "Description",
          "description" => "A description of what this cron trigger does.",
        ],
        "cron_schedule" => [
          "type" => "object",
          "title" => "Schedule Configuration",
          "description" => "Configure when and how often this trigger should fire.",
          "properties" => [
            "mode" => [
              "type" => "string",
              "title" => "Schedule Mode",
              "description" => "Choose between simple interval-based scheduling or advanced cron expressions.",
              "oneOf" => [
                ["const" => "simple", "title" => "Simple (Interval)"],
                ["const" => "advanced", "title" => "Advanced (Cron Expression)"],
              ],
              "default" => "simple",
            ],
            "schedule_type" => [
              "type" => "string",
              "title" => "Schedule Type",
              "description" => "Recurring runs continuously, One-shot runs a limited number of times.",
              "oneOf" => [
                ["const" => "recurring", "title" => "Recurring"],
                ["const" => "one_shot", "title" => "One-shot (Limited Runs)"],
              ],
              "default" => "recurring",
            ],
            // Simple mode settings.
            "interval" => [
              "type" => "string",
              "title" => "Run Interval",
              "description" => "How often the trigger should fire.",
              "oneOf" => [
                ["const" => "every_minute", "title" => "Every minute"],
                ["const" => "every_5_minutes", "title" => "Every 5 minutes"],
                ["const" => "every_15_minutes", "title" => "Every 15 minutes"],
                ["const" => "every_30_minutes", "title" => "Every 30 minutes"],
                ["const" => "every_hour", "title" => "Every hour"],
                ["const" => "every_2_hours", "title" => "Every 2 hours"],
                ["const" => "every_6_hours", "title" => "Every 6 hours"],
                ["const" => "every_12_hours", "title" => "Every 12 hours"],
                ["const" => "daily", "title" => "Daily (24 hours)"],
                ["const" => "weekly", "title" => "Weekly (7 days)"],
                ["const" => "custom", "title" => "Custom (specify seconds)"],
              ],
              "default" => "every_hour",
            ],
            "custom_interval" => [
              "type" => "integer",
              "title" => "Custom Interval (seconds)",
              "description" => "Custom interval in seconds when 'Custom' is selected.",
              "default" => 3600,
              "minimum" => 60,
              "maximum" => 2592000,
            ],
            "time_window_start" => [
              "type" => "string",
              "title" => "Time Window Start",
              "description" => "Optional start time for allowed execution window (HH:MM format, e.g., 09:00). Leave empty to allow any time.",
              "format" => "time",
              "default" => "",
            ],
            "time_window_end" => [
              "type" => "string",
              "title" => "Time Window End",
              "description" => "Optional end time for allowed execution window (HH:MM format, e.g., 17:00). Leave empty to allow any time.",
              "format" => "time",
              "default" => "",
            ],
            "days_of_week" => [
              "type" => "array",
              "title" => "Days of Week",
              "description" => "Select which days the trigger is allowed to fire. Leave empty for all days.",
              "items" => [
                "type" => "integer",
                "oneOf" => [
                  ["const" => 0, "title" => "Sunday"],
                  ["const" => 1, "title" => "Monday"],
                  ["const" => 2, "title" => "Tuesday"],
                  ["const" => 3, "title" => "Wednesday"],
                  ["const" => 4, "title" => "Thursday"],
                  ["const" => 5, "title" => "Friday"],
                  ["const" => 6, "title" => "Saturday"],
                ],
              ],
              "uniqueItems" => TRUE,
              "default" => [],
            ],
            // Advanced mode settings.
            "cron_expression" => [
              "type" => "string",
              "title" => "Cron Expression",
              "description" => "Standard cron expression (minute hour day-of-month month day-of-week). Examples: '0 * * * *' (hourly), '0 9 * * 1-5' (weekdays at 9am), '0 0 1 * *' (monthly).",
              "default" => "0 * * * *",
              "pattern" => "^[\\d\\*\\/\\,\\-]+\\s+[\\d\\*\\/\\,\\-]+\\s+[\\d\\*\\/\\,\\-]+\\s+[\\d\\*\\/\\,\\-]+\\s+[\\d\\*\\/\\,\\-]+$",
            ],
            // Common settings.
            "max_executions" => [
              "type" => "integer",
              "title" => "Maximum Executions",
              "description" => "Maximum number of times to execute. Set to 0 for unlimited. The trigger will be disabled after reaching this limit.",
              "default" => 0,
              "minimum" => 0,
            ],
            "timezone" => [
              "type" => "string",
              "title" => "Timezone",
              "description" => "Timezone for schedule calculations. Leave empty to use site default.",
              "default" => "",
            ],
          ],
        ],
      ],
    ];
  }

  /**
   * Get common cron expression examples for help text.
   *
   * @return array<string, string>
   *   Array of expressions with descriptions.
   */
  public static function getCronExpressionExamples(): array {
    return [
      "* * * * *" => "Every minute",
      "*/5 * * * *" => "Every 5 minutes",
      "0 * * * *" => "Every hour (at minute 0)",
      "0 */2 * * *" => "Every 2 hours",
      "0 9 * * *" => "Daily at 9:00 AM",
      "0 0 * * *" => "Daily at midnight",
      "0 9 * * 1-5" => "Weekdays at 9:00 AM",
      "0 0 * * 0" => "Weekly on Sunday at midnight",
      "0 0 1 * *" => "Monthly on the 1st at midnight",
      "0 0 1 1 *" => "Yearly on January 1st at midnight",
    ];
  }

}
