"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import styles from "@/components/administrator/LoginForm/loginform.module.css";

import { IoCloseOutline } from "react-icons/io5";
import Input from "@/components/administrator/form/Input/input";
import Loader from "../../web/Loader/loader";
import { useSearchParams } from "next/navigation";
import { useDispatch } from "react-redux";
import { setNotification } from "@/utils/store/features/ui/notification.slice";
import { login } from "@/services/auth";
// import { description } from "@/config/default";
import axios from "axios";
import useLogin from "@/hooks/useLogin";
import { LiaLockSolid, LiaUserTieSolid } from "react-icons/lia";

const LoginForm = ({ description }) => {
  const dispatch = useDispatch();
  const form = useRef({});
  const [notif, setNotif] = useState({
    status: false,
    message: "Error",
    type: "error",
  });
  const [userDetails, setUserDetails] = useState({});

  const buttonDisabled = useMemo(() => {
    return ["username", "password"].some((key) => !userDetails[key]);
  }, [userDetails]);
  const [error, setError] = useState({});
  const [isAllowedGeoLocation, setIsAllowedGeoLocation] = useState(true);
  const [isLoading, setIsLoading] = useState(false);

  const { requestGeoLocation } = useLogin();

  const searchParams = useSearchParams();
  const redirectUrl = searchParams.get("redirect") || null;
  const reason = searchParams.get("reason") || null;

  const getCityFromCoords = useCallback(async (lat, lon) => {
    const res = await axios.get(
      `https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lon}`
    );

    return res.data;
  }, []);

  useEffect(() => {
    if (!form.current.username) return;

    form.current.username.focus();
  }, [form]);

  useEffect(() => {
    if (!reason && !redirectUrl) return;

    dispatch(
      setNotification({
        status: true,
        message:
          reason === "unauthorized"
            ? "You are logged out! Please login again 🤣"
            : "Unexpected Error",
        type: "error",
      })
    );
  }, [redirectUrl, reason, dispatch]);

  const handleGeolocation = useCallback(
    (detail) => {
      if (!navigator.geolocation) {
        // Browser does not support Geolocation
        setIsAllowedGeoLocation(true);
        return detail;
      }

      return new Promise((resolve, reject) => {
        let detailData = detail;
        if ("geolocation" in navigator) {
          navigator.geolocation.getCurrentPosition(
            async (position) => {
              detailData.latitude = position.coords.latitude;
              detailData.longitude = position.coords.longitude;

              const response = await getCityFromCoords(
                detailData.latitude,
                detailData.longitude
              );

              if (response) {
                detailData = {
                  ...detailData,
                  display_name: response.display_name,
                  village: response.address.village,
                  municipality: response.address.municipality,
                  city: response.address.county,
                  region: response.address.state,
                };
              }

              setIsAllowedGeoLocation(true);
              resolve(detailData);
            },
            (error) => {
              setIsAllowedGeoLocation(false);
              resolve(null);
            },
            { enableHighAccuracy: true }
          );
          return;
        }
      });
    },
    [getCityFromCoords]
  );

  useEffect(() => {
    if (isAllowedGeoLocation) return;

    requestGeoLocation({
      action: async () => {
        const result = await handleGeolocation(userDetails?.detail);
        return result;
      },
      callback: (data) => {
        setUserDetails((prev) => ({ ...prev, detail: data }));
      },
    });
  }, [
    isAllowedGeoLocation,
    requestGeoLocation,
    handleGeolocation,
    userDetails,
  ]);

  useEffect(() => {
    const getDetail = async () => {
      try {
        const response = await axios.get("https://ipapi.co/json/");
        let detailData = {
          ip: response.data.ip,
          city: response.data.city,
          region: response.data.region,
          country: response.data.country_name,
          timezone: response.data.timezone,
          org: response.data.org,
        };

        const geolocation = await handleGeolocation(detailData);
        if (geolocation) {
          setUserDetails((prev) => ({ ...prev, detail: geolocation }));
          return;
        }

        setUserDetails((prev) => ({ ...prev, detail: detailData }));
      } catch (error) {
        console.log({ error });
        setUserDetails((prev) => ({ ...prev, detail: { error: true } }));
      }
    };

    getDetail();
  }, [getCityFromCoords, handleGeolocation]);

  const onSubmit = useCallback(
    async (e) => {
      try {
        e.preventDefault();
        // state section
        setError({});
        setNotif((prev) => ({ ...prev, status: false }));
        setIsLoading(true);

        const data = new FormData(e.target);
        data.append("detail", JSON.stringify(userDetails?.detail || {}));
        // login section
        const result = await login(data);

        console.log({ result });

        if (!result.status) {
          // on production build, client side can't access the error message from server action
          // so we have to manually check the error message
          const errorMessage = {
            username:
              "Username not found, please try again with another username",
            password:
              "Password is incorrect, please type in the correct password",
          };

          if (["username", "password"].includes(result.message)) {
            setError({
              message: errorMessage[result.message],
              error: result.message,
            });
            form.current?.[result.message].focus();
          }

          setNotif({
            status: true,
            message: (() => {
              if (["username", "password"].includes(result.message))
                return "Credential is incorrect, please try again with another credential.";

              if (result.message === "disabled")
                return "Your account is disabled, please contact your administrator.";

              return "Unexpected Error";
            })(),
            type: "error",
          });

          return;
        }

        setNotif({
          status: true,
          message: "Login Success, redirecting...",
          type: "success",
        });

        window.location.href = redirectUrl || "/dashboard";
      } catch (error) {
      } finally {
        setIsLoading(false);
      }
    },
    [redirectUrl, form, userDetails]
  );

  return (
    <div className={styles.container}>
      {/* notif scope */}
      {notif.status && (
        <div className={`${styles.notification} ${styles[notif.type]}`}>
          <p className={styles.notif_message}></p>
          {notif.message}
          <button
            onClick={() => setNotif((prev) => ({ ...prev, status: false }))}>
            <IoCloseOutline />
          </button>
        </div>
      )}

      {/* Form scope */}
      <div className={styles.form_login}>
        <div className={styles.form_header}>
          <h1>Welcome Back!</h1>
          <p className={styles.description}>
            <span>{description.title} </span>— Web Admin
          </p>
          <p>Login to your account. Enter your details below!</p>
        </div>
        <form
          className={styles.form}
          onSubmit={onSubmit}>
          <Input
            label="Username"
            name="username"
            icon={<LiaUserTieSolid />}
            ref={(input) => (form.current.username = input)}
            error={{
              status: error.error === "username",
              message: error.message,
            }}
            type="text"
            onInput={(e) =>
              setUserDetails((prev) => ({ ...prev, username: e.target.value }))
            }
          />
          <Input
            label="Password"
            name="password"
            icon={<LiaLockSolid />}
            ref={(input) => (form.current.password = input)}
            type="password"
            error={{
              status: error.error === "password",
              message: error.message,
            }}
            onInput={(e) =>
              setUserDetails((prev) => ({ ...prev, password: e.target.value }))
            }
          />
          <div className={styles.form_footer}>
            {isLoading && (
              <Loader
                width={20}
                color="#4085b3"
              />
            )}
            <button
              type="submit"
              disabled={buttonDisabled || isLoading}>
              Login
            </button>
          </div>
        </form>
      </div>
    </div>
  );
};

export default LoginForm;
