"use client";

import { createContext, useContext, useState, useEffect, useCallback } from "react";

const AuthContext = createContext(null);

const TOKEN_KEY = "auth_token";

async function fetchCurrentUser(token) {
  const res = await fetch("/api/v1/auth/me", {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok) return null;
  return res.json();
}

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [token, setToken] = useState(null);
  const [loading, setLoading] = useState(true);

  const refreshUser = useCallback(async (providedToken) => {
    const activeToken = providedToken ?? token;
    if (!activeToken) {
      setUser(null);
      return null;
    }

    const userInfo = await fetchCurrentUser(activeToken);
    if (!userInfo) {
      localStorage.removeItem(TOKEN_KEY);
      setToken(null);
      setUser(null);
      return null;
    }

    if (!token) {
      setToken(activeToken);
    }
    setUser(userInfo);
    return userInfo;
  }, [token]);

  useEffect(() => {
    const stored = localStorage.getItem(TOKEN_KEY);
    if (!stored) {
      setLoading(false);

      return;
    }
    refreshUser(stored)
      .catch(() => {
        localStorage.removeItem(TOKEN_KEY);
        setToken(null);
        setUser(null);
      })
      .finally(() => setLoading(false));
  }, [refreshUser]);

  const login = useCallback(async (username, password) => {
    const res = await fetch("/api/v1/auth/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password }),
    });

    let data;
    try {
      data = await res.json();
    } catch {
      throw new Error("Unable to log in, please try again later.");
    }

    if (!res.ok) {
      throw new Error(data.message || "Unable to log in, please try again later.");
    }

    const jwt = data.token;
    localStorage.setItem(TOKEN_KEY, jwt);
    setToken(jwt);

    const userInfo = await refreshUser(jwt);

    return userInfo;
  }, [refreshUser]);

  const register = useCallback(async ({ username, password, email, firstName, lastName, phone }) => {
    const res = await fetch("/api/v1/auth/register", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password, email, firstName, lastName, phone }),
    });

    let data;
    try {
      data = await res.json();
    } catch {
      throw new Error("Unable to register, please try again later.");
    }

    if (!res.ok) {
      if (data.errors && typeof data.errors === "object") {
        const fieldErrors = Object.entries(data.errors)
          .map(([field, msg]) => `${field}: ${msg}`)
          .join(", ");
        throw new Error(fieldErrors || data.message || "Unable to register, please try again later.");
      }
      throw new Error(data.message || "Unable to register, please try again later.");
    }

    const jwt = data.token;

    localStorage.setItem(TOKEN_KEY, jwt);
    setToken(jwt);

    const userInfo = await refreshUser(jwt);

    return userInfo;
  }, [refreshUser]);

  const logout = useCallback(() => {
    localStorage.removeItem(TOKEN_KEY);
    setToken(null);
    setUser(null);}, []);

  return (
    <AuthContext.Provider value={{ user, token, loading, login, logout, register, refreshUser }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) {
    throw new Error("useAuth must be used within an AuthProvider");
  }

  return ctx;
}
