import React, { useEffect, useState } from "react";
import { Preferences } from "@capacitor/preferences";
import Panel from "./Panel";
import AuthContext from "./AuthContext";
import { ResponseError } from "./errors";
import { url } from "./util";

function useStorageItem(key, fromString) {
  const [storedValue, setStoredValue] = useState();

  useEffect(() => {
    async function loadValue() {
      try {
        const result = await Preferences.get({ key });
        if (result.value != null) {
          const value = fromString ? fromString(result.value) : result.value;
          setStoredValue(value);
        } else {
          setStoredValue(undefined);
        }
      } catch (e) {
        return undefined;
      }
    }
    loadValue();
  }, [setStoredValue, key, fromString]);

  const setValue = async (value) => {
    try {
      setStoredValue(value);
      await Preferences.set({
        key,
        value,
      });
    } catch (e) {
      console.error(e);
    }
  };

  return [storedValue, setValue];
}

function App() {
  const [num, setNum] = useStorageItem("num", Number);
  const [role, setRole] = useStorageItem("role");
  const [token, setToken] = useStorageItem("token");
  const [disabled, setDisabled] = useStorageItem(
    "disabled",
    (value) => value === "true"
  );

  useEffect(() => {
    const setTokenData = (data) => {
      setToken(data.token);
      setRole(data.role);
      setDisabled(data.disabled);
    };

    const timerID = window.setInterval(
      () => renewToken(token, setTokenData),
      60000 // every minute
    );
    return () => window.clearInterval(timerID);
  }, [token, setToken, setRole, setDisabled]);

  const login = (newToken, member) => {
    setNum(member.num);
    setRole(member.role);
    setDisabled(member.disabled);
    setToken(newToken);
  };

  const logout = () => {
    setNum(null);
    setRole(null);
    setDisabled(null);
    setToken(null);
    Preferences.clear();
  };

  const value = { num, role, disabled, token };
  return (
    <AuthContext.Provider value={value}>
      <Panel onLogin={login} onLogout={logout} isLogged={isLoggedIn(token)} />
    </AuthContext.Provider>
  );
}

function getClaims(token) {
  const base64Url = token.split(".")[1];
  const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
  const jsonPayload = decodeURIComponent(
    atob(base64)
      .split("")
      .map(function (c) {
        return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
      })
      .join("")
  );

  return JSON.parse(jsonPayload);
}

function renewToken(oldToken, setTokenData) {
  if (!oldToken) {
    return;
  }

  fetch(url("/api/token"), {
    headers: { "x-authentication": oldToken },
  })
    .then((response) => {
      if (!response.ok) {
        throw new ResponseError(response);
      }
      return response.json();
    })
    .then(setTokenData)
    .catch((error) => {
      if (error instanceof ResponseError && error.response.status === 401) {
        setTokenData({ token: "", role: "" });
      } else {
        console.log("Error renewing token: " + error.message);
      }
    });
}

function isLoggedIn(token) {
  if (!token) {
    return false;
  }
  const claims = getClaims(token);
  if (claims["exp"] === undefined) {
    return true;
  }
  return claims["exp"] > Date.now() / 1000;
}

export default App;