import System from "@/models/system";
import showToast from "@/utils/toast";
import React, { useState, useEffect, useRef } from "react";
import debounce from "lodash.debounce";
import paths from "@/utils/paths";
import { useNavigate } from "react-router-dom";
import { AUTH_TIMESTAMP, AUTH_TOKEN, AUTH_USER } from "@/utils/constants";
import { useTranslation } from "react-i18next";
import { USERNAME_MIN_LENGTH, USERNAME_MAX_LENGTH } from "@/utils/username";
import { PW_REGEX } from "@/pages/GeneralSettings/Security";

export default function UserSetup({ setHeader, setForwardBtn, setBackBtn }) {
  const { t } = useTranslation();
  const [selectedOption, setSelectedOption] = useState("");
  const [singleUserPasswordValid, setSingleUserPasswordValid] = useState(false);
  const [multiUserLoginValid, setMultiUserLoginValid] = useState(false);
  const [enablePassword, setEnablePassword] = useState(false);
  const myTeamSubmitRef = useRef(null);
  const justMeSubmitRef = useRef(null);
  const navigate = useNavigate();

  const TITLE = t("onboarding.userSetup.title");
  const DESCRIPTION = t("onboarding.userSetup.description");

  function handleForward() {
    if (selectedOption === "just_me" && enablePassword) {
      justMeSubmitRef.current?.click();
    } else if (selectedOption === "just_me" && !enablePassword) {
      navigate(paths.onboarding.dataHandling());
    } else if (selectedOption === "my_team") {
      myTeamSubmitRef.current?.click();
    }
  }

  function handleBack() {
    navigate(paths.onboarding.llmPreference());
  }

  useEffect(() => {
    let isDisabled = true;
    if (selectedOption === "just_me") {
      isDisabled = !singleUserPasswordValid;
    } else if (selectedOption === "my_team") {
      isDisabled = !multiUserLoginValid;
    }

    setForwardBtn({
      showing: true,
      disabled: isDisabled,
      onClick: handleForward,
    });
  }, [selectedOption, singleUserPasswordValid, multiUserLoginValid]);

  useEffect(() => {
    setHeader({ title: TITLE, description: DESCRIPTION });
    setBackBtn({ showing: true, disabled: false, onClick: handleBack });
  }, []);

  return (
    <div className="w-full flex items-center justify-center flex-col gap-y-6">
      <div className="flex flex-col border rounded-lg border-white/20 light:border-theme-sidebar-border p-8 items-center gap-y-4 w-full max-w-[600px]">
        <div className=" text-white text-sm font-semibold md:-ml-44">
          {t("onboarding.userSetup.howManyUsers")}
        </div>
        <div className="flex flex-col md:flex-row gap-6 w-full justify-center">
          <button
            onClick={() => setSelectedOption("just_me")}
            className={`${
              selectedOption === "just_me"
                ? "text-sky-400 border-sky-400/70"
                : "text-theme-text-primary border-theme-sidebar-border"
            } min-w-[230px] h-11 p-4 rounded-[10px] border-2  justify-center items-center gap-[100px] inline-flex hover:border-sky-400/70 hover:text-sky-400 transition-all duration-300`}
          >
            <div className="text-center text-sm font-bold">
              {t("onboarding.userSetup.justMe")}
            </div>
          </button>
          <button
            onClick={() => setSelectedOption("my_team")}
            className={`${
              selectedOption === "my_team"
                ? "text-sky-400 border-sky-400/70"
                : "text-theme-text-primary border-theme-sidebar-border"
            } min-w-[230px] h-11 p-4 rounded-[10px] border-2  justify-center items-center gap-[100px] inline-flex hover:border-sky-400/70 hover:text-sky-400 transition-all duration-300`}
          >
            <div className="text-center text-sm font-bold">
              {t("onboarding.userSetup.myTeam")}
            </div>
          </button>
        </div>
      </div>
      {selectedOption === "just_me" && (
        <JustMe
          setSingleUserPasswordValid={setSingleUserPasswordValid}
          enablePassword={enablePassword}
          setEnablePassword={setEnablePassword}
          justMeSubmitRef={justMeSubmitRef}
          navigate={navigate}
        />
      )}
      {selectedOption === "my_team" && (
        <MyTeam
          setMultiUserLoginValid={setMultiUserLoginValid}
          myTeamSubmitRef={myTeamSubmitRef}
          navigate={navigate}
        />
      )}
    </div>
  );
}

const JustMe = ({
  setSingleUserPasswordValid,
  enablePassword,
  setEnablePassword,
  justMeSubmitRef,
  navigate,
}) => {
  const { t } = useTranslation();
  const [itemSelected, setItemSelected] = useState(false);
  const [password, setPassword] = useState("");
  const handleSubmit = async (e) => {
    e.preventDefault();
    const form = e.target;
    const formData = new FormData(form);

    if (!PW_REGEX.test(formData.get("password"))) {
      showToast(
        `Your password has restricted characters in it. Allowed symbols are _,-,!,@,$,%,^,&,*,(,),;`,
        "error"
      );
      return;
    }

    const { error } = await System.updateSystemPassword({
      usePassword: true,
      newPassword: formData.get("password"),
    });

    if (error) {
      showToast(`Failed to set password: ${error}`, "error");
      return;
    }

    // Auto-request token with password that was just set so they
    // are not redirected to login after completion.
    const { token } = await System.requestToken({
      password: formData.get("password"),
    });
    window.localStorage.removeItem(AUTH_USER);
    window.localStorage.removeItem(AUTH_TIMESTAMP);
    window.localStorage.setItem(AUTH_TOKEN, token);

    navigate(paths.onboarding.dataHandling());
  };

  const setNewPassword = (e) => setPassword(e.target.value);
  const handlePasswordChange = debounce(setNewPassword, 500);

  function handleYes() {
    setItemSelected(true);
    setEnablePassword(true);
  }

  function handleNo() {
    setItemSelected(true);
    setEnablePassword(false);
  }

  useEffect(() => {
    if (enablePassword && itemSelected && password.length >= 8) {
      setSingleUserPasswordValid(true);
    } else if (!enablePassword && itemSelected) {
      setSingleUserPasswordValid(true);
    } else {
      setSingleUserPasswordValid(false);
    }
  });
  return (
    <div className="w-full flex items-center justify-center flex-col gap-y-6">
      <div className="flex flex-col border rounded-lg border-white/20 light:border-theme-sidebar-border p-8 items-center gap-y-4 w-full max-w-[600px]">
        <div className=" text-white text-sm font-semibold md:-ml-56">
          {t("onboarding.userSetup.setPassword")}
        </div>
        <div className="flex flex-col md:flex-row gap-6 w-full justify-center">
          <button
            onClick={handleYes}
            className={`${
              enablePassword && itemSelected
                ? "text-sky-400 border-sky-400/70"
                : "text-theme-text-primary border-theme-sidebar-border"
            } min-w-[230px] h-11 p-4 rounded-[10px] border-2  justify-center items-center gap-[100px] inline-flex hover:border-sky-400/70 hover:text-sky-400 transition-all duration-300`}
          >
            <div className="text-center text-sm font-bold">
              {t("common.yes")}
            </div>
          </button>
          <button
            onClick={handleNo}
            className={`${
              !enablePassword && itemSelected
                ? "text-sky-400 border-sky-400/70"
                : "text-theme-text-primary border-theme-sidebar-border"
            } min-w-[230px] h-11 p-4 rounded-[10px] border-2  justify-center items-center gap-[100px] inline-flex hover:border-sky-400/70 hover:text-sky-400 transition-all duration-300`}
          >
            <div className="text-center text-sm font-bold">
              {t("common.no")}
            </div>
          </button>
        </div>
        {enablePassword && (
          <form className="w-full mt-4" onSubmit={handleSubmit}>
            <label
              htmlFor="name"
              className="block mb-3 text-sm font-medium text-white"
            >
              {t("onboarding.userSetup.instancePassword")}
            </label>
            <input
              name="password"
              type="password"
              className="border-none bg-theme-settings-input-bg text-white text-sm rounded-lg block w-full p-2.5 focus:outline-primary-button active:outline-primary-button outline-none placeholder:text-theme-text-secondary"
              placeholder="Your admin password"
              minLength={6}
              required={true}
              autoComplete="off"
              onChange={handlePasswordChange}
            />
            <div className="mt-4 text-white text-opacity-80 text-xs font-base -mb-2">
              {t("onboarding.userSetup.passwordReq")}
              <br />
              <i>{t("onboarding.userSetup.passwordWarn")}</i>{" "}
            </div>
            <button
              type="submit"
              ref={justMeSubmitRef}
              hidden
              aria-hidden="true"
            ></button>
          </form>
        )}
      </div>
    </div>
  );
};

const MyTeam = ({ setMultiUserLoginValid, myTeamSubmitRef, navigate }) => {
  const { t } = useTranslation();
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    const form = e.target;
    const formData = new FormData(form);
    const data = {
      username: formData.get("username"),
      password: formData.get("password"),
    };
    const { success, error } = await System.setupMultiUser(data);
    if (!success) {
      showToast(`Error: ${error}`, "error");
      return;
    }

    navigate(paths.onboarding.dataHandling());
    // Auto-request token with credentials that was just set so they
    // are not redirected to login after completion.
    const { user, token } = await System.requestToken(data);
    window.localStorage.setItem(AUTH_USER, JSON.stringify(user));
    window.localStorage.setItem(AUTH_TOKEN, token);
    window.localStorage.removeItem(AUTH_TIMESTAMP);
  };

  const setNewUsername = (e) => setUsername(e.target.value);
  const setNewPassword = (e) => setPassword(e.target.value);
  const handleUsernameChange = debounce(setNewUsername, 500);
  const handlePasswordChange = debounce(setNewPassword, 500);

  useEffect(() => {
    // Enable button if there's any input, allowing users to attempt submission
    // Validation errors will be shown via toast in handleSubmit
    if (username.trim().length > 0 && password.length > 0) {
      setMultiUserLoginValid(true);
    } else {
      setMultiUserLoginValid(false);
    }
  }, [username, password]);
  return (
    <div className="w-full flex items-center justify-center border max-w-[600px] rounded-lg border-white/20 light:border-theme-sidebar-border">
      <form onSubmit={handleSubmit}>
        <div className="flex flex-col w-full md:px-8 px-2 py-4">
          <div className="space-y-6 flex h-full w-full">
            <div className="w-full flex flex-col gap-y-4">
              <div>
                <label
                  htmlFor="name"
                  className="block mb-3 text-sm font-medium text-white"
                >
                  {t("onboarding.userSetup.adminUsername")}
                </label>
                <input
                  name="username"
                  type="text"
                  className="border-none bg-theme-settings-input-bg text-white text-sm rounded-lg block w-full p-2.5 focus:outline-primary-button active:outline-primary-button placeholder:text-theme-text-secondary outline-none"
                  placeholder="Your admin username"
                  minLength={USERNAME_MIN_LENGTH}
                  maxLength={USERNAME_MAX_LENGTH}
                  required={true}
                  autoComplete="off"
                  onChange={handleUsernameChange}
                />
              </div>
              <p className=" text-white text-opacity-80 text-xs font-base">
                {t("common.username_requirements")}
              </p>
              <div className="mt-4">
                <label
                  htmlFor="name"
                  className="block mb-3 text-sm font-medium text-white"
                >
                  {t("onboarding.userSetup.adminPassword")}
                </label>
                <input
                  name="password"
                  type="password"
                  className="border-none bg-theme-settings-input-bg text-white text-sm rounded-lg block w-full p-2.5 focus:outline-primary-button active:outline-primary-button placeholder:text-theme-text-secondary outline-none"
                  placeholder="Your admin password"
                  minLength={8}
                  required={true}
                  autoComplete="off"
                  onChange={handlePasswordChange}
                />
              </div>
              <p className=" text-white text-opacity-80 text-xs font-base">
                {t("onboarding.userSetup.adminPasswordReq")}
              </p>
            </div>
          </div>
        </div>
        <div className="flex w-full justify-between items-center px-6 py-4 space-x-6 border-t rounded-b border-theme-sidebar-border">
          <div className="text-theme-text-secondary text-opacity-80 text-xs font-base">
            {t("onboarding.userSetup.teamHint")}
          </div>
        </div>
        <button
          type="submit"
          ref={myTeamSubmitRef}
          hidden
          aria-hidden="true"
        ></button>
      </form>
    </div>
  );
};
