import { interval } from "rxjs";
import { Good } from "../goods/good.interface";
import { Planet, TradeInstance } from "../planet.model";
import { TradeRoute } from "../routes/trade-route.model";
import { GameService } from "../../service/game.service";
import { ShipType } from "./ship.type";

export interface ShipConfig extends ShipType {
  planetRoute: Planet[];
}

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

  public cargoSize = 10;
  cargoSpace: TradeInstance[] = [];
  public route: TradeRoute | undefined = new TradeRoute([])
  public name = "Pioneer-01-" + Math.round(Math.random() * 100);
  public loadingSpeed = 3.5;
  public cost = 0.5
  public buyCost = 0;
  public description: string = "";
  texture: string;

  public totalCost: number = 0;
  public totalEarnings: number = 0;

  private updateInterval = interval(1000).subscribe(() => {
    this.update();
  })
  private gameService: GameService;

  constructor(gameService: GameService, config: ShipConfig) {
    this.gameService = gameService;
    this.acceleration = config.acceleration;
    this.cargoSize = config.cargoSize;
    this.maxSpeed = config.maxSpeed;
    this.loadingSpeed = config.loadingSpeed;
    this.cost = config.cost;
    this.buyCost = config.buyCost;
    this.description = config.desciption;
    this.texture = config.texture;
    this.route = new TradeRoute(config.planetRoute)
    this.name = config.name + ' - ' + Math.round(Math.random() * 100);
    this.totalCost = config.buyCost;

  }


  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(dgood, good);
    }

    this.cargoSpace = this.cargoSpace.filter(c => c.amount != 0 && c.amount != undefined && c.amount > 0);
    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 && demand.target == c.target);
      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);
    const transferPerStep = cargo.amount / steps;

    for (let i = 1; i <= steps; i++) {
      if (cargo) {
        cargo.amount -= transferPerStep;
        to.amount += transferPerStep;
        this.gameService.money += 18 * transferPerStep;
        this.totalEarnings += 18 * transferPerStep;
      }
      await this.waitForLoading(1)
    }

    to.amount += cargo.amount;
    cargo.amount = 0;
    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 && cargo.target == c.target);
      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)
    })
  }

  update() {
    this.gameService.money -= this.cost;
    this.totalCost += this.cost;
  }


  sell() {
    this.updateInterval.unsubscribe();
  }

  get balance(): number {
    return this.totalEarnings - this.totalCost;
  }
}

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