"use client";

import {
  createContext,
  useContext,
  useEffect,
  useState,
  useCallback,
  type ReactNode,
} from "react";
import api from "@/lib/api";
import type { User, AuthResponse, LoginData, RegisterData } from "@/lib/types";

interface TwoFactorChallenge {
  email: string;
  method: 'totp' | 'email';
}

interface AuthContextType {
  user: User | null;
  isLoading: boolean;
  twoFactorChallenge: TwoFactorChallenge | null;
  login: (data: LoginData) => Promise<void>;
  register: (data: RegisterData) => Promise<void>;
  logout: () => Promise<void>;
  refreshUser: () => Promise<void>;
  verifyTwoFactor: (code: string) => Promise<void>;
  cancelTwoFactor: () => void;
}

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

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [twoFactorChallenge, setTwoFactorChallenge] = useState<TwoFactorChallenge | null>(null);

  const refreshUser = useCallback(async () => {
    try {
      const token = localStorage.getItem("auth_token");
      if (!token) {
        setUser(null);
        return;
      }
      const { data } = await api.get("/api/user");
      setUser(data.user);
    } catch {
      localStorage.removeItem("auth_token");
      setUser(null);
    }
  }, []);

  useEffect(() => {
    refreshUser().finally(() => setIsLoading(false));
  }, [refreshUser]);

  const login = async (loginData: LoginData) => {
    const { data } = await api.post<AuthResponse>("/api/login", loginData);

    if (data.two_factor) {
      setTwoFactorChallenge({
        email: loginData.email,
        method: data.two_factor_method!,
      });
      return;
    }

    localStorage.setItem("auth_token", data.token);
    document.cookie = `auth_token=${data.token}; path=/; max-age=${60 * 60 * 24 * 7}; SameSite=Lax`;
    setUser(data.user);
  };

  const verifyTwoFactor = async (code: string) => {
    if (!twoFactorChallenge) throw new Error("No 2FA challenge active");

    const { data } = await api.post<AuthResponse>("/api/two-factor/verify", {
      email: twoFactorChallenge.email,
      code,
    });

    localStorage.setItem("auth_token", data.token);
    document.cookie = `auth_token=${data.token}; path=/; max-age=${60 * 60 * 24 * 7}; SameSite=Lax`;
    setUser(data.user);
    setTwoFactorChallenge(null);
  };

  const cancelTwoFactor = () => {
    setTwoFactorChallenge(null);
  };

  const register = async (registerData: RegisterData) => {
    const { data } = await api.post<AuthResponse>("/api/register", registerData);
    localStorage.setItem("auth_token", data.token);
    document.cookie = `auth_token=${data.token}; path=/; max-age=${60 * 60 * 24 * 7}; SameSite=Lax`;
    setUser(data.user);
  };

  const logout = async () => {
    try {
      await api.post("/api/logout");
    } finally {
      localStorage.removeItem("auth_token");
      document.cookie = "auth_token=; path=/; max-age=0";
      setUser(null);
    }
  };

  return (
    <AuthContext.Provider
      value={{ user, isLoading, twoFactorChallenge, login, register, logout, refreshUser, verifyTwoFactor, cancelTwoFactor }}
    >
      {children}
    </AuthContext.Provider>
  );
}

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