import { Good } from "../goods/good.interface";
import { Planet, TradeInstance } from "../planet.model";
import { TradeRoute } from "../routes/trade-route.model";

export class Ship {
  public acceleration = 10; // Pixel pro Sekunde²
  public maxSpeed = 100;
  public currentSpeed = 0;

  public cargoSize = 50;
  cargoSpace: TradeInstance[] = [];
  public route: TradeRoute | undefined = new TradeRoute([])
  public name = "Pioneer-01-" + Math.round(Math.random() * 100);
  public loadingSpeed = 3.5;

  public status: 'loading' | 'unloading' | 'waiting' | 'idle' | 'traveling' = 'idle';
  public flightMode: FlightMode = FlightMode.Normal; 

  async exchangeGoods(planet: Planet) {
    if (!this.route) { 
      return Promise.resolve(null)
     }

    await this.unloadGoods(planet);
    await this.loadGoods(planet);
    return Promise.resolve(null);
    
  }

  dock(planet: Planet) {
    planet.dock(this)
  }

  undock(planet: Planet) {
    planet.undock(this);
  }
  

  private async unloadGoods(planet: Planet) {
    if (!planet || this.cargoSpace.length == 0) { return Promise.resolve(null); }

    const delivering = this.cargoSpace.filter(cargo => cargo.target == planet.name);

    for (let dgood of delivering) {
      const good = planet.getGood(dgood.type);
      if (!good) { continue; }
      await this.removeFromCargoSpace({type: dgood.type, amount: dgood.amount, target: dgood.target}, good);
    }

    this.cargoSpace = this.cargoSpace.filter(c => c.amount != 0 && c.amount != undefined)
    return Promise.resolve(null);

  }

  private async loadGoods(planet: Planet) {
    if (!this.route) { 
      return Promise.resolve(null)
    }
    this.status = 'loading';
    
    const demands = this.route.getTradeRouteDemands();
    if (demands.length == 0) { 
      return Promise.resolve(null)
     }

    for (let demand of demands) {
      // requested amount: demand - storage
      const stored = this.cargoSpace.find(c => c.type == demand.type);
      if (stored) { demand.amount -= stored.amount; };
      demand.amount = Math.min(demand.amount, this.freeCargoSpace);
      demand.amount = Math.max(demand.amount, 0)
      if (demand.amount == 0) { continue; }
      const received = planet.request(demand);
      await this.addToCargoSpace({type: demand.type, amount: received, target: demand.target})
    }

    return Promise.resolve(null)
  }

  get freeCargoSpace(): number {
    return this.cargoSize - this.cargoSpace.reduce((acc, succ) => acc + succ.amount, 0)
  }

  private async removeFromCargoSpace(cargo: TradeInstance, to: Good) {
    const steps = Math.ceil(cargo.amount)

    for (let i = 1; i <= steps; i++) {
      const existing = this.cargoSpace.find(c => c.type == cargo.type);
      if (existing) {
        existing.amount -= (cargo.amount / steps);
        to.amount += (cargo.amount / steps);
      }
      await this.waitForLoading(1)
    }

    return Promise.resolve(null)
  }

  private async addToCargoSpace(cargo: TradeInstance) {

    const steps = Math.ceil(cargo.amount)

    for (let i = 1; i <= steps; i++) {
      const existing = this.cargoSpace.find(c => c.type == cargo.type);
      if (existing) {
        existing.amount += (cargo.amount / steps);
      } else {
        this.cargoSpace.push({
          type: cargo.type,
          amount: cargo.amount / steps,
          target: cargo.target
        });
        
      }
      await this.waitForLoading(1)
    }

    return Promise.resolve(null)
    
  }

  async waitForLoading(amount: number) {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(null);
      }, amount * 1000 / this.loadingSpeed)
    })
  }
}

export enum FlightMode {
  Normal,   // Normales Fliegen zum Planeten
  Orbiting, // Kreisen um den Planeten
  Docking, // Gerader Flug und Landung
  Undocking,  
  Docked
}