/**
 * Root React Component for displaying overall Location UI
 */
import * as React from "react";

import { LocationCity } from "./City";
import { GenericLocation } from "./GenericLocation";

import { Cities } from "../Cities";
import { Locations } from "../Locations";
import { LocationType } from "../LocationTypeEnum";

import { CityName } from "../data/CityNames";
import { LocationName } from "../data/LocationNames";

import { CONSTANTS } from "../../Constants";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";

import { dialogBoxCreate } from "../../../utils/DialogBox";

type IProps = {
  initiallyInCity?: boolean;
  engine: IEngine;
  p: IPlayer;
};

type IState = {
  city: CityName;
  inCity: boolean;
  location: LocationName;
};

export class LocationRoot extends React.Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);

    this.state = {
      city: props.p.city,
      inCity: props.initiallyInCity == null ? true : props.initiallyInCity,
      location: props.p.location,
    };

    this.enterLocation = this.enterLocation.bind(this);
    this.returnToCity = this.returnToCity.bind(this);
    this.travel = this.travel.bind(this);
  }

  enterLocation(to: LocationName): void {
    this.props.p.gotoLocation(to);
    this.setState({
      inCity: false,
      location: to,
    });
  }

  /**
   * Click listener for a button that lets the player go from a specific location
   * back to the city
   */
  returnToCity(): void {
    this.setState({
      inCity: true,
    });
  }

  /**
   * Render UI for a city
   */
  renderCity(): React.ReactNode {
    const city = Cities[this.state.city];
    if (city == null) {
      throw new Error(`Invalid city when rendering UI: ${this.state.city}`);
    }

    return (
      <div className="noselect">
        <h2>{this.state.city}</h2>
        <LocationCity city={city} enterLocation={this.enterLocation} />
      </div>
    );
  }

  /**
   * Render UI for a specific location
   */
  renderLocation(): React.ReactNode {
    const loc = Locations[this.state.location];

    if (loc == null) {
      throw new Error(`Invalid location when rendering UI: ${this.state.location}`);
    }

    if (loc.types.includes(LocationType.StockMarket)) {
      this.props.engine.loadStockMarketContent();
    }

    return (
      <GenericLocation
        engine={this.props.engine}
        loc={loc}
        p={this.props.p}
        returnToCity={this.returnToCity}
        travel={this.travel}
      />
    );
  }

  /**
   * Travel to a different city
   * @param {CityName} to - Destination city
   */
  travel(to: CityName): void {
    const p = this.props.p;
    const cost = CONSTANTS.TravelCost;
    if (!p.canAfford(cost)) {
      dialogBoxCreate(`You cannot afford to travel to ${to}`);
      return;
    }

    p.loseMoney(cost);
    p.travel(to);
    dialogBoxCreate(<span className="noselect">You are now in {to}!</span>);

    // Dynamically update main menu
    if (p.firstTimeTraveled === false) {
      p.firstTimeTraveled = true;
      const travelTab = document.getElementById("travel-tab");
      const worldHeader = document.getElementById("world-menu-header");
      if (travelTab != null && worldHeader !== null) {
        travelTab.style.display = "list-item";
        worldHeader.click();
        worldHeader.click();
      }
    }

    if (this.props.p.travel(to)) {
      this.setState({
        inCity: true,
        city: to,
      });
    }
  }

  render(): React.ReactNode {
    if (this.state.inCity) {
      return this.renderCity();
    } else {
      return this.renderLocation();
    }
  }
}
