import { useState, useEffect } from "react";
import Head from "next/head";
import { useRouter } from "next/router";
import { useTranslation } from "next-i18next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import {
  Collapse,
  Container,
  Row,
  Col,
  Input,
  Label,
  InputGroup,
  InputGroupAddon,
  Button,
  Card,
  CardBody,
} from "reactstrap";
import { ReactMultiEmail, isEmail } from "react-multi-email";
import "react-multi-email/style.css";
import { toast, ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import queryString from "query-string";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faPlus,
  faTrashAlt,
  faCheck,
  faCogs,
  faExclamationTriangle,
} from "@fortawesome/free-solid-svg-icons";
import { useAppContext } from "@services/context";
import { createElection } from "@services/api";
import { translateGrades } from "@services/grades";
import HelpButton from "@components/form/HelpButton";
import Loader from "@components/wait";
import CandidatesField from "@components/form/CandidatesField";
import ConfirmModal from "@components/form/ConfirmModal";
import config from "../../next-i18next.config.js";

// Error messages
const AT_LEAST_2_CANDIDATES_ERROR = "Please add at least 2 candidates.";
const NO_TITLE_ERROR = "Please add a title.";

const isValidDate = (date) => date instanceof Date && !isNaN(date);
const getOnlyValidDate = (date) => (isValidDate(date) ? date : new Date());

// Convert a Date object into YYYY-MM-DD
const dateToISO = (date) =>
  getOnlyValidDate(date).toISOString().substring(0, 10);

// Retrieve the current hour, minute, sec, ms, time into a timestamp
const hours = (date) => getOnlyValidDate(date).getHours() * 3600 * 1000;
const minutes = (date) => getOnlyValidDate(date).getMinutes() * 60 * 1000;
const seconds = (date) => getOnlyValidDate(date).getSeconds() * 1000;
const ms = (date) => getOnlyValidDate(date).getMilliseconds();
const time = (date) =>
  hours(getOnlyValidDate(date)) +
  minutes(getOnlyValidDate(date)) +
  seconds(getOnlyValidDate(date)) +
  ms(getOnlyValidDate(date));

// Retrieve the time part from a timestamp and remove the day. Return a int.
const timeMinusDate = (date) => time(getOnlyValidDate(date));

// Retrieve the day and remove the time. Return a Date
const dateMinusTime = (date) =>
  new Date(getOnlyValidDate(date).getTime() - time(getOnlyValidDate(date)));

const displayClockOptions = () =>
  Array(24)
    .fill(1)
    .map((x, i) => (
      <option value={i} key={i}>
        {i}h00
      </option>
    ));

export const getStaticProps = async ({ locale }) => ({
  props: {
    ...(await serverSideTranslations(locale, [], config)),
  },
});

const CreateElection = (props) => {
  const { t } = useTranslation();

  // default value : start at the last hour
  const now = new Date();
  const [title, setTitle] = useState("");
  const [candidates, setCandidates] = useState([{ label: "" }, { label: "" }]);
  const [numGrades, setNumGrades] = useState(5);
  const [waiting, setWaiting] = useState(false);
  const [isAdvancedOptionsOpen, setAdvancedOptionsOpen] = useState(false);
  const [isTimeLimited, setTimeLimited] = useState(false);
  const [restrictResult, setRestrictResult] = useState(false);
  const [start, setStart] = useState(
    new Date(now.getTime() - minutes(now) - seconds(now) - ms(now))
  );
  const [finish, setFinish] = useState(
    new Date(start.getTime() + 7 * 24 * 3600 * 1000)
  );
  const [emails, setEmails] = useState([]);

  // set the title on loading
  const router = useRouter();
  useEffect(() => {
    if (!router.isReady) return;

    const { title: urlTitle } = router.query;
    setTitle(urlTitle || "");
  }, [router.isReady]);

  const handleIsTimeLimited = (event) => {
    setTimeLimited(event.target.value === "1");
  };

  const handleRestrictResultCheck = (event) => {
    setRestrictResult(event.target.value === "1");
  };

  const toggleAdvancedOptions = () => {
    setAdvancedOptionsOpen(!isAdvancedOptionsOpen);
  };

  const addCandidate = () => {
    if (candidates.length < 1000) {
      candidates.push({ label: "" });
      setCandidates(candidates);
    }
  };

  const checkFields = () => {
    if (!candidates) {
      return { ok: false, msg: AT_LEAST_2_CANDIDATES_ERROR };
    }

    let numCandidates = 0;
    candidates.forEach((c) => {
      if (c.label !== "") numCandidates += 1;
    });
    if (numCandidates < 2) {
      return { ok: false, msg: AT_LEAST_2_CANDIDATES_ERROR };
    }

    if (!title || title === "") {
      return { ok: false, msg: NO_TITLE_ERROR };
    }

    return { ok: true, msg: "OK" };
  };

  const handleSubmit = () => {
    const check = checkFields();
    if (!check.ok) {
      toast.error(t(check.msg), {
        position: toast.POSITION.TOP_CENTER,
      });
      return;
    }

    setWaiting(true);

    createElection(
      title,
      candidates.map((c) => c.label).filter((c) => c !== ""),
      {
        mails: emails,
        numGrades,
        start: start.getTime() / 1000,
        finish: finish.getTime() / 1000,
        restrictResult: restrictResult,
        locale: router.locale.substring(0, 2).toLowerCase(),
      },
      (result) => {
        if (result.id) {
          router.push(`/new/confirm/${result.id}`);
        } else {
          toast.error(t("Unknown error. Try again please."), {
            position: toast.POSITION.TOP_CENTER,
          });
          setWaiting(false);
        }
      }
    );
  };

  const handleSendNotReady = (msg) => {
    toast.error(t(msg), {
      position: toast.POSITION.TOP_CENTER,
    });
  };

  const check = checkFields();
  const grades = translateGrades(t);

  return (
    <Container>
      <Head>
        <meta
          key="og:title"
          property="og:title"
          content={t("common.application")}
        />
        <meta
          property="og:description"
          key="og:description"
          content={t("resource.valueProp")}
        />
      </Head>
      <ToastContainer />
      {waiting ? <Loader /> : ""}
      <form onSubmit={handleSubmit} autoComplete="off">
        <Row>
          <Col>
            <h3>{t("resource.startVote")}</h3>
          </Col>
        </Row>
        <hr />
        <Row className="mt-4">
          <Col xs="12">
            <Label for="title">{t("resource.questionLabel")}</Label>
          </Col>
          <Col>
            <Input
              placeholder={t("resource.writeQuestionHere")}
              tabIndex="1"
              name="title"
              id="title"
              autoFocus
              value={title}
              onChange={(e) => setTitle(e.target.value)}
              maxLength="250"
            />
          </Col>
          <Col xs="auto" className="align-self-center pl-0">
            <HelpButton>
              <u>{t("resource.eg")}</u> <em>{t("resource.exampleQuestion")}</em>
            </HelpButton>
          </Col>
        </Row>
        <Row className="mt-4">
          <Col xs="12">
            <Label for="title">{t("common.candidates")}</Label>
          </Col>
          <Col xs="12">
            <CandidatesField onChange={setCandidates} />
          </Col>
          <Col
            xs="12"
            sm="6"
            md="12"
            className="text-center text-sm-right text-md-left"
          >
            <Button
              color="link"
              className="text-white mt-3 mb-1"
              onClick={toggleAdvancedOptions}
            >
              <FontAwesomeIcon icon={faCogs} className="mr-2" />
              {t("resource.advancedOptions")}
            </Button>
          </Col>
        </Row>
        <Collapse isOpen={isAdvancedOptionsOpen}>
          <Card>
            <CardBody className="text-primary">
              <Row>
                <Col xs="12" md="3" lg="3">
                  <Label for="title">{t("Access to results")}</Label>
                </Col>
                <Col xs="12" md="4" lg="3">
                  <Label className="radio " htmlFor="restrict_result_false">
                    <span className="small text-dark">{t("Immediately")}</span>
                    <input
                      className="radio"
                      type="radio"
                      name="restrict_result"
                      id="restrict_result_false"
                      onClick={handleRestrictResultCheck}
                      defaultChecked={!restrictResult}
                      value="0"
                    />
                    <span className="checkround checkround-gray" />
                  </Label>
                </Col>
                <Col xs="12" md="4" lg="3">
                  <Label className="radio" htmlFor="restrict_result_true">
                    <span className="small">
                      <span className="text-dark">
                        {t("At the end of the election")}
                      </span>
                      <HelpButton className="ml-2">
                        {t(
                          "No one will be able to see the result until the end date is reached or until all participants have voted."
                        )}
                      </HelpButton>
                    </span>
                    <input
                      className="radio"
                      type="radio"
                      name="restrict_result"
                      id="restrict_result_true"
                      onClick={handleRestrictResultCheck}
                      defaultChecked={restrictResult}
                      value="1"
                    />
                    <span className="checkround checkround-gray" />
                  </Label>
                </Col>
              </Row>
              <hr className="mt-2 mb-2" />
              <Row>
                <Col xs="12" md="3" lg="3">
                  <Label for="title">{t("Voting time")}</Label>
                </Col>
                <Col xs="12" md="4" lg="3">
                  <Label className="radio " htmlFor="is_time_limited_false">
                    <span className="small text-dark">{t("Unlimited")}</span>
                    <input
                      className="radio"
                      type="radio"
                      name="time_limited"
                      id="is_time_limited_false"
                      onClick={handleIsTimeLimited}
                      defaultChecked={!isTimeLimited}
                      value="0"
                    />
                    <span className="checkround checkround-gray" />
                  </Label>
                </Col>
                <Col xs="12" md="4" lg="3">
                  <Label className="radio" htmlFor="is_time_limited_true">
                    <span className="small">
                      <span className="text-dark">{t("Defined period")}</span>
                    </span>
                    <input
                      className="radio"
                      type="radio"
                      name="time_limited"
                      id="is_time_limited_true"
                      onClick={handleIsTimeLimited}
                      defaultChecked={isTimeLimited}
                      value="1"
                    />
                    <span className="checkround checkround-gray" />
                  </Label>
                </Col>
              </Row>
              <div
                className={
                  (isTimeLimited ? "d-block " : "d-none") + " bg-light p-3"
                }
              >
                <Row>
                  <Col xs="12" md="3" lg="3">
                    <span className="label">- {t("Starting date")}</span>
                  </Col>
                  <Col xs="6" md="4" lg="3">
                    <input
                      className="form-control"
                      type="date"
                      value={dateToISO(start)}
                      onChange={(e) => {
                        setStart(
                          new Date(
                            timeMinusDate(start) +
                              new Date(e.target.valueAsNumber).getTime()
                          )
                        );
                      }}
                    />
                  </Col>
                  <Col xs="6" md="5" lg="3">
                    <select
                      className="form-control"
                      value={getOnlyValidDate(start).getHours()}
                      onChange={(e) =>
                        setStart(
                          new Date(
                            dateMinusTime(start).getTime() +
                              e.target.value * 3600000
                          )
                        )
                      }
                    >
                      {displayClockOptions()}
                    </select>
                  </Col>
                </Row>

                <Row className="mt-2">
                  <Col xs="12" md="3" lg="3">
                    <span className="label">- {t("Ending date")}</span>
                  </Col>
                  <Col xs="6" md="4" lg="3">
                    <input
                      className="form-control"
                      type="date"
                      value={dateToISO(finish)}
                      min={dateToISO(start)}
                      onChange={(e) => {
                        setFinish(
                          new Date(
                            timeMinusDate(finish) +
                              new Date(e.target.valueAsNumber).getTime()
                          )
                        );
                      }}
                    />
                  </Col>
                  <Col xs="6" md="5" lg="3">
                    <select
                      className="form-control"
                      value={getOnlyValidDate(finish).getHours()}
                      onChange={(e) =>
                        setFinish(
                          new Date(
                            dateMinusTime(finish).getTime() +
                              e.target.value * 3600000
                          )
                        )
                      }
                    >
                      {displayClockOptions()}
                    </select>
                  </Col>
                </Row>
              </div>
              <hr className="mt-2 mb-2" />
              <Row>
                <Col xs="12" md="3" lg="3">
                  <span className="label">{t("Grades")}</span>
                </Col>
                <Col xs="10" sm="11" md="4" lg="3">
                  <select
                    className="form-control"
                    tabIndex={candidates.length + 3}
                    onChange={(e) => setNumGrades(e.target.value)}
                    defaultValue="5"
                  >
                    <option value="4">4</option>
                    <option value="5">5</option>
                    <option value="6">6</option>
                    <option value="7">7</option>
                  </select>
                </Col>
                <Col xs="auto" className="align-self-center pl-0 ">
                  <HelpButton>
                    {t(
                      "You can select here the number of grades for your election"
                    )}
                    <br />
                    <u>{t("For example:")}</u>{" "}
                    <em>
                      {" "}
                      {t("5 = Excellent, Very good, Good, Fair, Passable")}
                    </em>
                  </HelpButton>
                </Col>
                <Col
                  xs="12"
                  md="9"
                  lg="9"
                  className="offset-xs-0 offset-md-3 offset-lg-3"
                >
                  {grades.map((mention, i) => {
                    return (
                      <span
                        key={i}
                        className="badge badge-light mr-2 mt-2 "
                        style={{
                          backgroundColor: mention.color,
                          color: "#fff",
                          opacity: i < numGrades ? 1 : 0.3,
                        }}
                      >
                        {mention.label}
                      </span>
                    );
                  })}
                </Col>
              </Row>
              <hr className="mt-2 mb-2" />
              <Row>
                <Col xs="12" md="3" lg="3">
                  <span className="label">{t("Participants")}</span>
                </Col>
                <Col xs="12" md="9" lg="9">
                  <ReactMultiEmail
                    placeholder={t("Add here participants' emails")}
                    emails={emails}
                    onChange={setEmails}
                    validateEmail={(email) => {
                      return isEmail(email); // return boolean
                    }}
                    getLabel={(email, index, removeEmail) => {
                      return (
                        <div data-tag key={index}>
                          {email}
                          <span
                            data-tag-handle
                            onClick={() => removeEmail(index)}
                          >
                            ×
                          </span>
                        </div>
                      );
                    }}
                  />
                  <div>
                    <small className="text-muted">
                      {t(
                        "If you list voters' emails, only them will be able to access the election"
                      )}
                    </small>
                  </div>
                </Col>
              </Row>
              <hr className="mt-2 mb-2" />
            </CardBody>
          </Card>
        </Collapse>
        <Row className="justify-content-end mt-2">
          <Col xs="12" md="3">
            {check.ok ? (
              <ConfirmModal
                title={title}
                candidates={candidates}
                isTimeLimited={isTimeLimited}
                start={start}
                finish={finish}
                emails={emails}
                restrictResult={restrictResult}
                grades={grades.slice(0, numGrades)}
                className={"btn btn-success float-right btn-block"}
                tabIndex={candidates.length + 1}
                confirmCallback={handleSubmit}
              />
            ) : (
              <Button
                type="button"
                className="btn btn-dark float-right btn-block"
                onClick={handleSendNotReady}
              >
                <FontAwesomeIcon icon={faCheck} className="mr-2" />
                {t("Confirm")}
              </Button>
            )}
          </Col>
        </Row>
      </form>
    </Container>
  );
};

export default CreateElection;
