import { createPatternTexture, createTexture, TexImage } from "../filler/common";
import { fillRectangle, Rect } from "./2d"
import { LayerAB, Scene } from "./Scene"
import { createProgram, createShader } from "./utils"


export enum BgType { FitCenter, Repeat }


export class BgLayer extends LayerAB {


  private vertexShaderCode = /*glsl*/ `
    attribute vec2 a_position;
    attribute vec2 a_texCoord;
    uniform mat4 u_matrix;
    varying vec2 v_texCoord;

    void main() {
      gl_Position = u_matrix * vec4(a_position, 0, 1);
      v_texCoord = a_texCoord;
    }

  `;

  private fragmentShaderCode = /*glsl*/ `
    precision mediump float;
    uniform sampler2D u_image;
    varying vec2 v_texCoord;

    void main() {
      vec4 color = texture2D(u_image, v_texCoord);
      gl_FragColor = color;
    }
  
  `



  program: WebGLProgram


  aPositionLoc: number
  aTexcoordLoc: number
  uMatrixLoc: WebGLUniformLocation

  vertexBuffer: WebGLBuffer
  texcoordBuffer: WebGLBuffer

  vertexArray = new Float32Array(12)
  texCoordArray = new Float32Array(12)

  texture: WebGLTexture


  constructor(
    public readonly scene: Scene,
    private image: TexImage,
    public readonly width: number,
    public readonly height: number,
    bgType: BgType = BgType.FitCenter,
    private texWidth: number = image.width,
    private texHeight: number = image.height,
  ) {
    super()

    const gl = scene.gl;


    this.program = createProgram(gl,
      createShader(gl, gl.VERTEX_SHADER, this.vertexShaderCode)!,
      createShader(gl, gl.FRAGMENT_SHADER, this.fragmentShaderCode)!)!

    this.aPositionLoc = gl.getAttribLocation(this.program, "a_position")
    this.aTexcoordLoc = gl.getAttribLocation(this.program, "a_texCoord")
    this.uMatrixLoc = gl.getUniformLocation(this.program, "u_matrix")!


    fillRectangle(this.vertexArray, 0, 0, 0, width, height)


    if (bgType == BgType.FitCenter) {
      const viewPort = new Rect(0, 0, width, height)
      const texRect = new Rect(0, 0, texWidth, texHeight)
      const dest = viewPort.centerFitTo(texRect)
      fillRectangle(this.texCoordArray, 0, dest.x / texWidth, dest.y / texHeight, dest.width / texWidth, dest.height / texHeight)
    } else {
      fillRectangle(this.texCoordArray, 0, 0, 0, width / texWidth, height / texHeight)
    }


    this.vertexBuffer = gl.createBuffer()!;
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, this.vertexArray, gl.STATIC_DRAW);


    this.texcoordBuffer = gl.createBuffer()!;
    gl.bindBuffer(gl.ARRAY_BUFFER, this.texcoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, this.texCoordArray, gl.STATIC_DRAW);


    this.texture = gl.createTexture()!;
    gl.bindTexture(gl.TEXTURE_2D, this.texture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

  }




  override draw() {
    const gl = this.scene.gl;
    gl.useProgram(this.program);

    gl.enableVertexAttribArray(this.aPositionLoc);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
    gl.vertexAttribPointer(this.aPositionLoc, 2, gl.FLOAT, false, 0, 0)

    gl.enableVertexAttribArray(this.aTexcoordLoc);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.texcoordBuffer);
    gl.vertexAttribPointer(this.aTexcoordLoc, 2, gl.FLOAT, false, 0, 0)

    gl.uniformMatrix4fv(this.uMatrixLoc, false, this.scene.projectionMat)


    gl.activeTexture(gl.TEXTURE0)
    gl.bindTexture(gl.TEXTURE_2D, this.texture)

    gl.drawArrays(gl.TRIANGLES, 0, 6);

  }




}




