const api = {
  urlServer:
    process.env.NEXT_PUBLIC_SERVER_URL || "https://demo.mieuxvoter.fr/api/",
  feedbackForm:
    process.env.NEXT_PUBLIC_FEEDBACK_FORM ||
    "https://docs.google.com/forms/d/e/1FAIpQLScuTsYeBXOSJAGSE_AFraFV7T2arEYua7UCM4NRBSCQQfRB6A/viewform",
  routesServer: {
    setElection: "election/",
    getElection: "election/get/:slug/",
    getResults: "election/results/:slug",
    voteElection: "election/vote/",
  },
};

const sendInviteMail = (res) => {
  /**
   * Send an invitation mail using a micro-service with Netlify
   */
  const { id, title, mails, tokens, locale } = res;

  if (!mails || !mails.length) {
    throw new Error("No emails are provided.");
  }

  if (mails.length !== tokens.length) {
    throw new Error("The number of emails differ from the number of tokens");
  }

  const origin =
    typeof window !== "undefined" && window.location.origin
      ? window.location.origin
      : "http://localhost";
  const urlVote = (pid, token) => new URL(`/vote/${pid}/${token}`, origin);
  const urlResult = (pid) => new URL(`/result/${pid}`, origin);

  const recipientVariables = {};
  tokens.forEach((token, index) => {
    recipientVariables[mails[index]] = {
      urlVote: urlVote(id, token),
      urlResult: urlResult(id),
    };
  });

  const req = fetch("/.netlify/functions/send-invite-email/", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      recipientVariables,
      title,
      locale,
    }),
  });

  return req.then((any) => res);
};

const createElection = (
  title,
  candidates,
  {
    /**
     * Create an election from its title, its candidates and a bunch of options
     */
    mails,
    numGrades,
    start,
    finish,
    restrictResult,
    locale,
  },
  successCallback,
  failureCallback
) => {
  const endpoint = new URL(api.routesServer.setElection, api.urlServer);

  console.log(endpoint.href);
  const onInvitationOnly = mails && mails.length > 0;

  fetch(endpoint.href, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      title,
      candidates,
      on_invitation_only: onInvitationOnly,
      num_grades: numGrades,
      elector_emails: mails || [],
      start_at: start,
      finish_at: finish,
      select_language: locale || "en",
      front_url: window.location.origin,
      restrict_results: restrictResult,
      send_mail: false,
    }),
  })
    .then((response) => {
      if (!response.ok) {
        throw Error(response.statusText);
      }
      return response.json();
    })
    .then((res) => {
      if (onInvitationOnly) {
        return sendInviteMail({ locale, mails: mails, ...res });
      }
      return res;
    })
    .then(successCallback)
    .catch(failureCallback || console.log);
};

const getResults = (pid, successCallback, failureCallback) => {
  /**
   * Fetch results from external API
   */

  const endpoint = new URL(
    api.routesServer.getResults.replace(new RegExp(":slug", "g"), pid),
    api.urlServer
  );

  return fetch(endpoint.href)
    .then((response) => {
      if (!response.ok) {
        return Promise.reject(response.text());
      }
      return response.json();
    })
    .then(successCallback || ((res) => res))
    .catch(failureCallback || ((err) => err));
};

const getDetails = (pid, successCallback, failureCallback) => {
  /**
   * Fetch data from external API
   */

  const detailsEndpoint = new URL(
    api.routesServer.getElection.replace(new RegExp(":slug", "g"), pid),
    api.urlServer
  );
  return fetch(detailsEndpoint.href)
    .then((response) => {
      if (!response.ok) {
        return Promise.reject(response.text());
      }
      return response.json();
    })
    .then(successCallback || ((res) => res))
    .catch(failureCallback || ((err) => err))
    .then((res) => res);
};

const castBallot = (judgments, pid, token, callbackSuccess, callbackError) => {
  /**
   * Save a ballot on the remote database
   */

  const endpoint = new URL(api.routesServer.voteElection, api.urlServer);

  const payload = {
    election: pid,
    grades_by_candidate: judgments,
  };
  if (token && token !== "") {
    payload["token"] = token;
  }

  fetch(endpoint.href, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  })
    .then(callbackSuccess || ((res) => res))
    .catch(callbackError || console.log);
};

export const UNKNOWN_ELECTION_ERROR = "E1:";
export const ONGOING_ELECTION_ERROR = "E2:";
export const NO_VOTE_ERROR = "E3:";
export const ELECTION_NOT_STARTED_ERROR = "E4:";
export const ELECTION_FINISHED_ERROR = "E5:";
export const INVITATION_ONLY_ERROR = "E6:";
export const UNKNOWN_TOKEN_ERROR = "E7:";
export const USED_TOKEN_ERROR = "E8:";
export const WRONG_ELECTION_ERROR = "E9:";

export const apiErrors = (error, t) => {
  if (error.includes(UNKNOWN_ELECTION_ERROR)) {
    return t("error.e1");
  }
  if (error.includes(ONGOING_ELECTION_ERROR)) {
    return t("error.e2");
  }
  if (error.includes(NO_VOTE_ERROR)) {
    return t("error.e3");
  }
  if (error.includes(ELECTION_NOT_STARTED_ERROR)) {
    return t("error.e4");
  }
  if (error.includes(ELECTION_FINISHED_ERROR)) {
    return t("error.e5");
  }
  if (error.includes(INVITATION_ONLY_ERROR)) {
    return t("error.e6");
  }
  if (error.includes(USED_TOKEN_ERROR)) {
    return t("error.e7");
  }
  if (error.includes(WRONG_ELECTION_ERROR)) {
    return t("error.e8");
  } else {
    return t("error.catch22");
  }
};

export {
  api,
  getDetails,
  getResults,
  createElection,
  sendInviteMail,
  castBallot,
};
