import React from "react";
import ReactDOM from "react-dom";
import { Map, TileLayer } from "react-leaflet";
import { SketchPicker } from "react-color";
import reactCSS from "reactcss";

export default class EditGameForm extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      zoom: 13,
      gamename: "",
      description: "",
      startDate: "",
      startTime: "",
      endDate: "",
      endTime: "",
      map: "",
      mapCenter: {
        lat: 62.2416479,
        lng: 25.7597186
      },
      factionNameInput: "", // >= 2 chars
      factionPasswordInput: "", // >= 3 chars
      factionColorInput: "#852222",
      factions: [],
      objectivePointDescriptionInput: "", // >= 7
      objectivePointMultiplierInput: "", // number
      objectivePoints: [],
      capture_time: 300,
      confirmation_time: 60,
      displayColorPicker: false
    };

    this.handleMapDrag = this.handleMapDrag.bind(this);
  }

  handleError = error => {
    this.setState({ errorMsg: error });
  };

  handleChange = e => {
    const { name, value } = e.target;
    this.setState({ [name]: value });
  };

  handleFactionAdd = e => {
    e.preventDefault();

    if (
      this.state.factionNameInput === "" ||
      this.state.factionPasswordInput === ""
    ) {
      return alert("Faction needs a name and password");
    }

    if (
      this.state.factions.findIndex(
        faction => faction.factionName === this.state.factionNameInput
      ) !== -1
    ) {
      return alert(
        "Faction " + this.state.factionNameInput + " already exists"
      );
    }

    this.setState(state => {
      let factions = state.factions;
      factions.push({
        factionName: this.state.factionNameInput,
        factionPassword: this.state.factionPasswordInput,
        colour: this.state.factionColorInput,
        multiplier: 1
      });
      return {
        factions: factions,
        factionNameInput: "",
        factionPasswordInput: ""
      };
    });
  };

  removeFaction(factionName) {
    this.setState(state => {
      let factions = state.factions;
      const index = factions.findIndex(
        faction => faction.factionName === factionName
      );

      if (index !== -1) {
        factions.splice(index, 1);
      } else {
        console.log("Faction is not in the faction list");
      }

      return factions;
    });
  }

  handleObjectivePointAdd = e => {
    e.preventDefault();

    if (
      this.state.objectivePointDescriptionInput === "" ||
      this.state.objectivePointMultiplierInput === ""
    ) {
      return alert("Capture point needs an ID and multiplier");
    }

    if (
      this.state.objectivePoints.findIndex(
        point =>
          point.objectivePointDescription ===
          this.state.objectivePointDescriptionInput
      ) !== -1
    ) {
      return alert(
        "Capture point " +
          this.state.objectivePointDescriptionInput +
          " already exists"
      );
    }

    this.setState(state => {
      let objectivePoints = state.objectivePoints;
      objectivePoints.push({
        objectivePointDescription: this.state.objectivePointDescriptionInput,
        objectivePointMultiplier: parseFloat(
          this.state.objectivePointMultiplierInput
        )
      });

      return {
        objectivePoints: objectivePoints,
        objectivePointDescriptionInput: "",
        objectivePointMultiplierInput: ""
      };
    });
  };

  removeObjectivePoint(objectivePointId) {
    this.setState(state => {
      let objectivePoints = state.objectivePoints;
      const index = objectivePoints.findIndex(
        point => point.objectivePointDescription === objectivePointId
      );

      if (index !== -1) {
        objectivePoints.splice(index, 1);
      } else {
        console.log("Objective point is not in the point list");
      }

      return objectivePoints;
    });
  }

  handleGameDeletion = e => {
    e.preventDefault();

    let token = sessionStorage.getItem("token");

    if (window.confirm("Are you sure you want to delete this game")) {
      alert("Game deleted");

      fetch(
        `${process.env.REACT_APP_API_URL}/game/delete/${this.props.gameId}`,
        {
          method: "DELETE",
          headers: {
            Authorization: "Bearer " + token
          }
        }
      )
        .then(result => result.json())
        .then(result => {
          console.log(result);
          this.handleView();
          this.props.onEditSave();
        })
        .catch(error => console.log(error));
    }
  };

  // show/hide this form
  handleView = e => {
    this.props.toggleView(this.props.view);
  };

  // remove view with ESC
  handleEsc = e => {
    if (e.keyCode === 27) {
      this.handleView();
    }
  };

  handleMapDrag = e => {
    this.setState({
      mapCenter: e.target.getCenter()
    });
  };

  handleMapScroll = e => {
    this.setState({
      zoom: e.target.getZoom()
    });
  };

  handleGameSave = e => {
    e.preventDefault();

    let startDate =
      this.state.startDate + "T" + this.state.startTime + ":00.000Z";
    let endDate = this.state.endDate + "T" + this.state.endTime + ":00.000Z";

    let objectivePoints = this.state.objectivePoints;

    // objective points are not allowed if the game has no factions
    if (this.state.factions.length === 0) {
      objectivePoints = [];
    }

    // Object the form sends to server
    let gameObject = {
      name: this.state.gamename,
      desc: this.state.description,
      map: "",
      startdate: startDate,
      enddate: endDate,
      center: this.state.mapCenter,
      factions: this.state.factions,
      objective_points: objectivePoints
    };

    // Add node settings to the game if the game has objective points
    if (objectivePoints.length > 0) {
      gameObject.nodesettings = {
        node_settings: {
          capture_time: this.state.capture_time,
          confirmation_time: this.state.confirmation_time,
          owner: 0,
          capture: 0,
          buttons_available: 16,
          heartbeat_interval: 60
        }
      };
    }

    let token = sessionStorage.getItem("token");

    // Send Game info to the server
    fetch(`${process.env.REACT_APP_API_URL}/game/edit/${this.props.gameId}`, {
      method: "PUT",
      headers: {
        Authorization: "Bearer " + token,
        Accept: "application/json",
        "Content-Type": "application/json"
      },
      body: JSON.stringify(gameObject)
    })
      .then(res => {
        if (!res.ok) {
          throw Error(res.statusMessage);
        } else {
          return res.json();
        }
      })
      .then(result => {
        alert(result.message);
        this.props.onEditSave();
        this.handleView();
      })
      .catch(error => console.log("Error: ", error));
  };

  componentDidMount() {
    document.addEventListener("keyup", this.handleEsc);
    this.getGameInfo(this.props.gameId);
  }

  componentWillUnmount() {
    document.removeEventListener("keyup", this.handleEsc);
  }

  getGameInfo(gameId) {
    fetch(`${process.env.REACT_APP_API_URL}/game/${gameId}`)
      .then(response => response.json())
      .then(json => this.setGameInfoToState(json))
      .catch(error => console.log(error));
  }

  setGameInfoToState(json) {
    let token = sessionStorage.getItem("token");

    // Get factions and passwordds
    fetch(
      `${process.env.REACT_APP_API_URL}/game/get-factions/${this.props.gameId}`,
      {
        method: "GET",
        headers: {
          Authorization: "Bearer " + token
        }
      }
    )
      .then(result => result.json())
      .then(result => {
        let factions = result.map(faction => {
          return {
            factionId: faction.factionId,
            factionName: faction.factionName,
            factionPassword: faction.factionPassword,
            multiplier: 1,
            colour: faction.colour
          };
        });

        // Remove objective point's id from the object
        let objectivePoints = json.objective_points.map(point => {
          return {
            objectivePointId: point.objectivePointId,
            objectivePointDescription: point.objectivePointDescription,
            objectivePointMultiplier: point.objectivePointMultiplier
          };
        });

        // get node settings if the settings exists in the game
        let nodesettings =
          json.nodesettings !== null &&
          json.nodesettings.node_settings !== undefined
            ? json.nodesettings.node_settings
            : undefined;

        this.setState({
          gamename: json.name,
          description: json.desc,
          startDate: json.startdate.substring(0, 10),
          startTime: json.startdate.substring(11, 16),
          endDate: json.enddate.substring(0, 10),
          endTime: json.enddate.substring(11, 16),
          mapCenter: {
            lat: json.center.lat,
            lng: json.center.lng
          },
          factions: factions,
          objectivePoints: objectivePoints,
          capture_time:
            nodesettings !== undefined
              ? json.nodesettings.node_settings.capture_time
              : this.state.capture_time,
          confirmation_time:
            nodesettings !== undefined
              ? json.nodesettings.node_settings.confirmation_time
              : this.state.confirmation_time
        });
      })
      .catch(error => console.log(error));
  }

  render() {
    let factions = [];
    for (let i = 0; i < this.state.factions.length; i++) {
      const faction = this.state.factions[i];
      factions.push(
        <li key={faction.factionName}>
          <div style={{ color: faction.colour }}>
            {faction.factionName} : {faction.factionPassword}
          </div>
          <button
            type="button"
            onClick={() => this.removeFaction(faction.factionName)}
          >
            Remove
          </button>
        </li>
      );
    }

    let objectivePoints = [];
    for (let i = 0; i < this.state.objectivePoints.length; i++) {
      const point = this.state.objectivePoints[i];
      objectivePoints.push(
        <li key={point.objectivePointDescription}>
          <div>
            {point.objectivePointDescription} : {point.objectivePointMultiplier}
          </div>
          <button
            type="button"
            onClick={() =>
              this.removeObjectivePoint(point.objectivePointDescription)
            }
          >
            Remove
          </button>
        </li>
      );
    }

    const styles = reactCSS({
      default: {
        color: {
          width: "36px",
          height: "14px",
          borderRadius: "2px",
          background: `${this.state.factionColorInput}`
        },
        swatch: {
          padding: "5px",
          background: "#fff",
          borderRadius: "1px",
          boxShadow: "0 0 0 1px rgba(0,0,0,.1)",
          display: "inline-block",
          cursor: "pointer"
        },
        popover: {
          position: "absolute",
          zIndex: "2"
        },
        cover: {
          position: "fixed",
          top: "0px",
          right: "0px",
          bottom: "0px",
          left: "0px"
        }
      }
    });

    return ReactDOM.createPortal(
      <div className="fade-main">
        <div className="sticky">
          <span
            id="closeEditGameFormX"
            className="close"
            onClick={this.handleView}
          >
            ×
          </span>
        </div>
        <div className="">
          <form id="gameEditForm" onSubmit={this.handleGameSave} />
          <form id="factionAddFrom" onSubmit={this.handleFactionAdd} />
          <form id="gameDeletionForm" onSubmit={this.handleGameDeletion} />
          <form
            id="objectivePointAddFrom"
            onSubmit={this.handleObjectivePointAdd}
          />

          <h1>Demo Game Editor</h1>
          <br />
          <input
            placeholder="Game name"
            name="gamename"
            value={this.state.gamename}
            onChange={this.handleChange}
            id="editGameNameInput"
            form="gameEditForm"
            required
          />
          <br />
          <input
            placeholder="Description"
            type="text"
            name="description"
            value={this.state.description}
            onChange={this.handleChange}
            id="editGameDescriptionInput"
            form="gameEditForm"
            required
          />
          <br />
          <label className="">Start:</label>
          <input
            className="formDate"
            type="date"
            name="startDate"
            value={this.state.startDate}
            onChange={this.handleChange}
            id="editGameDateStartInput"
            form="gameEditForm"
            required
          />
          <input
            className="formTime"
            type="time"
            name="startTime"
            value={this.state.startTime}
            onChange={this.handleChange}
            sid="editGameTimeStartInput"
            form="gameEditForm"
            required
          />
          <br />
          <label className="">End:</label>
          <input
            className="formDate"
            type="date"
            name="endDate"
            value={this.state.endDate}
            onChange={this.handleChange}
            min={this.state.startDate}
            id="editGameDateEndInput"
            form="gameEditForm"
            required
          />
          <input
            className="formTime"
            type="time"
            name="endTime"
            value={this.state.endTime}
            onChange={this.handleChange}
            id="editGameTimeEndInput"
            form="gameEditForm"
            required
          />
          <br />
          <br />

          <label>Factions</label>
          <br />
          <input
            name="factionNameInput"
            value={this.state.factionNameInput}
            minLength="2"
            onChange={this.handleChange}
            placeholder="Add new faction"
            form="factionAddFrom"
          />
          <input
            name="factionPasswordInput"
            value={this.state.factionPasswordInput}
            minLength="3"
            onChange={this.handleChange}
            placeholder="Faction password"
            form="factionAddFrom"
          />
          <div
            style={styles.swatch}
            onClick={() =>
              this.setState({
                displayColorPicker: !this.state.displayColorPicker
              })
            }
          >
            <div style={styles.color} />
          </div>
          {this.state.displayColorPicker && (
            <div
              style={styles.cover}
              onClick={() => this.setState({ displayColorPicker: false })}
            >
              <SketchPicker
                color={this.state.factionColorInput}
                onChangeComplete={color =>
                  this.setState({ factionColorInput: color.hex })
                }
              />
            </div>
          )}
          <button type="submit" form="factionAddFrom">
            Add
          </button>
          <ul>{factions}</ul>
          <br />
          <br />
          <label>Objective points</label>
          <br />
          <input
            name="objectivePointDescriptionInput"
            type="number"
            value={this.state.objectivePointDescriptionInput}
            onChange={this.handleChange}
            placeholder="Objective point id"
            min="1000000"
            form="objectivePointAddFrom"
          />
          <input
            name="objectivePointMultiplierInput"
            type="number"
            value={this.state.objectivePointMultiplierInput}
            onChange={this.handleChange}
            placeholder="Objective point multiplier"
            form="objectivePointAddFrom"
          />
          <button type="submit" form="objectivePointAddFrom">
            Add
          </button>
          <ul>{objectivePoints}</ul>
          <br />
          <br />
          <label>Node things (set if objective points are in the game)</label>
          <br />
          <br />
          <label className="" form="gameEditForm">
            Capture time:
          </label>
          <input
            name="capture_time"
            type="number"
            value={this.state.capture_time}
            form="gameEditForm"
            onChange={this.handleChange}
          />
          <label className="">Confimation time:</label>
          <input
            name="confirmation_time"
            type="number"
            value={this.state.confirmation_time}
            form="gameEditForm"
            onChange={this.handleChange}
          />
          <br />
          <br />
          <label>Map things</label>
          <br />
          <Map
            id="editGameCenterMap"
            className=""
            center={[this.state.mapCenter.lat, this.state.mapCenter.lng]}
            zoom={this.state.zoom}
            maxZoom="13"
            style={{ height: "400px", width: "400px" }}
            onmoveend={this.handleMapDrag}
            onzoomend={this.handleMapScroll}
          >
            <TileLayer
              attribution="Maanmittauslaitoksen kartta"
              url=" https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg"
            />
          </Map>
          <br />
          <button
            style={{ backgroundColor: "red" }}
            type="submit"
            form="gameDeletionForm"
          >
            Delete
          </button>
          <button id="editGameSubmitButton" type="submit" form="gameEditForm">
            Save changes
          </button>
          <h2>{this.state.errorMsg}</h2>
        </div>
      </div>,
      document.getElementById("form")
    );
  }
}