import { create } from 'zustand';
import AsyncStorage from '@react-native-async-storage/async-storage';

// expo-local-authentication ist ein NATIVE-Modul. In einem Dev-Client, der noch
// VOR dem Hinzufügen dieser Dependency gebaut wurde, fehlt der native Teil →
// `require()` wirft "Cannot find native module 'ExpoLocalAuthentication'" und
// würde die ganze App beim Start crashen (appLock wird im RootLayout importiert).
// Daher: defensiv laden. Fehlt das Modul → App-Sperre einfach „nicht verfügbar",
// der Rest der App läuft normal weiter. In jedem echten Build (EAS / frischer
// `expo prebuild`) ist das Modul drin und alles funktioniert.
type LocalAuthModule = typeof import('expo-local-authentication');
let LocalAuthentication: LocalAuthModule | null = null;
try {
  // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
  LocalAuthentication = require('expo-local-authentication') as LocalAuthModule;
} catch {
  LocalAuthentication = null;
}

/**
 * App-Sperre (Face ID / Touch ID).
 *
 * Liegt OBEN auf der bereits authentifizierten Supabase-Session — re-auth beim
 * Öffnen, kein Login-Ersatz. Sucht-/Stigma-Schutz: wer dein entsperrtes iPhone
 * nimmt, kann Rebreak nicht öffnen.
 *
 *  - `enabled`  → User-Präferenz, persistiert (AsyncStorage)
 *  - `locked`   → in-memory: ist die App gerade hinter der Sperre?
 *  - `available`→ Gerät kann biometrisch ODER per Geräte-Passcode auth'en
 *
 * Lock-Timing: sofort beim Backgrounden (siehe AppLockGate / AppState-Listener).
 */

const STORAGE_KEY = '@rebreak/app-lock-enabled';

/** Reason-String im System-Prompt von Face ID / Touch ID. Wird i18n überschrieben
 *  wo wir `t()` haben — dieser Default greift nur falls der Aufrufer keinen liefert. */
const DEFAULT_PROMPT = 'Rebreak entsperren';

type AppLockState = {
  /** persistierte User-Präferenz */
  enabled: boolean;
  /** in-memory: App ist gerade gesperrt */
  locked: boolean;
  /** Gerät unterstützt Biometrie/Passcode-Auth (sonst Toggle ausgrauen) */
  available: boolean;
  /** init() durch */
  ready: boolean;

  init: () => Promise<void>;
  setEnabled: (enabled: boolean) => Promise<void>;
  /** sperren (App geht in den Hintergrund) */
  lock: () => void;
  /** Face-ID/Touch-ID/Passcode-Prompt — bei Erfolg entsperrt. Gibt success zurück. */
  authenticate: (promptMessage?: string) => Promise<boolean>;
};

export const useAppLockStore = create<AppLockState>((set, get) => ({
  enabled: false,
  locked: false,
  available: false,
  ready: false,

  init: async () => {
    // Idempotenz: nur beim allerersten init() den locked-Default setzen. Spätere
    // init()-Calls (z.B. wenn RootLayoutInner durch router.replace re-mountet)
    // dürfen den aktuellen locked-Zustand NICHT zurücksetzen — sonst entsteht
    // eine Endlosschleife: unlock → re-mount → init() → locked=true wieder.
    const alreadyReady = get().ready;
    if (!LocalAuthentication) {
      // Native-Modul fehlt (alter Dev-Client) → Sperre nicht verfügbar, App läuft weiter.
      set({ enabled: false, available: false, locked: false, ready: true });
      return;
    }
    const [storedRaw, hasHardware, isEnrolled] = await Promise.all([
      AsyncStorage.getItem(STORAGE_KEY),
      LocalAuthentication.hasHardwareAsync(),
      LocalAuthentication.isEnrolledAsync(),
    ]);
    // available = Gerät hat Biometrie-Hardware UND mind. eine Methode eingerichtet
    // (Face/Touch ODER Geräte-Passcode — isEnrolledAsync deckt beides ab).
    const available = hasHardware && isEnrolled;
    const enabled = storedRaw === 'true' && available;
    set({
      enabled,
      available,
      // Cold-Start: locked=enabled (kein Flash von App-Inhalt vor LockScreen).
      // Re-Init: aktuellen locked-Stand erhalten — sonst Loop.
      locked: alreadyReady ? get().locked : enabled,
      ready: true,
    });
  },

  setEnabled: async (enabled) => {
    await AsyncStorage.setItem(STORAGE_KEY, enabled ? 'true' : 'false');
    set({ enabled, locked: false });
  },

  lock: () => {
    if (get().enabled) set({ locked: true });
  },

  authenticate: async (promptMessage) => {
    if (!LocalAuthentication) return false;
    const result = await LocalAuthentication.authenticateAsync({
      promptMessage: promptMessage ?? DEFAULT_PROMPT,
      // Geräte-Passcode als Fallback erlauben (Face ID schlägt 3x fehl → Passcode).
      // Wichtig, damit man sich nicht aus der App aussperrt.
      disableDeviceFallback: false,
      cancelLabel: undefined,
    });
    if (result.success) {
      set({ locked: false });
      return true;
    }
    return false;
  },
}));
