import { Rect, rectangleArray } from "../base/2d"

export type TexImage = HTMLCanvasElement | HTMLImageElement


// 设置项
export interface Settings {
  hintStyle: string, // 提示层样式
  sound: boolean; // 是否开启声音
  vibrate: boolean; // 是否开启震动
  autoNext: boolean; // 自动切换到下一个颜色 
}

export class Color {

  color: number
  parts: Uint8Array

  constructor(color: number) {
    this.color = color
    this.parts = new Uint8Array(4)
    let u32 = new Uint32Array(this.parts.buffer)
    u32[0] = color
  }

  toFloatArray(): Float32Array {
    let p = this.parts;
    let arr = new Float32Array(4)

    arr[0] = p[0] / 255;
    arr[1] = p[1] / 255;
    arr[2] = p[2] / 255;
    arr[3] = p[3] / 255;

    return arr;
  }


  fillFloatArray(arr: Float32Array, offset: number, count: number = 1) {
    let p = this.parts;
    const r = p[0] / 255;
    const g = p[1] / 255;
    const b = p[2] / 255;
    const a = p[3] / 255;

    for (var i = 0; i < count; i++) {
      arr[offset + 4 * i] = r
      arr[offset + 4 * i + 1] = g
      arr[offset + 4 * i + 2] = b
      arr[offset + 4 * i + 3] = a
    }
  }





  css(): string {
    let p = this.parts
    return `rgba(${p[0]},${p[1]},${p[2]},${p[3]})`
  }


  /**
   * 计算颜色的灰阶值，越高表示颜色越浅
   */
  get gray(): number {
    let p = this.parts;
    let r = p[0] * 0.299;
    let g = p[1] * 0.587;
    let b = p[2] * 0.114;

    let gray = r + g + b;

    return gray;

  }
}


export interface Center {
  x: number,
  y: number,
  radius: number,

  offset: number,
  label: string,
  fontHeight: number
}



/*
export interface Area {
  center: Center
  rect: Rect
  count: number
  id: number
  colored: boolean,
}

export interface AreaGroup {
  areas: Array<Area>
  color: number
}*/


export class Area {
  constructor(
    public center: Center,
    public rect: Rect,
    public id: number,
    public colored: boolean
  ) { }
}

export class AreaGroup {
  constructor(
    public areas: Array<Area>,
    public color: number
  ) { }

  get isAllColored(): boolean {
    return this.areas.every(a => a.colored)
  }

  get firstUncoloredArea(): Area | undefined {
    // 优先指向大区块（radius 大的排前面），引导用户从大到小填色
    let best: Area | undefined;
    let bestRadius = -1;
    for (const a of this.areas) {
      if (!a.colored && a.center.radius > bestRadius) {
        best = a;
        bestRadius = a.center.radius;
      }
    }
    return best;
  }

  // group的完成进度百分比
  get progressPercent(): number {
    let doneCount = this.areas.filter(a => a.colored).length;
    let allCount = this.areas.length;
    let percent = doneCount * 100 / allCount;
    return percent;
  }
}


export type AreaGroups = Array<AreaGroup>



export class Data {
  readonly areaHash: Map<number, Area>
  readonly groupHash: Map<number, AreaGroup>

  constructor(public readonly areaGroups: AreaGroups) {
    this.areaHash = new Map()
    this.groupHash = new Map()
    areaGroups.forEach(group => {
      Object.setPrototypeOf(group, AreaGroup.prototype)
      group.areas.forEach(area => {
        Object.setPrototypeOf(area, Area.prototype)
        this.areaHash.set(area.id, area)
        this.groupHash.set(area.id, group)
      })
    })
  }

  get areaCount(): number {
    return this.areaGroups.reduce((pre, cur) => pre + cur.areas.length, 0)
  }

  get maxAreaCountOfGroup(): number {
    return this.areaGroups.reduce((pre, cur) => {
      return Math.max(pre, cur.areas.length)
    }, 0)
  }


  groupAreaHash(group: AreaGroup): Map<number, Area> {
    return group.areas.reduce((pre, cur) => {
      return pre.set(cur.id, cur)
    }, new Map())
  }

  get coloredPercent(): number {
    let coloredCount = [...this.areaHash.values()].reduce((count: number, area: Area) => {
      return area.colored === true ? count + 1 : count;
    }, 0)
    return Math.round(coloredCount * 100 / this.areaHash.size);
  }

}







export function createTexture(gl: WebGL2RenderingContext, image: TexImage, filterType: GLuint = gl.NEAREST): WebGLTexture {

  // Create a texture.
  let texture = gl.createTexture()!;
  gl.bindTexture(gl.TEXTURE_2D, texture);

  // Set the parameters so we can render any size image.
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filterType);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filterType);

  //Upload the image into the texture.
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

  return texture;

}


export function createPatternTexture(gl: WebGL2RenderingContext, image: TexImage): WebGLTexture {

  // Create a texture.
  let texture = gl.createTexture()!;
  gl.bindTexture(gl.TEXTURE_2D, texture);

  // Set the parameters so we can render any size image.
  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);

  //Upload the image into the texture.
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

  return texture;

}




export function createReadFramebuffer(gl: WebGL2RenderingContext, texture: WebGLTexture): WebGLFramebuffer {
  let fb = gl.createFramebuffer()!
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb)
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)
  let canRead = gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE
  console.log(`canRead=${canRead}`)
  gl.bindFramebuffer(gl.FRAMEBUFFER, null)
  return fb
}



export function rectangleBuffer(gl: WebGL2RenderingContext, x: number, y: number, width: number, height: number): WebGLBuffer {
  let arr = rectangleArray(x, y, width, height)
  let buffer = gl.createBuffer()!
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
  gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW)
  gl.bindBuffer(gl.ARRAY_BUFFER, null)
  return buffer
}