import { DataCatalogScope } from './DataCatalog.js'
import { DataCatalogVersionKind } from './kinds.js'

export type DataCatalogLifecycle = 'stable' | 'beta' | 'dev'

export interface DataCatalogVersionSchema {
  /**
   * The key of the version.
   *
   * The key can only be set when creating a new data catalog entry.
   * @readonly
   */
  key: string
  /**
   * The kind of the schema
   */
  readonly kind: typeof DataCatalogVersionKind
  /**
   * The key of the parent data catalog entry.
   * It is only populated by the API when creating the version.
   * @readonly
   */
  catalogKey: string
  /**
   * The publication scope of the data catalog entry.
   *
   * When the scope is set to a different value than the one of the parent data catalog entry,
   * then this value is used to determine the visibility of the data catalog entry. However,
   * the reader cannot access the version with a "public" scope if the parent data catalog entry is private.
   *
   * @required
   */
  scope: DataCatalogScope
  /**
   * The lifecycle of the data catalog entry.
   *
   * - `stable`: The data catalog entry is stable and can be used in production.
   * - `beta`: The data catalog entry is in beta and may change in the future.
   * - `dev`: The data catalog entry is in development and likely will change in the future.
   *
   * The lifecycle is a readonly property and is set by the API when creating or updating the data catalog entry.
   * A version is immutable and to change the lifecycle, a new version must be created.
   *
   * @required
   */
  lifecycle: DataCatalogLifecycle
  /**
   * The version string according to the [semantic versioning](https://semver.org/) specification.
   * Note, this value is limited to 32 characters by the API.
   * @required
   */
  version: string
  /**
   * The id of the user who created the version.
   * It is ignored when creating or updating a data catalog entry.
   * @readonly
   */
  publishedBy: string
  /**
   * The timestamp when this version was unpublished.
   * Only set when the version was unpublished.
   * @readonly
   */
  unpublishedAt?: number
  /**
   * A flag indicating if the version is deprecated.
   * @readonly
   */
  deprecated?: boolean
  /**
   * The timestamp when the version was deprecated.
   * Only set when the version was deprecated.
   * @readonly
   */
  deprecatedAt?: number
  /**
   * The id of the user who deprecated the version.
   * Only set when the version was deprecated.
   * @readonly
   */
  deprecatedBy?: string
  /**
   * The reason why the version was deprecated.
   * Only set when the version was deprecated.
   */
  deprecationReason?: string
  /**
   * The timestamp when the data catalog entry was created.
   * It is ignored when creating or updating a data catalog entry.
   * @readonly
   */
  createdAt: number
  /**
   * The timestamp when the data catalog entry was last updated.
   * It is ignored when creating or updating a data catalog entry.
   * @readonly
   */
  updatedAt: number
  /**
   * The changelog of the data catalog entry.
   * Note, this value is required by the API when creating the version.
   */
  changelog?: string
}

export class DataCatalogVersion implements DataCatalogVersionSchema {
  key: string

  get kind(): typeof DataCatalogVersionKind {
    return DataCatalogVersionKind
  }

  catalogKey: string
  scope: DataCatalogScope
  lifecycle: DataCatalogLifecycle
  version: string
  publishedBy: string
  unpublishedAt?: number | undefined
  deprecated?: boolean | undefined
  deprecatedAt?: number | undefined
  deprecatedBy?: string | undefined
  deprecationReason?: string | undefined
  createdAt: number
  updatedAt: number
  changelog?: string | undefined

  static createSchema(input: Partial<DataCatalogVersionSchema>): DataCatalogVersionSchema {
    const {
      key = '',
      scope = 'private',
      publishedBy = '',
      createdAt = 0,
      updatedAt = 0,
      catalogKey = '',
      lifecycle = 'stable',
      version = '',
    } = input
    if (['public', 'private', 'organization'].indexOf(scope) === -1) {
      throw new Error(`Invalid scope: ${scope}`)
    }
    const result: DataCatalogVersionSchema = {
      key,
      kind: DataCatalogVersionKind,
      scope,
      publishedBy,
      createdAt,
      updatedAt,
      catalogKey,
      lifecycle,
      version,
    }
    if (typeof input.deprecated === 'boolean') {
      result.deprecated = input.deprecated
    }
    if (typeof input.deprecatedAt === 'number') {
      result.deprecatedAt = input.deprecatedAt
    }
    if (typeof input.deprecatedBy === 'string') {
      result.deprecatedBy = input.deprecatedBy
    }
    if (typeof input.changelog === 'string') {
      result.changelog = input.changelog
    }
    if (typeof input.deprecationReason === 'string') {
      result.deprecationReason = input.deprecationReason
    }
    if (typeof input.unpublishedAt === 'number') {
      result.unpublishedAt = input.unpublishedAt
    }
    return result
  }

  constructor(input: Partial<DataCatalogVersionSchema> = {}) {
    const init = DataCatalogVersion.createSchema(input)
    this.key = init.key
    this.catalogKey = init.catalogKey
    this.lifecycle = init.lifecycle
    this.scope = init.scope
    this.version = init.version
    this.publishedBy = init.publishedBy
    this.createdAt = init.createdAt
    this.updatedAt = init.updatedAt
    if (typeof init.changelog === 'string') {
      this.changelog = init.changelog
    }
    if (typeof init.deprecated === 'boolean') {
      this.deprecated = init.deprecated
    }
    if (typeof init.deprecatedAt === 'number') {
      this.deprecatedAt = init.deprecatedAt
    }
    if (typeof init.deprecatedBy === 'string') {
      this.deprecatedBy = init.deprecatedBy
    }
    if (typeof init.deprecationReason === 'string') {
      this.deprecationReason = init.deprecationReason
    }
    if (typeof init.unpublishedAt === 'number') {
      this.unpublishedAt = init.unpublishedAt
    }
  }

  toJSON(): DataCatalogVersionSchema {
    const result: DataCatalogVersionSchema = {
      key: this.key,
      kind: DataCatalogVersionKind,
      scope: this.scope,
      publishedBy: this.publishedBy,
      createdAt: this.createdAt,
      updatedAt: this.updatedAt,
      catalogKey: this.catalogKey,
      lifecycle: this.lifecycle,
      version: this.version,
    }
    if (typeof this.deprecated === 'boolean') {
      result.deprecated = this.deprecated
    }
    if (typeof this.deprecatedAt === 'number') {
      result.deprecatedAt = this.deprecatedAt
    }
    if (typeof this.deprecatedBy === 'string') {
      result.deprecatedBy = this.deprecatedBy
    }
    if (typeof this.deprecationReason === 'string') {
      result.deprecationReason = this.deprecationReason
    }
    if (typeof this.unpublishedAt === 'number') {
      result.unpublishedAt = this.unpublishedAt
    }
    if (typeof this.changelog === 'string' && this.changelog) {
      result.changelog = this.changelog
    }
    return result
  }
}
