import { nanoid } from '../../nanoid.js'
import type { IDeletion } from './Deletion.js'
import { OrganizationKind } from '../kinds.js'

export type UserOrganizationGrantType = 'owner' | 'manager' | 'editor' | 'viewer'

/**
 * In the system the user identity represents registration information associated with a specific identity provider.
 * This association allows the user to use different identity providers that map to the same user, as long as the
 * email stays consistent.
 */
export interface IOrganization {
  kind: typeof OrganizationKind
  /**
   * The database ID
   */
  key: string
  /**
   * The organization name
   */
  name: string
  /**
   * The key of the user that created the organization.
   */
  createdBy: string
  /**
   * The timestamp when the organization was created.
   */
  createdDate: number
  /**
   * Whether the organization object is deleted.
   */
  deleted?: boolean
  /**
   * The information about the delete information.
   * Always set when the `delete` is true.
   */
  deletedInfo?: IDeletion
  /**
   * The grant type to the organization the **current user** has.
   * By nature, it's a dynamic field populated by the data store.
   */
  grantType: UserOrganizationGrantType
}

export class Organization implements IOrganization {
  kind: typeof OrganizationKind = OrganizationKind
  key = ''
  name = ''
  createdBy = ''
  createdDate = 0
  deleted = false
  deletedInfo?: IDeletion
  grantType: UserOrganizationGrantType = 'viewer'

  constructor(input?: string | IOrganization) {
    let init: IOrganization
    if (typeof input === 'string') {
      init = JSON.parse(input)
    } else if (typeof input === 'object') {
      init = input
    } else {
      init = {
        kind: OrganizationKind,
        key: nanoid(),
        name: '',
        createdBy: '',
        createdDate: Date.now(),
        deleted: false,
        grantType: 'viewer',
      }
    }
    this.new(init)
  }

  new(init: IOrganization): void {
    if (!Organization.isOrganization(init)) {
      throw new Error(`Not an Organization.`)
    }
    const {
      key = nanoid(),
      name,
      createdBy,
      createdDate = Date.now(),
      deleted = false,
      deletedInfo,
      grantType = 'viewer',
    } = init
    this.kind = OrganizationKind
    this.key = key
    this.name = name
    this.createdBy = createdBy
    this.createdDate = createdDate
    this.deleted = deleted
    this.grantType = grantType
    if (deletedInfo) {
      this.deletedInfo = deletedInfo
    } else {
      this.deletedInfo = undefined
    }
  }

  /**
   * Checks whether the input is a definition of an user organization.
   */
  static isOrganization(input: unknown): boolean {
    const typed = input as IOrganization
    if (!input || typed.kind !== OrganizationKind) {
      return false
    }
    return true
  }

  toJSON(): IOrganization {
    const result: IOrganization = {
      kind: OrganizationKind,
      key: this.key,
      name: this.name,
      createdBy: this.createdBy,
      createdDate: this.createdDate,
      deleted: this.deleted,
      grantType: this.grantType,
    }
    if (this.deletedInfo) {
      result.deletedInfo = this.deletedInfo
    }
    return result
  }
}
