import React from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import MemberList from "./MemberList";
import ProductList from "./ProductList";
import Dashboard from "./Dashboard";
import Purchase from "./purchase/Purchase";
import Topup from "./Topup";
import ShowTransaction from "./ShowTransaction";
import ShowOrder from "./order/ShowOrder";
import CreateOrder from "./order/CreateOrder";
import AuthContext from "./AuthContext";
import SignIn from "./SignIn";
import Head from "./Head";

function Panel(props) {
  return (
    <div>
      <BrowserRouter>
        <Head onLogout={props.onLogout} />
        <Switch>
          <Route path="/members">
            <MemberList />
          </Route>
          <Route path="/products">
            <ProductList />
          </Route>
          <Route path="/transaction/:id">
            <ShowTransaction />
          </Route>
          <Route path="/purchase">
            <Purchase />
          </Route>
          <Route path="/topup">
            <Topup />
          </Route>
          <Route path="/order/create">
            <CreateOrder />
          </Route>
          <Route path="/order/:id" component={ShowOrder} />
          <Route path="/">
            <Dashboard />
          </Route>
        </Switch>
      </BrowserRouter>
    </div>
  );
}

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);
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      num: null,
      role: null,
      token: null,
    };

    this.logout = this.logout.bind(this);
    this.login = this.login.bind(this);
  }

  componentDidMount() {
    const token = localStorage.getItem("token");
    if (token) {
      const num = localStorage.getItem("num");
      const role = localStorage.getItem("role");
      this.setState({ num, role, token });
      if (getClaims(token)["exp"] !== undefined) {
        this.timerID = setInterval(
          () => this.renewToken(),
          60000 // every minute
        );
      }
    }
  }

  componentWillUnmount() {
    if (this.timeID) {
      clearInterval(this.timerID);
    }
  }

  storeState(token, num, role) {
    localStorage.setItem("token", token);
    localStorage.setItem("num", num);
    localStorage.setItem("role", role);
  }

  login(token, member) {
    this.setState({
      num: member.num,
      role: member.role,
      token: token,
    });
    this.storeState(token, member.num, member.role);
    if (getClaims(token)["exp"] !== undefined) {
      this.timerID = setInterval(
        () => this.renewToken(),
        60000 // every minute
      );
    }
  }

  logout() {
    if (this.timeID) {
      clearInterval(this.timerID);
    }
    this.setState({
      num: null,
      role: null,
      token: null,
    });
    this.storeState("", "", "");
  }

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

  renewToken() {
    fetch("/api/token", { headers: { "x-authentication": this.state.token } })
      .then((response) => {
        if (!response.ok) {
          throw new Error(
            response.status.toString() + " " + response.statusText
          );
        }
        return response.json();
      })
      .then((data) => {
        const token = data.token;
        this.setState({ token });
        localStorage.setItem("token", token);
      })
      .catch((error) => {
        console.log("Error renewing token: " + error.message);
      });
  }

  render() {
    let component;
    if (!this.isLoged()) {
      component = <SignIn onLogin={this.login} />;
    } else {
      component = <Panel onLogout={this.logout} />;
    }

    return (
      <AuthContext.Provider value={this.state}>
        {component}
      </AuthContext.Provider>
    );
  }
}

export default App;