"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useState,
  type ReactNode,
} from "react";
import type { User } from "@/data/types";
import { useToast } from "./toast-context";

type AuthContextValue = {
  user: User | null;
  loading: boolean;
  login: (
    email: string,
    password: string,
  ) => Promise<{ ok: boolean; redirectTo?: string }>;
  register: (
    name: string,
    email: string,
    password: string,
  ) => Promise<{ ok: boolean; redirectTo?: string }>;
  logout: () => Promise<void>;
  refresh: () => Promise<void>;
};

const AuthContext = createContext<AuthContextValue | null>(null);

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);
  const { toast } = useToast();

  const refresh = useCallback(async () => {
    const controller = new AbortController();
    const timer = window.setTimeout(() => controller.abort(), 6000);
    try {
      const res = await fetch("/api/auth/me", {
        credentials: "include",
        signal: controller.signal,
      });
      const data = (await res.json()) as { user: User | null };
      setUser(data.user ?? null);
    } catch {
      setUser(null);
    } finally {
      window.clearTimeout(timer);
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    void refresh();
  }, [refresh]);

  const login = async (email: string, password: string) => {
    try {
      const res = await fetch("/api/auth/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ email, password }),
      });
      const data = (await res.json()) as {
        user?: User;
        redirectTo?: string;
        error?: string;
      };
      if (!res.ok || !data.user) {
        toast(data.error ?? "Invalid email or password", "error");
        return { ok: false };
      }
      setUser(data.user);
      toast(`Welcome back, ${data.user.name}`);
      return { ok: true, redirectTo: data.redirectTo };
    } catch {
      toast("Unable to sign in. Check MariaDB / XAMPP.", "error");
      return { ok: false };
    }
  };

  const register = async (name: string, email: string, password: string) => {
    try {
      const res = await fetch("/api/auth/register", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ name, email, password }),
      });
      const data = (await res.json()) as {
        user?: User;
        redirectTo?: string;
        error?: string;
      };
      if (!res.ok || !data.user) {
        toast(data.error ?? "Could not create account", "error");
        return { ok: false };
      }
      setUser(data.user);
      toast("Account created");
      return { ok: true, redirectTo: data.redirectTo ?? "/account" };
    } catch {
      toast("Unable to register. Check MariaDB / XAMPP.", "error");
      return { ok: false };
    }
  };

  const logout = async () => {
    await fetch("/api/auth/logout", {
      method: "POST",
      credentials: "include",
    });
    setUser(null);
    toast("Signed out", "info");
  };

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

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