/*
 * Licensed to Apache Software Foundation (ASF) under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Apache Software Foundation (ASF) licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

// Tag types — MUST match api/proto/banyandb/database/v1/schema.proto TagType.
// The liaison's grpc-gateway maps unknown enum strings to UNSPECIFIED, so a
// stale name (e.g. the old TAG_TYPE_INT64) silently corrupts the schema. There
// is NO float tag type in BanyanDB.
export enum TagType {
  UNSPECIFIED = 'TAG_TYPE_UNSPECIFIED',
  STRING = 'TAG_TYPE_STRING',
  INT = 'TAG_TYPE_INT',
  STRING_ARRAY = 'TAG_TYPE_STRING_ARRAY',
  INT_ARRAY = 'TAG_TYPE_INT_ARRAY',
  DATA_BINARY = 'TAG_TYPE_DATA_BINARY',
  TIMESTAMP = 'TAG_TYPE_TIMESTAMP',
}

// Field types — MUST match api/proto/banyandb/database/v1/schema.proto
// FieldType (FIELD_TYPE_INT / FIELD_TYPE_FLOAT, not the 64-suffixed names).
export enum FieldType {
  UNSPECIFIED = 'FIELD_TYPE_UNSPECIFIED',
  STRING = 'FIELD_TYPE_STRING',
  INT = 'FIELD_TYPE_INT',
  FLOAT = 'FIELD_TYPE_FLOAT',
  DATA_BINARY = 'FIELD_TYPE_DATA_BINARY',
}

export enum CompressMethod {
  UNSPECIFIED = 'COMPRESSION_METHOD_UNSPECIFIED',
  ZSTD = 'COMPRESSION_METHOD_ZSTD',
}

export enum EncodingMethod {
  UNSPECIFIED = 'ENCODING_METHOD_UNSPECIFIED',
  GORILLA = 'ENCODING_METHOD_GORILLA',
}

export enum IndexType {
  // BanyanDB liaison's grpc-gateway encodes these as proto-style enum names
  // (TYPE_TREE / TYPE_INVERTED / TYPE_SKIPPING). The INDEX_TYPE_* variant used
  // to live here but caused the upstream POST /index-rule/schema endpoint to
  // 500. Keep the wire format aligned with the liaison so create / update
  // round-trips succeed.
  TREE = 'TYPE_TREE',
  INVERTED = 'TYPE_INVERTED',
  SKIPPING = 'TYPE_SKIPPING',
}

export interface IntervalRule {
  readonly unit: 'UNIT_HOUR' | 'UNIT_DAY';
  readonly num: number;
}

export interface LifecycleStage {
  readonly name: string;
  readonly shardNum: number;
  readonly segmentInterval: IntervalRule;
  readonly ttl: IntervalRule;
  readonly nodeSelector?: string;
  readonly close?: boolean;
  /** Per-stage replicas (proto ResourceOpts.stages[].replicas). Independent
   * from the group-level resourceOpts.replicas. */
  readonly replicas?: number;
}

export interface Group {
  readonly name: string;
  readonly catalog: 'CATALOG_STREAM' | 'CATALOG_MEASURE' | 'CATALOG_PROPERTY' | 'CATALOG_TRACE' | 'CATALOG_UNSPECIFIED';
  readonly resourceOpts: {
    readonly shardNum: number;
    readonly segmentInterval?: IntervalRule;
    readonly ttl?: IntervalRule;
    readonly stages?: LifecycleStage[];
    readonly defaultStages?: string[];
    readonly replicas?: number;
  };
  readonly updatedAt?: string;
}

export interface TagSpec {
  readonly name: string;
  readonly type: TagType;
  readonly indexedOnly?: boolean;
}

export interface TagFamilySpec {
  readonly name: string;
  readonly tags: TagSpec[];
}

export interface FieldSpec {
  readonly name: string;
  readonly fieldType: FieldType;
  readonly compressionMethod?: CompressMethod;
  readonly encodingMethod?: EncodingMethod;
}

export interface StreamSchema {
  readonly metadata: {
    readonly name: string;
    readonly group: string;
  };
  readonly tagFamilies: TagFamilySpec[];
  readonly entity: {
    readonly tagNames: string[];
  };
}

export interface MeasureSchema {
  readonly metadata: {
    readonly name: string;
    readonly group: string;
  };
  readonly tagFamilies: TagFamilySpec[];
  readonly fields: FieldSpec[];
  readonly entity: {
    readonly tagNames: string[];
  };
  readonly interval: string;
  readonly indexMode?: boolean;
}

export interface TraceSchema {
  readonly metadata: {
    readonly name: string;
    readonly group: string;
  };
  readonly tags: TagSpec[];
  readonly traceIdTagName: string;
  readonly spanIdTagName: string;
  readonly timestampTagName: string;
}

export interface PropertySchema {
  readonly metadata: {
    readonly name: string;
    readonly group: string;
  };
  readonly tags: TagSpec[];
}

export interface IndexRuleSchema {
  readonly metadata: {
    readonly name: string;
    readonly group: string;
  };
  readonly tags: string[];
  readonly type: IndexType;
  readonly analyzer?: string;
  /**
   * When true, the rule still indexes the tags but skips building the
   * sortable doc-values column. Mirrors `schema.proto` `IndexRule.no_sort`.
   */
  readonly noSort?: boolean;
}

export interface IndexRuleBindingSchema {
  readonly metadata: {
    readonly name: string;
    readonly group: string;
  };
  readonly rules: string[];
  readonly subject: {
    readonly name: string;
    readonly catalog: string;
  };
  /** Validity window start, expressed as epoch milliseconds. */
  readonly beginAt: number;
  /** Validity window end, expressed as epoch milliseconds. */
  readonly expireAt: number;
}

export interface TopNSchema {
  readonly metadata: {
    readonly name: string;
    readonly group: string;
  };
  readonly sourceMeasure: string;
  readonly fieldName: string;
  readonly fieldValueSort: 'SORT_ASC' | 'SORT_DESC' | 'SORT_UNSPECIFIED';
  readonly groupByTagNames: string[];
  readonly countersNumber: number;
}
