package cloud.nstart.terravault.ordinis.domain.definition;

import cloud.nstart.terravault.ordinis.domain.DataScope;
import com.fasterxml.jackson.databind.JsonNode;
import io.hypersistence.utils.hibernate.type.array.StringArrayType;
import io.hypersistence.utils.hibernate.type.json.JsonType;
import jakarta.persistence.Column;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
import org.hibernate.annotations.Type;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import jakarta.persistence.EntityListeners;

import java.time.OffsetDateTime;
import java.util.UUID;

/**
 * Каталоговый entity справочника: имя, JSON Schema, scope, поддерживаемые локали.
 * Read-mostly — обновления редкие (admin operation). Не Audited через Envers
 * (история через audit_log + outbox).
 */
@Entity
@Table(name = "dictionary_definitions")
@EntityListeners(AuditingEntityListener.class)
public class DictionaryDefinition {

  @Id
  @Column(name = "id", nullable = false, updatable = false)
  private UUID id;

  @Column(name = "name", nullable = false, unique = true, length = 128)
  private String name;

  @Column(name = "display_name", length = 256)
  private String displayName;

  @Column(name = "description", columnDefinition = "TEXT")
  private String description;

  @Enumerated(EnumType.STRING)
  @Column(name = "scope", nullable = false, length = 32)
  private DataScope scope;

  @Type(JsonType.class)
  @Column(name = "schema_json", nullable = false, columnDefinition = "jsonb")
  private JsonNode schemaJson;

  @Column(name = "schema_version", nullable = false, length = 32)
  private String schemaVersion = "1.0.0";

  @Column(name = "bundle", nullable = false, length = 64)
  private String bundle = "cuod";

  @Type(StringArrayType.class)
  @Column(name = "supported_locales", nullable = false, columnDefinition = "text[]")
  private String[] supportedLocales = {"ru-RU"};

  @Column(name = "default_locale", nullable = false, length = 10)
  private String defaultLocale = "ru-RU";

  /**
   * Per-dictionary Redis projection opt-in (CEO plan E2 tiered perf).
   * False (default) — projection-writer skips this dict's events, read-api
   * goes to PG read replica. True — projection-writer materializes updates
   * to Redis (read-api routing TBD в отдельном feature).
   */
  @Column(name = "redis_projection_enabled", nullable = false)
  private boolean redisProjectionEnabled = false;

  /**
   * Per-dictionary approval workflow opt-in (Approval v2 epic, D1=A).
   * False (default) — direct CRUD continues. True — все mutations должны
   * пройти через draft → review → approve flow в record_drafts table.
   */
  @Column(name = "approval_required", nullable = false)
  private boolean approvalRequired = false;

  /**
   * Optional минимальная Keycloak роль для reviewer'а на этот dict.
   * Например {@code "ordinis:restricted"} для критичных справочников.
   * NULL = любой пользователь с ролью {@code ordinis:approver}.
   */
  @Column(name = "approval_min_role", length = 64)
  private String approvalMinRole;

  @CreatedDate
  @Column(name = "created_at", nullable = false, updatable = false)
  private OffsetDateTime createdAt;

  @LastModifiedDate
  @Column(name = "updated_at", nullable = false)
  private OffsetDateTime updatedAt;

  @CreatedBy
  @Column(name = "created_by", length = 128, updatable = false)
  private String createdBy;

  @LastModifiedBy
  @Column(name = "updated_by", length = 128)
  private String updatedBy;

  @Version
  @Column(name = "version")
  private Long version;

  protected DictionaryDefinition() {}

  public DictionaryDefinition(UUID id, String name, DataScope scope, JsonNode schemaJson) {
    this.id = id;
    this.name = name;
    this.scope = scope;
    this.schemaJson = schemaJson;
  }

  public UUID getId() { return id; }
  public String getName() { return name; }
  public String getDisplayName() { return displayName; }
  public String getDescription() { return description; }
  public DataScope getScope() { return scope; }
  public JsonNode getSchemaJson() { return schemaJson; }
  public String getSchemaVersion() { return schemaVersion; }
  public String getBundle() { return bundle; }
  public String[] getSupportedLocales() { return supportedLocales; }
  public String getDefaultLocale() { return defaultLocale; }
  public boolean isRedisProjectionEnabled() { return redisProjectionEnabled; }
  public boolean isApprovalRequired() { return approvalRequired; }
  public String getApprovalMinRole() { return approvalMinRole; }
  public OffsetDateTime getCreatedAt() { return createdAt; }
  public OffsetDateTime getUpdatedAt() { return updatedAt; }
  public String getCreatedBy() { return createdBy; }
  public String getUpdatedBy() { return updatedBy; }
  public Long getVersion() { return version; }

  public void setDisplayName(String v) { this.displayName = v; }
  public void setDescription(String v) { this.description = v; }
  public void setSchemaJson(JsonNode v) { this.schemaJson = v; }
  public void setSchemaVersion(String v) { this.schemaVersion = v; }
  public void setBundle(String v) { this.bundle = v; }
  public void setSupportedLocales(String[] v) { this.supportedLocales = v; }
  public void setDefaultLocale(String v) { this.defaultLocale = v; }
  public void setRedisProjectionEnabled(boolean v) { this.redisProjectionEnabled = v; }
  public void setApprovalRequired(boolean v) { this.approvalRequired = v; }
  public void setApprovalMinRole(String v) { this.approvalMinRole = v; }
}
