import { to1D } from '../convert';
import { WorldChunk } from './world-chunk';
import { WorldLoader } from './world-loader';
import { WorldManifest } from './world-manifest';

export class WorldManager {
  protected _chunks!: WorldChunk[];

  constructor(public loader: WorldLoader, public manifest: WorldManifest) {
    this._chunks = new Array(this.worldWidth * this.worldHeight);
  }

  public get worldWidth() {
    return this.manifest.worldWidth;
  }

  public get worldHeight() {
    return this.manifest.worldHeight;
  }

  public get worldChunkSize() {
    return this.manifest.worldChunkSize;
  }

  async loadHeightData(chunkX: number, chunkY: number) {
    const heightData = await this.loader.loadHeightMap(
      chunkX,
      chunkY,
      this.manifest.worldHeightScale,
    );

    this._chunks[to1D(chunkX, chunkY, this.worldWidth)] = new WorldChunk(
      heightData,
      chunkX,
      chunkY,
      this.worldChunkSize,
      this.manifest.regionMap.find(({ x, y }) => x === chunkX && y === chunkY)!,
    );
  }

  async loadWorld() {
    for (let x = 0; x < this.worldWidth; x++) {
      for (let y = 0; y < this.worldHeight; y++) {
        await this.loadHeightData(x, y);
      }
    }
  }

  async initialize() {}

  getPointHeight(x: number, y: number): number {
    const chunkX = Math.floor(x / this.worldChunkSize);
    const chunkY = Math.floor(y / this.worldChunkSize);
    if (
      chunkX >= this.worldWidth ||
      chunkY >= this.worldHeight ||
      x < 0 ||
      y < 0
    ) {
      return 0;
    }

    return this._chunks[to1D(chunkX, chunkY, this.worldWidth)].getPoint(
      x - chunkX * this.worldChunkSize,
      y - chunkY * this.worldChunkSize,
    );
  }

  getHeight(x: number, y: number): number {
    const chunkX = Math.floor(x / this.worldChunkSize);
    const chunkY = Math.floor(y / this.worldChunkSize);
    if (
      chunkX >= this.worldWidth ||
      chunkY >= this.worldHeight ||
      x < 0 ||
      y < 0
    ) {
      return 0;
    }

    return this._chunks[
      to1D(chunkX, chunkY, this.worldWidth)
    ].getInterpolatedPoint(
      x - chunkX * this.worldChunkSize,
      y - chunkY * this.worldChunkSize,
    );
  }
}
