import { Vector3, Vector2 } from 'three';
import { to1D } from '../convert';
import { barycentricPoint } from '../helper';
import { WorldManifestRegion } from './WorldManifest';

export class WorldChunk {
  constructor(
    public heightData: number[],
    public x: number,
    public y: number,
    public size: number,
    public region: WorldManifestRegion,
    public scaledSize = size,
  ) {}

  public getPoint(x: number, y: number): number {
    return this.heightData[to1D(Math.floor(x), Math.floor(y), this.size)];
  }

  public getInterpolatedPoint(x: number, y: number): number {
    const terrainX = x - this.x * this.size;
    const terrainY = y - this.y * this.size;
    const gridSquareSize = this.scaledSize / this.size;
    const gridX = Math.floor(x / gridSquareSize);
    const gridY = Math.floor(y / gridSquareSize);

    if (gridX >= this.size || gridY >= this.size || gridX < 0 || gridY < 0) {
      return 0;
    }

    const xCoord = (terrainX % gridSquareSize) / gridSquareSize;
    const yCoord = (terrainY % gridSquareSize) / gridSquareSize;
    let result: number;
    if (xCoord <= 1 - yCoord) {
      result = barycentricPoint(
        new Vector3(0, this.getPoint(gridX, gridY), 0),
        new Vector3(1, this.getPoint(gridX + 1, gridY), 0),
        new Vector3(0, this.getPoint(gridX, gridY + 1), 1),
        new Vector2(xCoord, yCoord),
      );
    } else {
      result = barycentricPoint(
        new Vector3(1, this.getPoint(gridX + 1, gridY), 0),
        new Vector3(1, this.getPoint(gridX + 1, gridY + 1), 1),
        new Vector3(0, this.getPoint(gridX, gridY + 1), 1),
        new Vector2(xCoord, yCoord),
      );
    }
    return result;
  }
}
