import { createContext, useContext, useEffect, useState, useCallback } from "react";

const DEFAULT_PASSWORD_MIN_LENGTH = 8;

const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [user, setUser] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [mustChangePassword, setMustChangePassword] = useState(false);
  const [passwordMinLength, setPasswordMinLength] = useState(DEFAULT_PASSWORD_MIN_LENGTH);

  useEffect(() => {
    let cancelled = false;

    window.omsorg.auth.getSession().then((session) => {
      if (cancelled) return;
      setIsAuthenticated(session.isAuthenticated);
      setUser(session.user);
      setMustChangePassword(!!session.mustChangePassword);
      setIsLoading(false);
    });

    const unsubscribe = window.omsorg.auth.onSessionChanged((session) => {
      setIsAuthenticated(session.isAuthenticated);
      setUser(session.user);
      setMustChangePassword(!!session.mustChangePassword);
      setIsLoading(false);
    });

    // Kein Login nötig - wird auch vor der Anmeldung (Passwort-vergessen-Flow) gebraucht,
    // schlägt bei fehlendem Server einfach auf DEFAULT_PASSWORD_MIN_LENGTH zurück.
    window.omsorg.auth.getPasswordPolicy().then((result) => {
      if (!cancelled && result.success) {
        setPasswordMinLength(result.minLength);
      }
    });

    return () => {
      cancelled = true;
      unsubscribe();
    };
  }, []);

  const login = useCallback(async (username, password) => {
    const result = await window.omsorg.auth.login(username, password);
    if (result.success) {
      setIsAuthenticated(true);
      setUser(result.user);
      setMustChangePassword(!!result.mustChangePassword);
    }
    return result;
  }, []);

  const logout = useCallback(async () => {
    await window.omsorg.auth.logout();
    setIsAuthenticated(false);
    setUser(null);
    setMustChangePassword(false);
  }, []);

  const changePassword = useCallback(async (currentPassword, newPassword) => {
    const result = await window.omsorg.auth.changePassword(currentPassword, newPassword);
    if (result.success) {
      // Serverseitig wurden alle Sessions widerrufen (siehe UserService.ChangeOwnPasswordAsync) -
      // der aktuelle Access-Token ist schon tot, also lokal neu einloggen lassen statt weiterzumachen.
      setIsAuthenticated(false);
      setUser(null);
      setMustChangePassword(false);
    }
    return result;
  }, []);

  const hasPermission = useCallback(
    (module, action) => !!user?.permissions?.some((p) => p.module === module && p.action === action),
    [user]
  );

  // Rein kosmetisch (z.B. Suchfeld ausblenden, wenn ohnehin nur der eigene Datensatz zurückkommt) -
  // die eigentliche Durchsetzung von "nur eigene Daten" passiert serverseitig (siehe omsorgCore/
  // CLAUDE.md, "Datenebenen-Scope"), nicht hier.
  const getScope = useCallback(
    (module, action) => user?.permissions?.find((p) => p.module === module && p.action === action)?.scope ?? null,
    [user]
  );

  return (
    <AuthContext.Provider
      value={{
        isAuthenticated,
        user,
        isLoading,
        mustChangePassword,
        passwordMinLength,
        login,
        logout,
        changePassword,
        hasPermission,
        getScope
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth muss innerhalb von AuthProvider verwendet werden");
  return ctx;
}
