import React, { Component } from 'react';
import './TodoApp.css';

interface Item {
  name: string;
  completed: boolean;
}

interface AppState {
  items: Item[];    // existing items
  newName: string;  // text in the field to add a new name
}

export class TodoApp extends Component<{}, AppState> {

  constructor(props: any) {
    super(props);
    this.state = { items: [], newName: "" };

    setTimeout(() => this.refresh(), 0);  // get the correct state from the server
  }

  // Called when the user checks the box next to an uncompleted item. The
  // second parameter is the index of that item in the list.
  async completeItem(evt: any, index: number) {
    const items = this.state.items.slice(0);
    items[index] = {name: items[index].name, completed: true};
    this.setState({items: items});

    let resp = await fetch(
        "http://localhost:4567/completed?name=" +
            encodeURIComponent(items[index].name),
        {method: "POST", body: ""});
    if (!resp.ok)
      throw new Error(`bad response: ${resp.statusText}`);

    setTimeout(() => this.refresh(), 5500);  // update when it disappears
  }

  // Called when the user clicks on the button to add the new item.
  async addItem(evt: any) {
    const name = this.state.newName.trim().replace('\t', ' ');  // no tabs
    if (name.length > 0) {
      const items = this.state.items.slice(0);
      items.push({name: name, completed: false});
      this.setState({items: items, newName: ""});

      let resp = await fetch(
          "http://localhost:4567/add?name=" + encodeURIComponent(name),
          {method: "POST", body: ""})
      if (!resp.ok)
        throw new Error(`bad response: ${resp.statusText}`);
    }
  }

  // Called when the user clisk the Refresh button. Sync to server state.
  async refresh() {
    let resp = await fetch("http://localhost:4567/list");
    let text = await resp.text();

    const items = [];
    if (text.length > 0) {
      const lines = text.split('\n');
      for (let i = 0; i < lines.length; i++) {
        const text = lines[i].trim();
        if (text.endsWith("\t(completed)")) {
          items.push({name: text.substring(0, text.length-12), completed: true});
        } else {
          items.push({name: text, completed: false});
        }
      }
    }
    this.setState({items: items});
  }

  // Called each time the text in the new item name field is changed.
  setNewName(evt: any) {
    this.setState({newName: evt.target.value});
  }

  render() {
    let items : any[] = [];
    for (let i = 0; i < this.state.items.length; i++) {
      if (this.state.items[i].completed) {
        items.push(
          <div className="form-check" key={i}>
            <input className="form-check-input" type="checkbox"
                id={"check" + i} checked={true} readOnly={true} />
            <label className="form-check-label completed" htmlFor={"check" + i}>
              {this.state.items[i].name}
            </label>
          </div>);
      } else {
        items.push(
          <div className="form-check" key={i}>
            <input className="form-check-input" type="checkbox"
                id={"check" + i} checked={false}
                onChange={evt => this.completeItem(evt, i)} />
            <label className="form-check-label" htmlFor={"check" + i}>
              {this.state.items[i].name}
            </label>
          </div>);
      }
    }

    return (
      <div>
        <h2>To-Do List</h2>
        {items}
        <p className="instructions">Check the item to mark it completed.</p>
        <p className="more-instructions">New item:
          <input type="text" className="new-item"
              value={this.state.newName}
              onChange={evt => this.setNewName(evt)} />
          <button type="button" className="btn btn-link"
              onClick={evt => this.addItem(evt)}>Add</button>
        </p>
        <p className="more-instructions">
          <button type="button" className="btn btn-link refresh"
              onClick={() => this.refresh()}>Refresh</button>
        </p>
      </div>);
  }

}
