import { useRouter } from 'next/router';
import { createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { api, ApiError } from './api';

export interface AuthUser {
  id: string;
  email: string;
  name: string;
}

export interface Membership {
  role: 'ORG_ADMIN' | 'MEMBER' | 'VIEWER';
  org: { id: string; name: string; slug: string };
}

interface MeResponse {
  user: AuthUser;
  memberships: Membership[];
}

interface AuthContextValue {
  user: AuthUser | null;
  memberships: Membership[];
  activeOrg: Membership | null;
  loading: boolean;
  setActiveOrgId: (orgId: string) => void;
  login: (email: string, password: string) => Promise<void>;
  register: (data: { email: string; password: string; name: string; orgName: string }) => Promise<void>;
  logout: () => Promise<void>;
}

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

const ACTIVE_ORG_KEY = 'ulhub_active_org';

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<AuthUser | null>(null);
  const [memberships, setMemberships] = useState<Membership[]>([]);
  const [activeOrgId, setActiveOrgIdState] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  const applySession = useCallback((session: MeResponse) => {
    setUser(session.user);
    setMemberships(session.memberships);
    setActiveOrgIdState((current) => {
      const stored = current ?? localStorage.getItem(ACTIVE_ORG_KEY);
      const valid = session.memberships.some((m) => m.org.id === stored);
      return valid ? stored : (session.memberships[0]?.org.id ?? null);
    });
  }, []);

  useEffect(() => {
    api
      .get<MeResponse>('/api/auth/me')
      .then(applySession)
      .catch(() => setUser(null))
      .finally(() => setLoading(false));
  }, [applySession]);

  const setActiveOrgId = useCallback((orgId: string) => {
    localStorage.setItem(ACTIVE_ORG_KEY, orgId);
    setActiveOrgIdState(orgId);
  }, []);

  const login = useCallback(
    async (email: string, password: string) => {
      applySession(await api.post<MeResponse>('/api/auth/login', { email, password }));
    },
    [applySession],
  );

  const register = useCallback(
    async (data: { email: string; password: string; name: string; orgName: string }) => {
      applySession(await api.post<MeResponse>('/api/auth/register', data));
    },
    [applySession],
  );

  const logout = useCallback(async () => {
    await api.post('/api/auth/logout', {}).catch(() => undefined);
    localStorage.removeItem(ACTIVE_ORG_KEY);
    setUser(null);
    setMemberships([]);
    setActiveOrgIdState(null);
  }, []);

  const value = useMemo<AuthContextValue>(
    () => ({
      user,
      memberships,
      activeOrg: memberships.find((m) => m.org.id === activeOrgId) ?? null,
      loading,
      setActiveOrgId,
      login,
      register,
      logout,
    }),
    [user, memberships, activeOrgId, loading, setActiveOrgId, login, register, logout],
  );

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

export function useAuth(): AuthContextValue {
  const ctx = useContext(AuthContext);
  if (!ctx) {
    throw new Error('useAuth must be used inside AuthProvider');
  }
  return ctx;
}

// Client-side page guard: redirects to /login when unauthenticated.
export function useRequireAuth() {
  const auth = useAuth();
  const router = useRouter();
  useEffect(() => {
    if (!auth.loading && !auth.user) {
      router.replace('/login');
    }
  }, [auth.loading, auth.user, router]);
  return auth;
}

export { ApiError };
