import { LoadingButton } from "@mui/lab";
import { Box, FormControlLabel, LinearProgress, Switch, TextField, Typography } from "@mui/material";
import { fetch } from "@tauri-apps/plugin-http";
import { useAtom } from "jotai";
import { useState } from "react";
import { useNotification } from "../../../contexts/NotificationContext";
import { serverUrlAtom } from "../../../lib/jotai";
import { HeaderLogo } from "../../Generic/HeaderLogo";

export const SqlInjectionRegister = () => {
  // contexts
  const { openNotification } = useNotification();

  // atoms
  const [serverUrl, setServerUrl] = useAtom(serverUrlAtom);

  // states
  const [emailValueRaw, setEmailValueRaw] = useState<string>("");
  const [errorMsg, setErrorMsg] = useState<string>("");
  const [passwordValueRaw, setPasswordValueRaw] = useState<string>("");
  const [rePasswordValueRaw, setRePasswordValueRaw] = useState<string>("");
  const [passwordStrength, setPasswordStrength] = useState(0);
  const [passwordStrengthColor, setPasswordStrengthColor] = useState<"primary" | "error" | "warning" | "success">(
    "primary",
  );
  const [passwordStrengthInfo, setPasswordStrengthInfo] = useState("Enter a password");
  const [registerLoading, setRegisterLoading] = useState<boolean>(false);
  const [secured, setSecured] = useState<boolean>(false);

  let newPasswordStrengthInfo = "Enter a password";

  const passwordInputEvent = (passwordValueRawInput: string) => {
    setPasswordValueRaw(passwordValueRawInput);

    // call function to update strength meter
    calculatePasswordStrength(passwordValueRawInput);
  };

  const rePasswordInputEvent = (rePasswordValueRawInput: string) => {
    setRePasswordValueRaw(rePasswordValueRawInput);
  };

  const calculatePasswordStrength = (passwordValueRaw: string) => {
    let strengthPoints = 0;

    // logic for calculating password strength
    if (passwordValueRaw.length >= 8 && passwordValueRaw.length <= 128) {
      strengthPoints += 20;
    }
    if (passwordValueRaw.match(/[a-z]/g)) {
      strengthPoints += 20;
    }
    if (passwordValueRaw.match(/[A-Z]/g)) {
      strengthPoints += 20;
    }
    if (passwordValueRaw.match(/[0-9]/g)) {
      strengthPoints += 20;
    }
    if (passwordValueRaw.match(/[^a-zA-Z\d]/g)) {
      strengthPoints += 20;
    }

    // calculate strengthPoints as a percentage
    strengthPoints = Math.min(strengthPoints, 100);

    // logic for changing color of progress bar
    if (strengthPoints === 0) {
      setPasswordStrengthColor("primary");
      newPasswordStrengthInfo = "Enter a password";
    } else if (strengthPoints <= 20) {
      setPasswordStrengthColor("error");
      newPasswordStrengthInfo = "Password strength is weak";
    } else if (strengthPoints <= 40) {
      setPasswordStrengthColor("warning");
      newPasswordStrengthInfo = "Password strength is decent";
    } else if (strengthPoints <= 60) {
      setPasswordStrengthColor("warning");
      newPasswordStrengthInfo = "Password strength is decent";
    } else if (strengthPoints <= 80) {
      setPasswordStrengthColor("success");
      newPasswordStrengthInfo = "Password strength is good";
    } else if (strengthPoints <= 100) {
      setPasswordStrengthColor("success");
      newPasswordStrengthInfo = "Password strength is strong";
    }

    // update state
    setPasswordStrength(strengthPoints);
    setPasswordStrengthInfo(newPasswordStrengthInfo);
  };

  const nextClickEvent = async () => {
    // reset the error messages
    setErrorMsg("");

    // ensure that the server url does not end with a trailing slash
    setServerUrl(serverUrl.replace(/\/$/, ""));

    // construct the request body
    const requestBody = {
      email: emailValueRaw,
      password: passwordValueRaw,
      rePassword: rePasswordValueRaw,
    };

    // start loading indicator
    setRegisterLoading(true);

    // construct endpoint url
    const endpointUrl = serverUrl + (secured ? "/secure-register-sql" : "/unsecure-register-sql");

    try {
      // make request good
      const response = await fetch(endpointUrl, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(requestBody),
      });

      // check if registration was successful
      if (!response.ok) {
        const errorMessage = await response.text();
        console.log("Registration failed:", errorMessage);
        setErrorMsg(errorMessage);
      } else {
        openNotification("Registration successful");
      }
    } catch (e) {
      // log the error and handle failure
      console.log("Request failed", e);
    } finally {
      // stop loading indicator regardless of success/failure
      setRegisterLoading(false);
    }
  };

  return (
    <>
      <Box
        alignItems="center"
        display="flex"
        flexDirection="row"
        sx={{
          mb: 2,
        }}
      >
        <HeaderLogo />
        <Typography
          sx={{
            color: "grey",
          }}
          variant="h6"
        >
          &nbsp;Register
        </Typography>
      </Box>
      <Box
        sx={{
          display: "flex",
          flexDirection: "column",
        }}
      >
        <form
          onSubmit={(e) => {
            e.preventDefault();
            nextClickEvent();
          }}
        >
          <TextField
            error={Boolean(errorMsg)}
            fullWidth
            id="email"
            label="Email"
            onChange={(e: { target: { value: string } }) => setEmailValueRaw(e.target.value)}
            size="small"
            type="text"
            value={emailValueRaw}
            sx={{ mb: 2 }}
            variant="outlined"
          />
          <TextField
            error={Boolean(errorMsg)}
            fullWidth
            id="password"
            label="Password"
            onChange={(e: { target: { value: string } }) => passwordInputEvent(e.target.value)}
            size="small"
            type="password"
            value={passwordValueRaw}
            sx={{ mb: 2 }}
            variant="outlined"
          />
          <TextField
            error={Boolean(errorMsg)}
            fullWidth
            helperText={Boolean(errorMsg) ? errorMsg : ""}
            id="re-password"
            label="Re-enter password"
            onChange={(e: { target: { value: string } }) => rePasswordInputEvent(e.target.value)}
            size="small"
            type="password"
            value={rePasswordValueRaw}
            sx={{ mb: 2 }}
            variant="outlined"
          />
          <LinearProgress
            color={passwordStrengthColor}
            value={passwordStrength}
            variant="determinate"
          />
          <Typography
            sx={{
              color: "lightgrey",
              fontSize: "12px",
              mt: 0.5,
              whiteSpace: "normal",
              overflowWrap: "break-word",
            }}
          >
            {passwordStrengthInfo}
          </Typography>
          <Typography
            component="div"
            sx={{
              color: "lightgrey",
              fontSize: "12px",
              whiteSpace: "normal",
              overflowWrap: "break-word",
            }}
          >
            <ul>
              <li>Between 8 and 128 characters</li>
              <li>At least one uppercase and lowercase letter</li>
              <li>At least one number</li>
              <li>At least one special character</li>
            </ul>
          </Typography>
          <Box
            sx={{
              display: "flex",
              flexDirection: "row",
              justifyContent: "space-between",
            }}
          >
            <FormControlLabel
              control={
                <Switch
                  checked={secured}
                  onChange={(e) => {
                    setSecured(e.target.checked);
                  }}
                />
              }
              label="Use secure endpoint"
            />
            <LoadingButton
              loading={registerLoading}
              type="submit"
              variant="contained"
            >
              Next
            </LoadingButton>
          </Box>
        </form>
      </Box>
    </>
  );
};
