"use client";

// React Imports
import { createContext, useContext, useEffect, useState } from "react";
import type { ReactNode } from "react";

// API Imports
import {
  authService,
  type AuthResponse,
  type AuthTokenValue,
  type AuthUser,
  type RegisterRequest,
} from "@/libs/api/services/authService";

export type LoginResult = { user: AuthUser | null };
export type RegisterPayload = RegisterRequest;

interface AuthContextType {
  user: AuthUser | null;
  isLoading: boolean;
  isAuthenticated: boolean;
  login: (identifier: string, password: string) => Promise<LoginResult>;
  register: (payload: RegisterPayload) => Promise<LoginResult>;
  logout: () => void;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export const useAuth = () => {
  const context = useContext(AuthContext);

  if (!context) {
    throw new Error("useAuth must be used within an AuthProvider");
  }

  return context;
};

interface AuthProviderProps {
  children: ReactNode;
}

const STORAGE_KEYS = {
  authUser: "auth_user",
} as const;

const hasAuthToken = (token: AuthTokenValue | null | undefined) => {
  if (!token) return false;

  if (typeof token === "string") {
    return token.trim().length > 0;
  }

  return typeof token.access === "string" && token.access.trim().length > 0;
};

export const AuthProvider = ({ children }: AuthProviderProps) => {
  const [user, setUser] = useState<AuthUser | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const token =
      typeof window !== "undefined" ? localStorage.getItem("auth_token") : null;
    const storedUser =
      typeof window !== "undefined"
        ? localStorage.getItem(STORAGE_KEYS.authUser)
        : null;

    if (token && storedUser) {
      try {
        const userData = JSON.parse(storedUser) as AuthUser;

        setUser(userData);
      } catch (error) {
        console.error("Error parsing stored user data:", error);
        authService.logout();
        localStorage.removeItem(STORAGE_KEYS.authUser);
      }
    }

    setIsLoading(false);
  }, []);

  const normalizeUser = (
    raw: Record<string, unknown> | null | undefined,
  ): AuthUser => {
    if (!raw || typeof raw !== "object") {
      return {
        id: 0,
        username: "",
        email: "",
        first_name: "",
        last_name: "",
        phone_number: "",
      };
    }

    return {
      id: Number(raw.id) || 0,
      username: (raw.username as string) ?? "",
      email: (raw.email as string) ?? "",
      first_name: (raw.first_name as string) ?? (raw.firstName as string) ?? "",
      last_name: (raw.last_name as string) ?? (raw.lastName as string) ?? "",
      phone_number:
        (raw.phone_number as string) ?? (raw.phoneNumber as string) ?? "",
    };
  };

  const persistUser = (userData: AuthUser) => {
    setUser(userData);

    if (typeof window !== "undefined") {
      localStorage.setItem(STORAGE_KEYS.authUser, JSON.stringify(userData));
    }
  };

  const authenticate = (
    response: AuthResponse,
    fallbackMessage: string,
  ): LoginResult => {
    if (!response.data || !hasAuthToken(response.token)) {
      throw new Error(response.msg || fallbackMessage);
    }

    const userData = normalizeUser(
      response.data as unknown as Record<string, unknown>,
    );

    persistUser(userData);

    return { user: userData };
  };

  const login = async (
    identifier: string,
    password: string,
  ): Promise<LoginResult> => {
    const response = await authService.login({ identifier, password });

    if (response.code >= 400) {
      throw new Error(response.msg || "Login failed");
    }

    return authenticate(response, "Login failed");
  };

  const register = async (payload: RegisterPayload): Promise<LoginResult> => {
    const response = await authService.register(payload);

    if (response.code >= 400) {
      throw new Error(response.msg || "Registration failed");
    }

    return authenticate(response, "Registration failed");
  };

  const logout = () => {
    authService.logout();
    setUser(null);

    if (typeof window !== "undefined") {
      localStorage.removeItem(STORAGE_KEYS.authUser);
    }
  };

  const value: AuthContextType = {
    user,
    isLoading,
    isAuthenticated: !!user,
    login,
    register,
    logout,
  };

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
