/* eslint-disable @typescript-eslint/no-explicit-any */

export default class TextureHook {
  public createdTextures: Array<any> = new Array<any>()

  public maxTexturesCount: number = 0

  public isInit: boolean = false

  private realGLCreateTexture: (...args: any[]) => void = function () {}

  private realGLDeleteTexture: (...args: any[]) => void = function () {}

  private gl: any

  constructor(_gl?: any) {
    if (!_gl) {
      console.warn("[TextureHook] GL can't be NULL")
    } else if (_gl.__proto__.createTexture) {
      this.gl = _gl
      this.realGLCreateTexture = this.gl.__proto__.createTexture
      this.realGLDeleteTexture = this.gl.__proto__.deleteTexture

      // replace with new function
      this.gl.__proto__.createTexture = this.fakeGLCreateTexture.bind(this)
      this.gl.__proto__.deleteTexture = this.fakeGLDeleteTexture.bind(this)
      this.isInit = true

      console.info('[TextureHook] GL was Hooked!')
    }
  }

  public get currentTextureCount(): number {
    return this.createdTextures.length
  }

  public registerTexture(texture: any): void {
    this.createdTextures.push(texture) // ++;
    this.maxTexturesCount = Math.max(
      this.createdTextures.length,
      this.maxTexturesCount
    )
  }

  private fakeGLCreateTexture(): any {
    const texture = this.realGLCreateTexture.call(this.gl)
    this.registerTexture(texture)
    return texture
  }

  private fakeGLDeleteTexture(texture: any): void {
    const index: number = this.createdTextures.indexOf(texture)
    if (index > -1) {
      this.createdTextures.splice(index, 1)
    }

    this.realGLDeleteTexture.call(this.gl, texture)
  }

  public reset(): void {
    this.createdTextures = new Array<any>()
    this.maxTexturesCount = 0
  }

  public release(): void {
    if (this.isInit) {
      this.gl.__proto__.createTexture = this.realGLCreateTexture
      this.gl.__proto__.deleteTexture = this.realGLDeleteTexture

      console.info('[TextureHook] Hook was removed!')
    }

    this.isInit = false
  }
}
