import { jwtDecode, JwtPayload } from "jwt-decode";
import { ReactNode, useEffect, useState } from "react";
import { apiAuth, baseUrl, User } from "./api";
import { useNavigate } from "react-router";
import { Eye, EyeSlash } from "./Icons";
import { useSession } from "./Session";
import { relative } from "path";
import Header from "./Header";

interface PassToken extends JwtPayload {
  username: string;
  name: string;
  team_id: number;
}

enum Mode {
  register = "register",
  set = "set password",
  change = "change password",
}

export const SetPassword = () => {
  const [mode, setMode] = useState<Mode>();
  const [name, setName] = useState("after getting your token.");
  const [username, setUsername] = useState("");
  const [teamID, setTeamID] = useState<number>();
  const [currentPassword, setCurrentPassword] = useState("");
  const [password, setPassword] = useState("");
  const [passwordr, setPasswordr] = useState("");
  const [token, setToken] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);
  const [visible, setVisible] = useState(false);
  const newPlayerTemplate = {
    username: "",
    display_name: "",
    number: "",
    email: "",
  } as User;
  const [player, setPlayer] = useState(newPlayerTemplate);
  const navigate = useNavigate();
  const { user } = useSession();

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (password === passwordr) {
      setLoading(true);
      if (mode === Mode.change) {
        //====CHANGING PASSWORD====
        const resp = await apiAuth(
          "player/change_password",
          { current_password: currentPassword, new_password: password },
          "POST"
        );
        setLoading(false);
        if (resp.detail) setError(resp.detail);
        else {
          setError(resp);
          setTimeout(() => navigate("/"), 2000);
        }
      } else if (mode === Mode.set) {
        //====SETTING PASSWORD====
        const req = new Request(`${baseUrl}api/set_password`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ token: token, password: password }),
        });
        let resp: Response;
        try {
          resp = await fetch(req);
        } catch (e) {
          throw new Error(`request failed: ${e}`);
        }
        setLoading(false);

        if (resp.ok) {
          console.log(resp);
          navigate("/", {
            replace: true,
            state: { username: username, password: password },
          });
        }

        if (!resp.ok) {
          if (resp.status === 401) {
            const { detail } = await resp.json();
            if (detail) setError(detail);
            else setError("unauthorized");
            throw new Error("Unauthorized");
          }
        }
      } else if (mode === Mode.register) {
        //====REGISTER NEW USER====
        const req = new Request(`${baseUrl}api/register`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            ...player,
            team_id: teamID,
            token: token,
            password: password,
          }),
        });
        let resp: Response;
        try {
          resp = await fetch(req);
        } catch (e) {
          throw new Error(`request failed: ${e}`);
        }
        setLoading(false);

        if (resp.ok) {
          console.log(resp);
          navigate("/", {
            replace: true,
            state: { username: player.username, password: password },
          });
        }

        if (!resp.ok) {
          const { detail } = await resp.json();
          if (detail) setError(detail);
          else setError("unauthorized");
          throw new Error("Unauthorized");
        }
      }
    } else setError("passwords are not the same");
  }

  useEffect(() => {
    if (user) {
      setUsername(user.username);
      setName(user.display_name);
      setMode(Mode.change);
    } else {
      const params = new URLSearchParams(window.location.search);
      const token = params.get("token");
      if (token) {
        setToken(token);
        try {
          const payload = jwtDecode<PassToken>(token);
          console.log(payload);
          switch (payload.sub) {
            case "register":
              setMode(Mode.register);
              if (payload.team_id) setTeamID(payload.team_id);
              break;
            case "set password":
              setMode(Mode.set);
              if (payload.username) setUsername(payload.username);
              break;
          }
          if (payload.name) setName(payload.name);
        } catch (InvalidTokenError) {
          setName("Mr. I-have-no-valid Token");
        }
      }
    }
  }, []);

  let header: ReactNode;
  switch (mode) {
    case Mode.change:
      header = <h2>change your password, {name}</h2>;
      break;
    case Mode.set:
      header = (
        <>
          <Header />
          <h2>set your password, {name}</h2>
        </>
      );
      break;
    case Mode.register:
      header = (
        <>
          <Header />
          <h2>
            register as a member of <i>{name}</i>
          </h2>
        </>
      );
  }

  let textInputs: ReactNode;
  switch (mode) {
    case Mode.change:
      textInputs = (
        <div>
          <input
            type={visible ? "text" : "password"}
            id="password"
            name="password"
            placeholder="current password"
            minLength={8}
            value={currentPassword}
            required
            onChange={(evt) => {
              setError("");
              setCurrentPassword(evt.target.value);
            }}
          />
          <hr style={{ margin: "8px" }} />
        </div>
      );
      break;
    case Mode.register:
      textInputs = (
        <div className="new-player-inputs">
          <div>
            <label>name</label>
            <input
              type="text"
              required
              value={player.display_name}
              onChange={(e) => {
                setPlayer({
                  ...player,
                  display_name: e.target.value,
                  username: e.target.value.toLowerCase().replace(/\W/g, ""),
                });
              }}
            />
          </div>
          <div>
            <label>username</label>
            <input
              type="text"
              required
              value={player.username}
              onChange={(e) => {
                setPlayer({ ...player, username: e.target.value });
              }}
            />
          </div>
          <div>
            <label>number (optional)</label>
            <input
              type="text"
              value={player.number || ""}
              onChange={(e) => {
                setPlayer({ ...player, number: e.target.value });
              }}
            />
          </div>
          <div>
            <label>email (optional)</label>
            <input
              type="email"
              value={player.email || ""}
              onChange={(e) => {
                setPlayer({ ...player, email: e.target.value });
              }}
            />
          </div>
          <hr style={{ margin: "8px" }} />
        </div>
      );
      break;
  }

  let passwordInputs = (
    <>
      <div>
        <input
          type={visible ? "text" : "password"}
          id="password"
          name="password"
          placeholder="password"
          minLength={8}
          value={password}
          required
          onChange={(evt) => {
            setError("");
            setPassword(evt.target.value);
          }}
        />
      </div>
      <div>
        <input
          type={visible ? "text" : "password"}
          id="password-repeat"
          name="password-repeat"
          placeholder="repeat password"
          minLength={8}
          value={passwordr}
          required
          onChange={(evt) => {
            setError("");
            setPasswordr(evt.target.value);
          }}
        />
      </div>
    </>
  );

  return mode ? (
    <>
      {header}
      <hr style={{ width: "100%" }} />
      <form onSubmit={handleSubmit}>
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            flexDirection: "column",
          }}
        >
          {textInputs}
          {passwordInputs}
          <div
            style={{
              background: "unset",
              fontSize: "medium",
              cursor: "pointer",
              display: "flex",
              alignItems: "center",
              gap: "8px",
            }}
            onClick={() => setVisible(!visible)}
          >
            {visible ? <Eye /> : <EyeSlash />} show passwords
          </div>
        </div>
        <div>{error && <span style={{ color: "red" }}>{error}</span>}</div>
        <button type="submit" value="login" style={{ fontSize: "small" }}>
          submit
        </button>
        {loading && <span className="loader" />}
      </form>
    </>
  ) : (
    <span className="loader" />
  );
};
