import { PlatformBindings } from './PlatformBindings.js'
import { EventTypes } from '../../events/EventTypes.js'
import type { TelemetryConfig } from '@api-client/core/config/index.js'

export const KeyPrefix = 'api-client.config.'
export const TelemetryKey = `${KeyPrefix}telemetry`

export interface LocalConfiguration {
  /**
   * Reads a previously stored local value.
   *
   * @param key The key under which the property was stored.
   * @returns The configuration value or undefined when not found.
   */
  get(key: string): Promise<unknown | undefined>

  /**
   * Sets a config property that is permanently stored.
   *
   * @param key The key under to store the value.
   * @param value The value to store. If this is not a primitive it will be serialized with `JSON.stringify()`.
   */
  set(key: string, value: unknown): Promise<void>

  /**
   * Deletes previously stored local value.
   *
   * @param key The key under which the property was stored.
   */
  delete(key: string): Promise<void>
}

export interface SessionConfiguration {
  /**
   * Reads a previously stored session value.
   *
   * @param key The key under which the property was stored.
   * @returns The configuration value or undefined when not found.
   */
  get(key: string): Promise<unknown | undefined>

  /**
   * Sets a config property that is held in the storage only for the time of the current session.
   *
   * @param key The key under to store the value.
   * @param value The value to store. If this is not a primitive it will be serialized with `JSON.stringify()`.
   */
  set(key: string, value: unknown): Promise<void>

  /**
   * Deletes previously stored session value.
   *
   * @param key The key under which the property was stored.
   */
  delete(key: string): Promise<void>
}

export interface TelemetryConfiguration {
  /**
   * Reads the set telemetry configuration. If the configuration is missing a default value is returned.
   */
  read(): Promise<TelemetryConfig>

  /**
   * Sets the configuration for telemetry.
   *
   * @param config The configuration to set.
   */
  set(config: TelemetryConfig): Promise<void>
}

/**
 * The base class for application settings bindings.
 */
export abstract class ConfigurationBindings extends PlatformBindings {
  abstract local: LocalConfiguration

  abstract session: SessionConfiguration

  abstract telemetry: TelemetryConfiguration

  async initialize(): Promise<void> {
    window.addEventListener(EventTypes.Config.Session.get, this.getSessionHandler.bind(this))
    window.addEventListener(EventTypes.Config.Session.set, this.setSessionHandler.bind(this))
    window.addEventListener(EventTypes.Config.Session.delete, this.deleteSessionHandler.bind(this))

    window.addEventListener(EventTypes.Config.Local.get, this.getLocalHandler.bind(this))
    window.addEventListener(EventTypes.Config.Local.set, this.setLocalHandler.bind(this))
    window.addEventListener(EventTypes.Config.Local.delete, this.deleteLocalHandler.bind(this))

    window.addEventListener(EventTypes.Config.Telemetry.read, this.telemetryReadHandler.bind(this))
    window.addEventListener(EventTypes.Config.Telemetry.set, this.telemetrySetHandler.bind(this))
  }

  protected getSessionHandler(input: Event): void {
    const e = input as CustomEvent
    e.preventDefault()
    e.detail.result = this.session.get(e.detail.key)
  }

  protected setSessionHandler(input: Event): void {
    const e = input as CustomEvent
    e.preventDefault()
    e.detail.result = this.session.set(e.detail.key, e.detail.value)
  }

  protected deleteSessionHandler(input: Event): void {
    const e = input as CustomEvent
    e.preventDefault()
    e.detail.result = this.session.delete(e.detail.key)
  }

  protected getLocalHandler(input: Event): void {
    const e = input as CustomEvent
    e.preventDefault()
    e.detail.result = this.local.get(e.detail.key)
  }

  protected setLocalHandler(input: Event): void {
    const e = input as CustomEvent
    e.preventDefault()
    e.detail.result = this.local.set(e.detail.key, e.detail.value)
  }

  protected deleteLocalHandler(input: Event): void {
    const e = input as CustomEvent
    e.preventDefault()
    e.detail.result = this.local.delete(e.detail.key)
  }

  protected telemetryReadHandler(input: Event): void {
    const e = input as CustomEvent
    e.preventDefault()
    e.detail.result = this.telemetry.read()
  }

  protected telemetrySetHandler(input: Event): void {
    const e = input as CustomEvent
    e.preventDefault()
    e.detail.result = this.telemetry.set(e.detail.config)
  }
}
