import { nanoid } from '../../nanoid.js'

export const Kind = 'Core#UserIdentity'

type Provider = 'google'

/**
 * 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 IUserIdentity {
  kind: typeof Kind
  /**
   * The database ID
   */
  key: string
  /**
   * The related user id.
   */
  userId: string
  /**
   * The identity provider.
   */
  provider: Provider
  /**
   * The provider's unique ID.
   * This allows to recognize a returning user.
   */
  providerId: string
  /**
   * `true`, if the provider has verified the email address.
   */
  emailVerified: boolean
  /**
   * If present, the host domain of the user's GSuite email address.
   * Google specific.
   */
  hostDomain?: string
}

export class UserIdentity implements IUserIdentity {
  kind: typeof Kind = Kind
  key = ''
  userId = ''
  provider: Provider = 'google'
  providerId = ''
  emailVerified = false
  hostDomain?: string

  constructor(input?: string | IUserIdentity) {
    let init: IUserIdentity
    if (typeof input === 'string') {
      init = JSON.parse(input)
    } else if (typeof input === 'object') {
      init = input
    } else {
      init = {
        kind: Kind,
        key: nanoid(),
        userId: '',
        provider: 'google',
        providerId: '',
        emailVerified: false,
      }
    }
    this.new(init)
  }

  new(init: IUserIdentity): void {
    if (!UserIdentity.isUserIdentity(init)) {
      throw new Error(`Not a UserIdentity.`)
    }
    const { key = nanoid(), emailVerified, provider, providerId, userId, hostDomain } = init
    this.kind = Kind
    this.key = key
    this.provider = provider
    this.providerId = providerId
    this.userId = userId
    this.emailVerified = emailVerified
    if (hostDomain) {
      this.hostDomain = hostDomain
    } else {
      this.hostDomain = undefined
    }
  }

  static isUserIdentity(input: unknown): boolean {
    const typed = input as IUserIdentity
    if (!input || typed.kind !== Kind) {
      return false
    }
    return true
  }

  toJSON(): IUserIdentity {
    const result: IUserIdentity = {
      kind: Kind,
      key: this.key,
      provider: this.provider,
      providerId: this.providerId,
      userId: this.userId,
      emailVerified: this.emailVerified,
    }
    if (this.hostDomain) {
      result.hostDomain = this.hostDomain
    }
    return result
  }
}
