"use client";
import { useState, useEffect, useCallback, createContext, useContext } from "react";
import { api } from "@/lib/api";
import {
  hasNostrExtension,
  getPublicKey,
  signEvent,
  createAuthEvent,
  fetchNostrProfile,
  createBunkerSigner,
  type BunkerSignerInterface,
  type NostrProfile,
} from "@/lib/nostr";

export interface User {
  pubkey: string;
  role: string;
  isSuperAdmin?: boolean;
  permissions?: string[];
  username?: string;
  name?: string;
  picture?: string;
  about?: string;
  nip05?: string;
  displayName?: string;
}

interface AuthContextType {
  user: User | null;
  loading: boolean;
  login: () => Promise<User>;
  loginWithBunker: (input: string) => Promise<User>;
  loginWithConnectedSigner: (signer: BunkerSignerInterface) => Promise<User>;
  logout: () => void;
  isAdmin: boolean;
  isModerator: boolean;
  isSuperAdmin: boolean;
  permissions: string[];
  can: (permission: string) => boolean;
  refreshAccess: () => Promise<void>;
}

export const AuthContext = createContext<AuthContextType>({
  user: null,
  loading: true,
  login: async () => ({ pubkey: "", role: "guest" }),
  loginWithBunker: async () => ({ pubkey: "", role: "guest" }),
  loginWithConnectedSigner: async () => ({ pubkey: "", role: "guest" }),
  logout: () => {},
  isAdmin: false,
  isModerator: false,
  isSuperAdmin: false,
  permissions: [],
  can: () => false,
  refreshAccess: async () => {},
});

export function useAuth() {
  return useContext(AuthContext);
}

export function useAuthProvider(): AuthContextType {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);

  const refreshAccess = useCallback(async () => {
    const token = localStorage.getItem("bbe_token");
    if (!token) return;
    try {
      const me = await api.getMe();
      setUser((prev) => {
        if (!prev) return prev;
        const next: User = {
          ...prev,
          role: me.role,
          isSuperAdmin: me.isSuperAdmin,
          permissions: me.permissions,
          username: me.username ?? prev.username,
        };
        localStorage.setItem("bbe_user", JSON.stringify(next));
        return next;
      });
    } catch {
      // Best-effort refresh. The stored snapshot remains usable.
    }
  }, []);

  useEffect(() => {
    const stored = localStorage.getItem("bbe_user");
    const token = localStorage.getItem("bbe_token");
    if (stored && token) {
      try {
        setUser(JSON.parse(stored));
      } catch {
        localStorage.removeItem("bbe_user");
        localStorage.removeItem("bbe_token");
      }
      // Refresh effective role and permissions live so a stale JWT snapshot does
      // not drive what the user can see or do.
      void refreshAccess();
    }
    setLoading(false);
  }, [refreshAccess]);

  const completeAuth = useCallback(
    async (
      getPubKey: () => Promise<string>,
      sign: (event: any) => Promise<any>
    ): Promise<User> => {
      const pubkey = await getPubKey();
      const { challenge } = await api.getChallenge(pubkey);
      const event = createAuthEvent(pubkey, challenge);
      const signedEvent = await sign(event);
      const { token, user: userData } = await api.verify(pubkey, signedEvent);

      let profile: NostrProfile = {};
      try {
        profile = await fetchNostrProfile(pubkey);
      } catch {
        // Profile fetch is best-effort
      }

      const fullUser: User = {
        ...userData,
        isSuperAdmin: userData.isSuperAdmin ?? false,
        permissions: userData.permissions ?? [],
        name: profile.name,
        displayName: profile.displayName,
        picture: profile.picture,
        about: profile.about,
        nip05: profile.nip05,
        username: userData.username,
      };

      localStorage.setItem("bbe_token", token);
      localStorage.setItem("bbe_user", JSON.stringify(fullUser));
      setUser(fullUser);
      return fullUser;
    },
    []
  );

  const login = useCallback(async (): Promise<User> => {
    if (!hasNostrExtension()) {
      throw new Error("Please install a Nostr extension (e.g., Alby, nos2x)");
    }
    return completeAuth(getPublicKey, signEvent);
  }, [completeAuth]);

  const loginWithConnectedSigner = useCallback(
    async (signer: BunkerSignerInterface): Promise<User> => {
      return completeAuth(
        () => signer.getPublicKey(),
        (event) => signer.signEvent(event)
      );
    },
    [completeAuth]
  );

  const loginWithBunker = useCallback(
    async (input: string): Promise<User> => {
      const { signer } = await createBunkerSigner(input);
      try {
        return await loginWithConnectedSigner(signer);
      } finally {
        await signer.close().catch(() => {});
      }
    },
    [loginWithConnectedSigner]
  );

  const logout = useCallback(() => {
    localStorage.removeItem("bbe_token");
    localStorage.removeItem("bbe_user");
    setUser(null);
  }, []);

  const permissions = user?.permissions ?? [];
  const isSuperAdmin = user?.isSuperAdmin ?? false;
  const can = useCallback(
    (permission: string) => isSuperAdmin || permissions.includes(permission),
    [isSuperAdmin, permissions]
  );

  return {
    user,
    loading,
    login,
    loginWithBunker,
    loginWithConnectedSigner,
    logout,
    isSuperAdmin,
    permissions,
    can,
    refreshAccess,
    // Compatibility shims for any remaining role-name checks.
    isAdmin: isSuperAdmin || user?.role === "admin",
    isModerator: isSuperAdmin || user?.role === "admin" || user?.role === "moderator",
  };
}
