import React, {
  createContext,
  useEffect,
  useState,
  useContext,
  useMemo,
  useCallback
} from "react";
import history from "browser-history";
import pathToRegexp from "path-to-regexp";

const RouterContext = createContext();

const Router = ({ children }) => {
  const [url, setUrl] = useState(window.location.pathname);

  useEffect(() => {
    history((e, url) => setUrl(url));
  }, []);

  const go = url => {
    setUrl(url);
    history(url);
  };

  const testUrl = useCallback(
    (path, exact) => {
      const re = pathToRegexp(exact ? path : path + "(.*)", [], {
        sensitive: false
      });
      return {
        doesMatch: re.test(url),
        parts: re.exec(url)
      };
    },
    [url]
  );

  const contextValue = {
    url,
    testUrl,
    go
  };

  return (
    <RouterContext.Provider value={contextValue}>
      {children}
    </RouterContext.Provider>
  );
};

const Route = ({
  path,
  exact,
  component: Component,
  children,
  ...componentProps
}) => {
  const { testUrl } = useContext(RouterContext);
  const r = useMemo(() => testUrl(path, exact), [testUrl, path, exact]);

  if (r.doesMatch) {
    return Component ? (
      <Component {...componentProps} parts={r.parts} />
    ) : (
      children
    );
  }
  return null;
};

const Link = ({ path, children }) => {
  const { go } = useContext(RouterContext);

  const onClick = () => {
    go(path);
  };

  return <a onClick={onClick}>{children}</a>;
};

const Redirect = ({ from, to }) => {
  const { go, testUrl } = useContext(RouterContext);
  const r = useMemo(() => testUrl(from, true), [testUrl, from]);

  if (r.doesMatch) {
    go(to);
  }
  return null;
};

export { RouterContext, Router, Route, Redirect, Link };
