import React, { useEffect, useState } from "react";

import Button from "react-bootstrap/Button";
import Container from "react-bootstrap/Container";
import Form from "react-bootstrap/Form";

import InputGroup from "react-bootstrap/InputGroup";
import ListGroup from "react-bootstrap/ListGroup";
import Modal from "react-bootstrap/Modal";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faUser, faPlus, faRemove, faSave, faSearch, faSignOut } from "@fortawesome/free-solid-svg-icons";

import CONSTANTS from "./constants";

import "./App.css";

function ConfirmLogout({ setOpenConfirmLogout, setLoginState, fetchNotes, setViewState }) {
  const handleConfirmLogout = () => {
    fetch(`//${CONSTANTS.LOGOUT_URL}`)
      .then((res) => res.json())
      .then((res_json) => {
        setLoginState(CONSTANTS.NOT_LOGGED_IN);
        setOpenConfirmLogout(false);
      });
  };

  return (
    <div className="modal show" style={{ display: "block", position: "fixed", marginTop: "33vh" }}>
      <Modal.Dialog>
        <Modal.Header closeButton>
          <Modal.Title>Are you sure to quit editing the note and log out ? </Modal.Title>
        </Modal.Header>
        <Modal.Footer>
          <Button variant="secondary" onClick={(e) => setOpenConfirmLogout(false)}>
            Cancel
          </Button>
          <Button
            variant="primary"
            onClick={(e) => {
              handleConfirmLogout(e);
            }}
          >
            Logout
          </Button>
        </Modal.Footer>
      </Modal.Dialog>
    </div>
  );
}

function ConfirmCancelEdit({ setOpenConfirmCancelEdit, fetchNotes, setViewState }) {
  return (
    <div className="modal show" style={{ display: "block", position: "fixed", marginTop: "33vh" }}>
      <Modal.Dialog>
        <Modal.Header closeButton>
          <Modal.Title>Are you sure to quit editing the note ? </Modal.Title>
        </Modal.Header>
        <Modal.Footer>
          <Button variant="secondary" onClick={(e) => setOpenConfirmCancelEdit(false)}>
            Close
          </Button>
          <Button
            variant="primary"
            onClick={(e) => {
              setViewState(CONSTANTS.VIEW_STATE_VIEW_NOTE);
              fetchNotes();
              setOpenConfirmCancelEdit(false);
            }}
          >
            cancel edit
          </Button>
        </Modal.Footer>
      </Modal.Dialog>
    </div>
  );
}

function ConfirmDeleteNote({ note_id, setOpenConfirmDeleteNote, fetchNotes, setViewState }) {
  const handleDeleteClick = () => {
    fetch(`//${CONSTANTS.DELETE_NOTE_ENDPOINT}/${note_id}`, {
      method: "DELETE",
      credentials: "include",
    })
      .then((res) => res.json())
      .then((res_json) => {
        fetchNotes();
        setViewState(CONSTANTS.VIEW_STATE_EMPTY_NOTE);
        setOpenConfirmDeleteNote(false);
      });
  };

  return (
    <div className="modal show" style={{ display: "block", position: "fixed", marginTop: "33vh" }}>
      <Modal.Dialog>
        <Modal.Header closeButton>
          <Modal.Title>Are you sure to quit editing the note ? </Modal.Title>
        </Modal.Header>
        <Modal.Footer>
          <Button variant="secondary" onClick={(e) => setOpenConfirmDeleteNote(false)}>
            Close
          </Button>
          <Button variant="primary" onClick={(e) => handleDeleteClick(e)}>
            Confirm delete
          </Button>
        </Modal.Footer>
      </Modal.Dialog>
    </div>
  );
}

const ViewNote = ({ view_note_id, setViewState, setViewNoteId, first_note_id, fetchNotes }) => {
  var [note_detail, setNoteDetail] = useState("");
  var [iso_day_string, setIsoDayString] = useState("");
  var [open_confirm_delete_note, setOpenConfirmDeleteNote] = useState(false);

  const handleDeleteClick = () => {
    setOpenConfirmDeleteNote(true);
  };

  useEffect(() => {
    fetch(`//${CONSTANTS.GET_NOTE_ENDPOINT}/${view_note_id}`, { credentials: "include" })
      .then((res) => res.json())
      .then((res_json) => {
        setNoteDetail(res_json[0]);
        if (res_json[0]?.lastsavedtime && res_json[0]?.lastsavedtime != "") {
          var d = new Date(res_json[0].lastsavedtime);
          setIsoDayString(d.toISOString().split(".")[0].replace("T", " "));
        } else {
          setIsoDayString("");
        }
      });
  }, [view_note_id]);

  return (
    <>
      {open_confirm_delete_note ? (
        <ConfirmDeleteNote
          note_id={note_detail._id}
          setViewState={setViewState}
          fetchNotes={fetchNotes}
          setOpenConfirmDeleteNote={setOpenConfirmDeleteNote}
        />
      ) : (
        <></>
      )}
      <div class="viewnote-container">
        <div class="viewnote-body">
          <div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", alignItems: "center" }}>
            <div>Last saved: {iso_day_string || ""}</div>
            <div class="button-container">
              <Button variant="primary" onClick={(e) => handleDeleteClick(e)}>
                <div class="icon-button-container">
                  <div>
                    <FontAwesomeIcon icon={faSave} />
                  </div>
                  <div class="icon-button-text">Delete</div>
                </div>
              </Button>
            </div>
          </div>
          <div class="input-container">
            <Form.Control
              type="text"
              id="note-title"
              aria-describedby="note-title"
              value={note_detail?.title || ""}
              onClick={(e) => {
                setViewState(CONSTANTS.VIEW_STATE_EDIT_NOTE);
              }}
              style={{ cursor: "pointer" }}
            />
          </div>
          <div class="input-container">
            <Form.Control
              as="textarea"
              rows={10}
              value={note_detail?.content || ""}
              onClick={(e) => {
                setViewState(CONSTANTS.VIEW_STATE_EDIT_NOTE);
              }}
              style={{ cursor: "pointer" }}
            />
          </div>
        </div>
      </div>
    </>
  );
};

// EXPLAIN: After one clicks on the “New note icon” (on any page view where it is shown),
// EXPLAIN: a new node creation panel shows in the right panel (Fig. 3).
// EXPLAIN: There is a node title input field and a note content input field, into which the user can enter texts.
// EXPLAIN: There is a “Cancel” button, clicking which a confirmation box

// EXPLAIN: “Are you sure to quit editing the note?” will be popped up:
// EXPLAIN: if the user confirms quitting, the page view goes back to the one shown in Fig. 2;
// EXPLAIN: otherwise, the current page view remains.

// EXPLAIN: There is a “Save” button, clicking which the newly created note is shown on the right panel,
// EXPLAIN: with the “Last saved” time and a “Delete” button displayed on top of the note,
// EXPLAIN: as shown in Fig. 4; besides, the note title should be listed in the left panel,
// EXPLAIN: as the first in the list (as it is the latest), the note title should be highlighted in a different color than the
// EXPLAIN: rest of the note titles in the list (since this note’s content is shown in the right panel),
// EXPLAIN: and the total number of notes in ( ) on top of the list should be incremented.

const NewNote = ({ fetchNotes, setViewState }) => {
  var [note_title, setNoteTitle] = useState("");
  var [note_content, setNoteContent] = useState("");
  var [open_confirm_cancel_edit, setOpenConfirmCancelEdit] = useState(false);

  const handleSaveNoteClick = () => {
    fetch(`//${CONSTANTS.ADD_NEW_NOTE_ENDPOINT}`, {
      method: "POST",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ title: note_title, content: note_content }),
    })
      .then((res) => res.json())
      .then((res_json) => {
        fetchNotes();
        setViewState(CONSTANTS.VIEW_STATE_EMPTY_NOTE);
      });
  };

  return (
    <>
      {open_confirm_cancel_edit ? (
        <ConfirmCancelEdit
          setViewState={setViewState}
          fetchNotes={fetchNotes}
          setOpenConfirmCancelEdit={setOpenConfirmCancelEdit}
        />
      ) : (
        <></>
      )}
      <div class="viewnote-container">
        <div class="viewnote-body">
          <div class="viewnote-title">
            <div class="button-container">
              <Button variant="primary" onClick={(e) => setOpenConfirmCancelEdit(true)}>
                <div class="icon-button-container">
                  <div>
                    <FontAwesomeIcon icon={faRemove} />
                  </div>
                  <div class="icon-button-text">Cancel</div>
                </div>
              </Button>
            </div>
            <div class="button-container">
              <Button variant="primary" onClick={(e) => handleSaveNoteClick(e)}>
                <div class="icon-button-container">
                  <div>
                    <FontAwesomeIcon icon={faSave} />
                  </div>
                  <div class="icon-button-text">Save</div>
                </div>
              </Button>
            </div>
          </div>
          <div class="input-container">
            <Form.Label htmlFor="note-title">Note title</Form.Label>
            <Form.Control
              type="text"
              id="new-note-title"
              aria-describedby="note-title"
              onChange={(e) => setNoteTitle(e.target.value)}
            />
          </div>
          <div class="input-container">
            <div>
              <Form.Label htmlFor="new-note-content">Note Content</Form.Label>
              <Form.Control as="textarea" rows={10} onChange={(e) => setNoteContent(e.target.value)} />
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

const EditNote = ({ view_note_id, fetchNotes, setViewState }) => {
  var [note_title, setNoteTitle] = useState("");
  var [note_content, setNoteContent] = useState("");
  var [open_confirm_cancel_edit, setOpenConfirmCancelEdit] = useState(false);

  var [note_detail, setNoteDetail] = useState("");

  const handleSaveNoteClick = () => {
    fetch(`//${CONSTANTS.SAVE_NOTE_ENDPOINT}/${view_note_id}`, {
      method: "PUT",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ title: note_title, content: note_content }),
    })
      .then((res) => res.json())
      .then((res_json) => {
        fetchNotes();
        setViewState(CONSTANTS.VIEW_STATE_EMPTY_NOTE);
      });
  };

  useEffect(() => {
    fetch(`//${CONSTANTS.GET_NOTE_ENDPOINT}/${view_note_id}`, {
      credentials: "include",
    })
      .then((res) => res.json())
      .then((res_json) => {
        setNoteTitle(res_json[0]?.title);
        setNoteContent(res_json[0]?.content);
      });
  }, [view_note_id]);

  return (
    <>
      {open_confirm_cancel_edit ? (
        <ConfirmCancelEdit
          setViewState={setViewState}
          fetchNotes={fetchNotes}
          setOpenConfirmCancelEdit={setOpenConfirmCancelEdit}
        />
      ) : (
        <></>
      )}
      <div class="viewnote-container">
        <div class="viewnote-body">
          <div class="viewnote-title">
            <div class="button-container">
              <Button variant="primary" onClick={(e) => setOpenConfirmCancelEdit(true)}>
                <div class="icon-button-container">
                  <div>
                    <FontAwesomeIcon icon={faRemove} />
                  </div>
                  <div style={{ paddingLeft: "0.5rem" }}>Cancel</div>
                </div>
              </Button>
            </div>
            <div class="button-container">
              <Button variant="primary" onClick={(e) => handleSaveNoteClick(e)}>
                <div class="icon-button-container">
                  <div>
                    <FontAwesomeIcon icon={faSave} />
                  </div>
                  <div style={{ paddingLeft: "0.5rem" }}>Save</div>
                </div>
              </Button>
            </div>
          </div>
          <div class="input-container">
            <Form.Label htmlFor="note-title">Note title</Form.Label>
            <Form.Control
              type="text"
              id="new-note-title"
              aria-describedby="note-title"
              value={note_title}
              onChange={(e) => setNoteTitle(e.target.value)}
            />
          </div>
          <div class="input-container">
            <div>
              <Form.Label htmlFor="new-note-content">Note Content</Form.Label>
              <Form.Control
                as="textarea"
                rows={10}
                value={note_content}
                onChange={(e) => setNoteContent(e.target.value)}
              />
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

const AddNoteButton = ({ setViewNoteId, view_state, setViewState }) => {
  if ([CONSTANTS.VIEW_STATE_EMPTY_NOTE, CONSTANTS.VIEW_STATE_VIEW_NOTE].includes(view_state))
    return (
      <button
        type="button"
        class="btn btn-primary btn-circle btn-lg"
        onClick={(e) => {
          setViewNoteId("");
          setViewState(CONSTANTS.VIEW_STATE_ADD_NOTE);
        }}
      >
        <FontAwesomeIcon icon={faPlus} />
      </button>
    );

  return <></>;
};

const Home = ({ user_info, setUserInfo, setLoginState }) => {
  var [note_list, setNoteList] = useState([]);
  var [is_loading, setIsLoading] = useState(true);
  var [search_note, setSearchNote] = useState("");
  var [view_state, setViewState] = useState(CONSTANTS.VIEW_STATE_VIEW_NOTE);
  var [view_note_id, setViewNoteId] = useState("");
  var [first_note_id, setFirstNoteId] = useState("");
  var [open_confirm_logout, setOpenConfirmLogout] = useState(false);

  const handleLogoutClick = () => {
    setOpenConfirmLogout(true);
  };

  const fetchNotes = () => {
    fetch(`//${CONSTANTS.GET_NOTE_ENDPOINT}/*`, {
      credentials: "include",
    })
      .then((res) => res.json())
      .then((res_json) => {
        setIsLoading(false);
        setNoteList(res_json);
      });
  };

  useEffect(() => {
    setIsLoading(true);
    fetch(`//${CONSTANTS.SEARCH_URL}/${search_note}`, {
      credentials: "include",
    })
      .then((res) => res.json())
      .then((res_json) => {
        setIsLoading(false);
        setNoteList(res_json);
      });
  }, [search_note]);

  useEffect(() => {
    setViewState(CONSTANTS.VIEW_STATE_EMPTY_NOTE);
    fetchNotes();
  }, []);

  if (is_loading) return <>loading...</>;

  const EmptyNote = () => {
    return <></>;
  };

  const NoteContent = ({ view_state, view_note_id, setViewNoteId }) => {
    if (view_state == CONSTANTS.VIEW_STATE_VIEW_NOTE) {
      return (
        <ViewNote
          view_note_id={view_note_id}
          setViewNoteId={setViewNoteId}
          first_note_id={first_note_id}
          fetchNotes={fetchNotes}
          setViewState={setViewState}
        />
      );
    }
    if (view_state == CONSTANTS.VIEW_STATE_ADD_NOTE)
      return <NewNote setViewState={setViewState} fetchNotes={fetchNotes} />;
    if (view_state == CONSTANTS.VIEW_STATE_EDIT_NOTE)
      return <EditNote view_note_id={view_note_id} setViewState={setViewState} fetchNotes={fetchNotes} />;

    return <EmptyNote />;
  };

  if (note_list == []) return <>loading notes</>;

  return (
    <>
      {open_confirm_logout ? (
        <ConfirmLogout setOpenConfirmLogout={setOpenConfirmLogout} setLoginState={setLoginState} />
      ) : (
        <></>
      )}
      <div class="home-container">
        <div class="home-background">iNotes</div>
        <div class="top-nav-bar">
          <div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between" }}>
            <div
              style={{
                display: "flex",
                flexDirection: "row",
                alignItems: "center",
                paddingLeft: "2rem",
              }}
            >
              <div
                class="user-avatar"
                style={{ backgroundImage: `url("http://${CONSTANTS.BACKEND_HOST}/${user_info.icon}")` }}
              ></div>
              <div class="username-container">{user_info.name}</div>
            </div>
            <div class="logout-button-container">
              <Button variant="primary" onClick={(e) => handleLogoutClick(e)}>
                <div class="icon-button-container">
                  <div>
                    <FontAwesomeIcon icon={faSignOut} />
                  </div>
                  <div class="icon-button-text">log out</div>
                </div>
              </Button>
            </div>
          </div>
        </div>
        <div class="left-nav-bar-container">
          <div style={{ width: "20vw", display: "flex", flexDirection: "column", paddingTop: "1rem" }}>
            <div style={{ display: "flex", flexDirection: "row", justifyContent: "center", paddingTop: "2rem" }}>
              <div style={{ width: "80%", display: "flex" }}>
                <InputGroup className="mb-3">
                  <InputGroup.Text>
                    <FontAwesomeIcon icon={faSearch} />
                  </InputGroup.Text>
                  <Form.Control id="search-note" onChange={(e) => setSearchNote(e.target.value)} />
                </InputGroup>
              </div>
            </div>
            <div class="left-nav-bar-notes-container">
              <div style={{ fontSize: "2rem" }}>Notes ({note_list.length})</div>

              {note_list.length < 1 ? (
                <>sorry but the list is empty</>
              ) : (
                <>
                  <ListGroup class="list-group-container">
                    {note_list
                      .filter((n) => {
                        const re = new RegExp(search_note);
                        return n.title?.search(re) > -1;
                      })
                      .map((n, idx) => (
                        <ListGroup.Item
                          key={`list_${idx}`}
                          onClick={(e) => {
                            setViewNoteId(n._id);
                            setViewState(CONSTANTS.VIEW_STATE_VIEW_NOTE);
                          }}
                          style={{ backgroundColor: n._id == view_note_id ? "cyan" : "" }}
                        >
                          {n.title || "no title"}
                        </ListGroup.Item>
                      ))}
                  </ListGroup>
                </>
              )}
            </div>
          </div>

          <div class="note-container">
            <NoteContent setViewNoteId={setViewNoteId} view_state={view_state} view_note_id={view_note_id} />
          </div>
          <div class="add-note-button-container">
            <AddNoteButton setViewNoteId={setViewNoteId} view_state={view_state} setViewState={setViewState} />
          </div>
        </div>
      </div>
    </>
  );
};

const Login = ({ login_state, setLoginState, setUserInfo }) => {
  var [debug, setDebug] = useState();
  var [username, setUsername] = useState("");
  var [password, setPassword] = useState("");

  const helloworld_alert = (username, password) => {
    fetch("//localhost:3001/signin", {
      method: "POST",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password }),
    });
  };

  const handleSignIn = (username, password) => {
    fetch(`//${CONSTANTS.SIGN_IN_URL}`, {
      method: "POST",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password }),
    })
      .then((res) => res.json())
      .then((res_json) => {
        setDebug(JSON.stringify(res_json));
        if (res_json.msg == CONSTANTS.MSG_LOGIN_SUCCESS) {
          setLoginState(CONSTANTS.LOGGED_IN);
          setUserInfo(res_json.user_meta);
        }
      });
  };

  return (
    <Container>
      <div>
        <div class="login-background">
          <div style={{ fontSize: "3rem" }}>iNotes</div>
          <div style={{ paddingTop: "5rem" }}>
            <Form>
              <Form.Group className="mb-3">
                <div class="menu-input-field">
                  <Form.Label>Username:</Form.Label>
                  <div class="login-input-container">
                    <Form.Control
                      type="text"
                      placeholder="username"
                      value={username}
                      onChange={(e) => setUsername(e.target.value)}
                    />
                  </div>
                </div>
              </Form.Group>
              <Form.Group className="mb-3">
                <div class="menu-input-field">
                  <Form.Label>Password:</Form.Label>
                  <div class="login-input-container">
                    <Form.Control
                      type="password"
                      placeholder="password"
                      value={password}
                      onChange={(e) => {
                        setPassword(e.target.value);
                      }}
                    />
                  </div>
                </div>
              </Form.Group>
            </Form>
          </div>
          <div style={{ paddingTop: "5rem" }}>
            <Button variant="primary" onClick={(e) => handleSignIn(username, password)}>
              <div class="icon-button-container">
                <div>
                  <FontAwesomeIcon icon={faUser} />
                </div>
                <div class="icon-button-text">Sign in</div>
              </div>
            </Button>
          </div>
        </div>
      </div>
    </Container>
  );
};

const App = () => {
  var [login_state, setLoginState] = useState(CONSTANTS.NOT_LOGGED_IN);
  var [user_info, setUserInfo] = useState({});

  if (login_state == CONSTANTS.NOT_LOGGED_IN) {
    return <Login login_state={login_state} setLoginState={setLoginState} setUserInfo={setUserInfo} />;
  }

  return (
    <div>
      <Home user_info={user_info} setUserInfo={setUserInfo} setLoginState={setLoginState} />
    </div>
  );
};

export default App;
