import { Deserialize } from "../util/deserialize.model";
import { IslandDataModel } from "../../../data/models/island-data.model";
import { Coordinate3dStringModel } from "./coordinate-3d-string.model";

export class IslandInstanceModel implements Deserialize {
  name: string;
  id: number;
  spawnerOverrides: object; // TODO Figure out what this actually does
  treasureMapSpawnPoints: Coordinate3dStringModel[];
  wildPirateCampSpawnPoints: Coordinate3dStringModel[];
  minTreasureQuality: number;
  maxTreasureQuality: number;
  useNpcVolumesForTreasures: boolean;
  useLevelBoundsForTreasures: boolean;
  prioritizeVolumesForTreasures: boolean;
  islandPoints: number;
  islandTreasureBottleSupplyCrateOverrides: string; // TODO figure out what this actually is
  islandWidth: number;
  islandHeight: number;
  singleSpawnPointX: number;
  singleSpawnPointY: number;
  singleSpawnPointZ: number;
  worldX: number;
  worldY: number;
  rotation: number;

  // Specify extra player spawn points. Unique within entire grid
  spawnPointRegionOverride: number = -1;
  finalNPCLevelMultiplier: number = 1;
  finalNPCLevelOffset: number = 0;
  instanceTreasureQualityMultiplier: number = 1;
  instanceTreasureQualityAddition: number = 0;

  // Linked comma separated values normally. Lets just fix that...
  public IslandInstanceCustomData: object = {};
  public IslandInstanceClientCustomData: object = {};

  deserialize(input: any): this {
    // Do this before actually assigning to current object
    const string1 = input.IslandInstanceCustomDatas1;
    delete input.IslandInstanceCustomDatas1;
    const string2 = input.IslandInstanceCustomDatas2;
    delete input.IslandInstanceCustomDatas2;
    const stringClient1 = input.IslandInstanceClientCustomDatas1;
    delete input.IslandInstanceClientCustomDatas1;
    const stringClient2 = input.IslandInstanceClientCustomDatas2;
    delete input.IslandInstanceClientCustomDatas2;
    Object.assign(this, input);

    // Some minor assumption about how this works, but...
    if (string1) {
      const array1 = string1.split(',');
      const array2 = string2.split(',');
      if (array1.length !== array2.length)
        throw Error('IslandInstanceCustomDatas unmatched array length');
      array1.forEach((i, idx) => this.IslandInstanceCustomData[i] = array2[idx]);
    }

    if (stringClient1) {
      const array1 = stringClient1.split(',');
      const array2 = stringClient2.split(',');
      if (array1.length !== array2.length)
        throw Error('IslandInstanceClientCustomDatas unmatched array length');
      array1.forEach((i, idx) => this.IslandInstanceClientCustomData[i] = array2[idx]);
    }

    if (this.treasureMapSpawnPoints === undefined) this.treasureMapSpawnPoints = [];
    this.treasureMapSpawnPoints = this.treasureMapSpawnPoints.map(i => new Coordinate3dStringModel().deserialize(i));
    if (this.wildPirateCampSpawnPoints === undefined) this.wildPirateCampSpawnPoints = [];
    this.wildPirateCampSpawnPoints = this.wildPirateCampSpawnPoints.map(i => new Coordinate3dStringModel().deserialize(i));
    return this;
  }

  toJSON(): object {
    let json = Object.assign({}, this);
    // Remove some stupidity from the above
    delete json.IslandInstanceCustomData;
    delete json.IslandInstanceClientCustomData;
    // Remap to separate variables
    if (Object.keys(this.IslandInstanceCustomData).length > 0) {
      json['IslandInstanceCustomDatas1'] = Object.keys(this.IslandInstanceCustomData).join(',');
      json['IslandInstanceCustomDatas2'] = Object.values(this.IslandInstanceCustomData).join(',');
    }
    if (Object.keys(this.IslandInstanceCustomData).length > 0) {
      json['IslandInstanceClientCustomDatas1'] = Object.keys(this.IslandInstanceClientCustomData).join(',');
      json['IslandInstanceClientCustomDatas2'] = Object.values(this.IslandInstanceClientCustomData).join(',');
    }

    if (json.spawnPointRegionOverride === -1) delete json.spawnPointRegionOverride;
    if (json.finalNPCLevelMultiplier === 1) delete json.finalNPCLevelMultiplier;
    if (json.finalNPCLevelOffset === 0) delete json.finalNPCLevelMultiplier;
    if (json.instanceTreasureQualityMultiplier === 1) delete json.instanceTreasureQualityMultiplier;
    if (json.instanceTreasureQualityAddition === 0) delete json.instanceTreasureQualityAddition;

    return json;
  }

  static fromIslandData(data: IslandDataModel): IslandInstanceModel {
    return new IslandInstanceModel().deserialize({
      name: data.name,
      spawnerOverrides: data.spawnerOverrides,
      treasureMapSpawnPoints: data.treasureMapSpawnPoints,
      wildPirateCampSpawnPoints: data.wildPirateCampSpawnPoints,
      minTreasureQuality: data.minTreasureQuality,
      maxTreasureQuality: data.maxTreasureQuality,
      useNpcVolumesForTreasures: data.useNpcVolumesForTreasures,
      useLevelBoundsForTreasures: data.useLevelBoundsForTreasures,
      prioritizeVolumesForTreasures: data.prioritizeVolumesForTreasures,
      islandPoints: data.islandPoints,
      islandTreasureBottleSupplyCrateOverrides: data.islandTreasureBottleSupplyCrateOverrides,
      islandWidth: data.x,
      islandHeight: data.y,
      singleSpawnPointX: data.singleSpawnPointX,
      singleSpawnPointY: data.singleSpawnPointY,
      singleSpawnPointZ: data.singleSpawnPointZ
    });
  }
}