import { useState } from "react";
import {
  Box,
  Button,
  TextField,
  useMediaQuery,
  Typography,
  useTheme,
  CircularProgress,
} from "@mui/material";
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
import { Formik } from "formik";
import * as yup from "yup";
import { useNavigate } from "react-router-dom";
import { useDispatch } from "react-redux";
import { setLogin } from "@/state";
import Dropzone from "react-dropzone";
import FlexBetween from "@/components/FlexBetween";
import { apiFetch } from "../../state/api";
// import { setToken } from "../../state/token";

const registerSchema = yup.object().shape({
  firstName: yup.string().required("Pflichtfeld"),
  lastName: yup.string().required("Pflichtfeld"),
  email: yup.string().email("invalid email").required("Pflichtfeld"),
  password: yup.string().required("Pflichtfeld"),
  occupation: yup.string().required("Pflichtfeld"),
  location: yup.string().required("Pflichtfeld"),
  picture: yup.mixed().required("Pflichtfeld"),
});

const loginSchema = yup.object().shape({
  email: yup.string().email("invalid email").required("required"),
  password: yup.string().required("required"),
});

const initialValuesRegister = {
  firstName: "",
  lastName: "",
  email: "",
  password: "",
  location: "",
  occupation: "",
  picture: "",
};

const initialValuesLogin = {
  email: "",
  password: "",
};

const Form = () => {
  const [pageType, setPageType] = useState("login");
  const [isLoading, setIsLoading] = useState(false);
  const { palette } = useTheme();
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const isNonMobile = useMediaQuery("(min-width:600px)");
  const isLogin = pageType === "login";
  const isRegister = pageType === "register";
  const [error, setError] = useState("");

  const register = async (values, onSubmitProps) => {
    try {
      setIsLoading(true);
      setError("");
      // this allows us to send form info with image
      const formData = new FormData();
      for (let value in values) {
        formData.append(value, values[value]);
      }

      if (values.picture && values.picture.name) {
        formData.append("picturePath", values.picture.name);
      }

      // apiFetch but without credentials
      const savedUserResponse = await apiFetch(`${import.meta.env.VITE_BASE_URL}/auth/register`, {
        method: "POST",
        body: formData,
      });
      const savedUser = await savedUserResponse.json();

      if (savedUserResponse.status === 201) {
        setPageType("login");
        onSubmitProps.resetForm();
      } else {
        setError(savedUser.message || "Registration failed, check email.");
      }
    } catch (err) {
      console.error("Register Error:", err);
      setError(
        "Überprüfe das alle Felder ausgefüllt sind, dass die E-Mail noch nicht benutzt ist und das Bild muss kleiner als 15 MB sein.",
      );
    } finally {
      setIsLoading(false);
    }
  };

  const login = async (values, onSubmitProps) => {
    try {
      setIsLoading(true);
      setError("");
      const loggedInResponse = await apiFetch(`${import.meta.env.VITE_BASE_URL}/auth/login`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(values),
      });

      let loggedIn = null;
      try {
        loggedIn = await loggedInResponse.json();
      } catch (e) {
        setError("Invalid server response");
        return;
      }

      if (loggedInResponse.status !== 200) {
        // switch (err.status) {
        switch (loggedInResponse.status) {
          case 400:
            setError(loggedIn.message || "Invalid input. Please check your data.");
            break;
          case 401:
            setError(loggedIn.message || "Invalid credentials.");
            break;
          case 403:
            setError(loggedIn.message || "You are not allowed to perform this action.");
            break;
          case 404:
            setError(loggedIn.message || "Resource not found.");
            break;
          case 500:
            setError(loggedIn.message || "Server error. Try again later.");
            break;
          default:
            setError(loggedIn.message || "Login failed. Invalid credentials.");
        }

        return;
      }

      if (loggedIn) {
        dispatch(
          setLogin({
            user: loggedIn.user,
            token: loggedIn.token,
          }),
        );
        // onSubmitProps.resetForm();
        navigate("/home");
      }
    } catch (err) {
      setError("Login failed. Please check your connection.");
      console.error(err); // would be removed in real production build
    } finally {
      setIsLoading(false);
    }
  };

  const handleFormSubmit = async (values, onSubmitProps) => {
    if (isLogin) await login(values, onSubmitProps);
    if (isRegister) await register(values, onSubmitProps);
  };

  return (
    <Formik
      onSubmit={handleFormSubmit}
      initialValues={isLogin ? initialValuesLogin : initialValuesRegister}
      validationSchema={isLogin ? loginSchema : registerSchema}
    >
      {({
        values,
        errors,
        touched,
        handleBlur,
        handleChange,
        handleSubmit,
        setFieldValue,
        resetForm,
      }) => (
        <form onSubmit={handleSubmit}>
          <Box
            display="grid"
            gap="30px"
            gridTemplateColumns="repeat(4, minmax(0, 1fr))"
            sx={{
              "& > div": { gridColumn: isNonMobile ? undefined : "span 4" },
            }}
          >
            {isRegister && (
              <>
                <TextField
                  label="Vorname"
                  onBlur={handleBlur}
                  onChange={handleChange}
                  value={values.firstName || ""}
                  name="firstName"
                  error={Boolean(touched.firstName) && Boolean(errors.firstName)}
                  helperText={touched.firstName && errors.firstName}
                  sx={{ gridColumn: "span 2" }}
                />
                <TextField
                  label="Nachname"
                  onBlur={handleBlur}
                  onChange={handleChange}
                  value={values.lastName || ""}
                  name="lastName"
                  error={Boolean(touched.lastName) && Boolean(errors.lastName)}
                  helperText={touched.lastName && errors.lastName}
                  sx={{ gridColumn: "span 2" }}
                />
                <TextField
                  label="Studiengang"
                  onBlur={handleBlur}
                  onChange={handleChange}
                  value={values.occupation || ""}
                  name="occupation"
                  error={Boolean(touched.occupation) && Boolean(errors.occupation)}
                  helperText={touched.occupation && errors.occupation}
                  sx={{ gridColumn: "span 4" }}
                />
                <TextField
                  label="Standort"
                  onBlur={handleBlur}
                  onChange={handleChange}
                  value={values.location || ""}
                  name="location"
                  error={Boolean(touched.location) && Boolean(errors.location)}
                  helperText={touched.location && errors.location}
                  sx={{ gridColumn: "span 4" }}
                />
                <Box
                  gridColumn="span 4"
                  border={`1px solid ${palette.neutral.medium}`}
                  borderRadius="5px"
                  p="1rem"
                >
                  <Dropzone
                    acceptedFiles=".jpg,.jpeg,.png"
                    accept={{
                      "image/jpeg": [".jpeg", ".jpg"],
                      "image/png": [".png"],
                    }}
                    maxSize={15 * 1024 * 1024} // maximum size 15 MB, see comment in server
                    multiple={false}
                    onDrop={(acceptedFiles) => setFieldValue("picture", acceptedFiles[0])}
                  >
                    {({ getRootProps, getInputProps }) => (
                      <Box
                        {...getRootProps()}
                        border={`2px dashed ${palette.primary.main}`}
                        p="1rem"
                        sx={{ "&:hover": { cursor: "pointer" } }}
                      >
                        <input {...getInputProps()} />
                        {!values.picture ? (
                          <p>Add Picture Here *</p>
                        ) : (
                          <FlexBetween>
                            <Typography>{values.picture.name}</Typography>
                            <EditOutlinedIcon />
                          </FlexBetween>
                        )}
                      </Box>
                    )}
                  </Dropzone>
                  {Boolean(touched.picture) && Boolean(errors.picture) && (
                    <Typography color="error" sx={{ mt: "0.5rem", fontSize: "0.75rem" }}>
                      {errors.picture}
                    </Typography>
                  )}
                </Box>
              </>
            )}

            <TextField
              label="E-Mail"
              onBlur={handleBlur}
              onChange={handleChange}
              value={values.email || ""}
              name="email"
              error={Boolean(touched.email) && Boolean(errors.email)}
              helperText={touched.email && errors.email}
              sx={{ gridColumn: "span 4" }}
            />
            <TextField
              label="Passwort"
              type="password"
              onBlur={handleBlur}
              onChange={handleChange}
              value={values.password || ""}
              name="password"
              error={Boolean(touched.password) && Boolean(errors.password)}
              helperText={touched.password && errors.password}
              sx={{ gridColumn: "span 4" }}
            />
          </Box>

          {error && (
            <Typography color="error" sx={{ mt: "1rem" }}>
              {error}
            </Typography>
          )}

          {/* BUTTONS */}
          <Box>
            <Button
              fullWidth
              type="submit"
              disabled={isLoading}
              sx={{
                m: "2rem 0",
                p: "1rem",
                backgroundColor: palette.primary.main,
                color: palette.background.alt,
                "&:hover": { color: palette.primary.dark },
              }}
            >
              {isLoading ? (
                <CircularProgress size={24} sx={{ color: palette.background.alt }} />
              ) : isLogin ? (
                "LOGIN"
              ) : (
                "REGISTRIEREN"
              )}
            </Button>
            <Typography
              onClick={() => {
                setPageType(isLogin ? "register" : "login");
                resetForm();
                setError("");
              }}
              sx={{
                textDecoration: "underline",
                color: palette.primary.main,
                "&:hover": {
                  cursor: "pointer",
                  color: palette.primary.light,
                },
              }}
            >
              {isLogin
                ? "Noch keinen Benutzer? Hier registrieren."
                : "Bereits registriert? Hier ist das Login."}
            </Typography>
          </Box>
        </form>
      )}
    </Formik>
  );
};

export default Form;
