<?php

declare(strict_types=1);

namespace Drupal\flowdrop_memory\Entity;

use Drupal\Component\Serialization\Json;
use Drupal\Core\Entity\Attribute\ContentEntityType;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\flowdrop_memory\MemoryRecordStorageSchema;

/**
 * Defines the FlowDrop memory record content entity.
 *
 * Stores a single scoped key-value pair. The value field holds JSON-encoded
 * data. A composite index on (scope, scope_id, memory_key) ensures efficient
 * lookups and enforces uniqueness per scope.
 *
 * @internal
 */
#[ContentEntityType(
  id: 'flowdrop_memory_record',
  label: new TranslatableMarkup('FlowDrop Memory Record'),
  label_collection: new TranslatableMarkup('FlowDrop Memory Records'),
  label_singular: new TranslatableMarkup('memory record'),
  label_plural: new TranslatableMarkup('memory records'),
  handlers: [
    'storage_schema' => MemoryRecordStorageSchema::class,
  ],
  entity_keys: [
    'id' => 'id',
    'uuid' => 'uuid',
  ],
  base_table: 'flowdrop_memory_record',
  label_count: [
    'singular' => '@count memory record',
    'plural' => '@count memory records',
  ],
)]
class MemoryRecord extends ContentEntityBase implements MemoryRecordInterface {

  /**
   * {@inheritdoc}
   */
  public function getScope(): string {
    return (string) $this->get('scope')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function getScopeId(): string {
    return (string) ($this->get('scope_id')->value ?? '');
  }

  /**
   * {@inheritdoc}
   */
  public function getMemoryKey(): string {
    return (string) $this->get('memory_key')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function getValue(): mixed {
    $raw = $this->get('value')->value;
    if ($raw === NULL || $raw === '') {
      return NULL;
    }
    return Json::decode($raw);
  }

  /**
   * {@inheritdoc}
   */
  public function setValue(mixed $value): static {
    $this->set('value', Json::encode($value));
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getExpiry(): ?int {
    $value = $this->get('expires')->value;
    return $value !== NULL ? (int) $value : NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function setExpiry(?int $timestamp): static {
    $this->set('expires', $timestamp);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function isExpired(): bool {
    $expiry = $this->getExpiry();
    return $expiry !== NULL && $expiry < time();
  }

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type): array {
    $fields = parent::baseFieldDefinitions($entity_type);

    $fields['scope'] = BaseFieldDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Scope'))
      ->setDescription(new TranslatableMarkup('The memory scope (e.g. "pipeline", "session", "global").'))
      ->setRequired(TRUE)
      ->setSetting('max_length', 255);

    $fields['scope_id'] = BaseFieldDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Scope ID'))
      ->setDescription(new TranslatableMarkup('The scope identifier. Empty string for no sub-scope.'))
      ->setRequired(FALSE)
      ->setSetting('max_length', 255)
      ->setDefaultValue('');

    $fields['memory_key'] = BaseFieldDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Key'))
      ->setDescription(new TranslatableMarkup('The memory key within the scope.'))
      ->setRequired(TRUE)
      ->setSetting('max_length', 512);

    $fields['value'] = BaseFieldDefinition::create('string_long')
      ->setLabel(new TranslatableMarkup('Value'))
      ->setDescription(new TranslatableMarkup('JSON-encoded stored value.'))
      ->setRequired(FALSE);

    $fields['created'] = BaseFieldDefinition::create('created')
      ->setLabel(new TranslatableMarkup('Created'))
      ->setDescription(new TranslatableMarkup('The time the record was created.'));

    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(new TranslatableMarkup('Changed'))
      ->setDescription(new TranslatableMarkup('The time the record was last updated.'));

    $fields['expires'] = BaseFieldDefinition::create('timestamp')
      ->setLabel(new TranslatableMarkup('Expires'))
      ->setDescription(new TranslatableMarkup('Unix timestamp when this record expires. NULL means permanent.'))
      ->setRequired(FALSE);

    return $fields;
  }

}
