import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from 'react';
import { clearTokens, getToken } from '../api/http';
import * as permApi from '../api/permission';

interface AuthState {
  ready: boolean;
  token: string;
  uid: string;
  roles: string[];
  isAdmin: boolean;
  syncSession: () => void;
  refreshRoles: () => Promise<void>;
  signOut: () => void;
}

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

export function AuthProvider({ children }: { children: ReactNode }) {
  const [ready, setReady] = useState(false);
  const [token, setToken] = useState(getToken);
  const [uid, setUid] = useState(() => localStorage.getItem('uid') ?? '');
  const [roles, setRoles] = useState<string[]>(() => {
    try {
      return JSON.parse(localStorage.getItem('roles') ?? '[]') as string[];
    } catch {
      return [];
    }
  });

  const syncSession = useCallback(() => {
    setToken(getToken());
    setUid(localStorage.getItem('uid') ?? '');
  }, []);

  const refreshRoles = useCallback(async () => {
    if (!getToken()) {
      setRoles([]);
      return;
    }
    try {
      const me = await permApi.getMyPermissions();
      setRoles(me.roles ?? []);
      localStorage.setItem('roles', JSON.stringify(me.roles ?? []));
      if (me.uid) {
        setUid(me.uid);
        localStorage.setItem('uid', me.uid);
      }
    } catch {
      setRoles([]);
    }
  }, []);

  useEffect(() => {
    (async () => {
      if (getToken()) await refreshRoles();
      setReady(true);
    })();
  }, [refreshRoles]);

  const signOut = useCallback(() => {
    clearTokens();
    setToken('');
    setUid('');
    setRoles([]);
  }, []);

  const value = useMemo(
    () => ({
      ready,
      token,
      uid,
      roles,
      isAdmin: permApi.isAdminRole(roles),
      syncSession,
      refreshRoles,
      signOut,
    }),
    [ready, token, uid, roles, syncSession, refreshRoles, signOut],
  );

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

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuth 需在 AuthProvider 內');
  return ctx;
}
