import Resource from '../resource'

class Texture {
  static async fromFile (gl, file, flip, filtering, repeat) {
    let image = await Resource.loadImage(file)
    return Texture.createTexture2D(gl, image, flip, filtering, repeat)
  }

  static createTexture2D (gl, img, flip = false, filtering, repeat = gl.REPEAT) {
    let tex = gl.createTexture()
    gl.bindTexture(gl.TEXTURE_2D, tex)
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flip)
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img)

    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, repeat)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, repeat)

    if (filtering) {
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filtering)
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filtering)
    } else {
      gl.generateMipmap(gl.TEXTURE_2D)
    }

    gl.bindTexture(gl.TEXTURE_2D, null)

    let oTex = new Texture()
    oTex.type = gl.TEXTURE_2D
    oTex.id = tex

    return oTex
  }

  static createTextureCubeMap (gl, img) {
    if (!img || img.length !== 6) throw new Error('createTextureCubeMap() requires six images!')
    let tex = gl.createTexture()
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex)

    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false)

    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img[0])
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img[1])
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img[2])
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img[3])
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img[4])
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img[5])

    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR)

    gl.bindTexture(gl.TEXTURE_CUBE_MAP, null)

    let oTex = new Texture()
    oTex.type = gl.TEXTURE_CUBE_MAP
    oTex.id = tex

    return oTex
  }
}

class Material {
  constructor (textures) {
    this.textures = textures
  }

  async loadTextures (gl) {
    if (this.textures) {
      for (let ti in this.textures) {
        let tex = this.textures[ti]
        if (!(tex instanceof Texture)) {
          let result = await Texture.fromFile(gl, tex, true)
          this.textures[ti] = result
        }
      }
    }
  }

  apply (gl, shader) {
    // TODO: lighting related things

    // Load textures
    if (!this.textures || !this.textures.length) return
    for (let i in this.textures) {
      let tex = this.textures[i]
      if (tex && tex instanceof Texture) {
        gl.activeTexture(gl.TEXTURE0 + parseInt(i))
        gl.bindTexture(tex.type, tex.id)
      }
    }
  }
}

export { Texture, Material }
