const API_ROOT = "https://api.realworld.io/api";

const encode = encodeURIComponent;

export default function createAgent([state, actions]) {
  async function send(method, url, data, resKey) {
    const headers = {},
      opts = { method, headers };

    if (data !== undefined) {
      headers["Content-Type"] = "application/json";
      opts.body = JSON.stringify(data);
    }

    if (state.token) headers["Authorization"] = `Token ${state.token}`;

    try {
      const response = await fetch(API_ROOT + url, opts);
      const json = await response.json();
      return resKey ? json[resKey] : json;
    } catch (err) {
      if (err && err.response && err.response.status === 401) {
        actions.logout();
      }
      return err;
    }
  }

  const Auth = {
    current: () => send("get", "/user", undefined, "user"),
    login: (email, password) => send("post", "/users/login", { user: { email, password } }),
    register: (username, email, password) =>
      send("post", "/users", { user: { username, email, password } }),
    save: user => send("put", "/user", { user })
  };

  const Tags = {
    getAll: () => send("get", "/tags", undefined, "tags")
  };

  const limit = (count, p) => `limit=${count}&offset=${p ? p * count : 0}`;
  const omitSlug = article => Object.assign({}, article, { slug: undefined });

  const Articles = {
    all: (page, lim = 10) => send("get", `/articles?${limit(lim, page)}`),
    byAuthor: (author, page) => send("get", `/articles?author=${encode(author)}&${limit(5, page)}`),
    byTag: (tag, page, lim = 10) => send("get", `/articles?tag=${encode(tag)}&${limit(lim, page)}`),
    del: slug => send("delete", `/articles/${slug}`),
    favorite: slug => send("post", `/articles/${slug}/favorite`),
    favoritedBy: (author, page) =>
      send("get", `/articles?favorited=${encode(author)}&${limit(5, page)}`),
    feed: () => send("get", "/articles/feed?limit=10&offset=0"),
    get: slug => send("get", `/articles/${slug}`, undefined, "article"),
    unfavorite: slug => send("delete", `/articles/${slug}/favorite`),
    update: article => send("put", `/articles/${article.slug}`, { article: omitSlug(article) }),
    create: article => send("post", "/articles", { article })
  };

  const Comments = {
    create: (slug, comment) => send("post", `/articles/${slug}/comments`, { comment }),
    delete: (slug, commentId) => send("delete", `/articles/${slug}/comments/${commentId}`),
    forArticle: slug => send("get", `/articles/${slug}/comments`, undefined, "comments")
  };

  const Profile = {
    follow: username => send("post", `/profiles/${username}/follow`),
    get: username => send("get", `/profiles/${username}`, undefined, "profile"),
    unfollow: username => send("delete", `/profiles/${username}/follow`)
  };

  return {
    Articles,
    Auth,
    Comments,
    Profile,
    Tags
  };
}