import { Logger } from './logger'
import Timeout from './timeout'
import EnhancedContentApi from '../enhancedContent'

export default class TimeOnPageTracker {
  #logger: Logger
  #ecApi?: EnhancedContentApi
  #timeOnPage = 0 // The total time on page
  #timeOnPageSessionStart = Date.now() // The current time on page session start time
  #visibilitychangeHandler: () => void
  #beforeunloadHandler: () => void
  #timeout: Timeout

  public constructor(logger: Logger, ecApi?: EnhancedContentApi) {
    this.#logger = logger
    this.#ecApi = ecApi
    this.#visibilitychangeHandler = this.#visibilitychangeCallback.bind(this)
    this.#beforeunloadHandler = this.sendEvent.bind(this)
    this.#timeout = new Timeout()
  }

  public start(): void {
    document.addEventListener('visibilitychange', this.#visibilitychangeHandler)
    window.addEventListener('beforeunload', this.#beforeunloadHandler)
    this.#timeout.start(this.sendEvent.bind(this))
  }

  public stop(): void {
    document.removeEventListener('visibilitychange', this.#visibilitychangeHandler)
    window.removeEventListener('beforeunload', this.#beforeunloadHandler)
    this.#timeout.clear()
  }

  public restart(): void {
    this.stop()
    this.#timeOnPage = 0
    this.#timeOnPageSessionStart = Date.now()
    this.start()
  }

  public sendEvent(): void {
    const currentTime = Date.now()
    this.#timeOnPage += (currentTime - this.#timeOnPageSessionStart) / 1000
    this.#timeOnPageSessionStart = currentTime
    this.#logger.log('time_on_page', {
      timeOnPage: this.#timeOnPage,
      lastEcRenderConfig: this.#ecApi?.lastRenderConfig,
    })
  }

  #visibilitychangeCallback(): void {
    // document.visibilityState returns the current visibility state of the document.
    // It returns these states as “hidden“, “visible”, and “prerender”.
    // - hidden means the current tab is not in focus, either switched to another tab, minimized, or closed
    // - visible means the current tab is in focus
    // - prerender means the page has been loaded but the user has not viewed the page
    if (document.visibilityState === 'visible') {
      // If the document is change to visible, reset the session start time and continue the timeout
      this.#timeOnPageSessionStart = Date.now()
    } else {
      // If the document is not visible, it means the user is swtiching to another tab or closing the tab
      // Calculate the time on page and log it, also remove the timeout
      this.sendEvent()
      this.#timeout.clear()
    }
  }
}
