import { useEffect, useRef, useState } from 'react';
import { Alert, AppState, Platform, View } from 'react-native';
import { useTranslation } from 'react-i18next';
import { useColors } from '../../../lib/theme';
import { apiFetch } from '../../../lib/api';
import { invalidateMe } from '../../../hooks/useMe';
import { protection, FAMILY_CONTROLS_AVAILABLE } from '../../../lib/protection';
import { useProtectionState } from '../../../hooks/useProtectionState';
import { useBlocklistSync } from '../../../hooks/useBlocklistSync';
import { getPermissionScreenshot } from '../../../lib/onboardingAssets';
import i18n from '../../../lib/i18n';
import { AndroidSetupFlow, IosUnsupervisedSetupFlow } from '../../blocker/SetupFlows';
import { LayerSwitchCard } from '../../blocker/LayerSwitchCard';
import { OnboardingShell } from '../OnboardingShell';
import { LyraBubble } from '../LyraBubble';
import { CTABar } from '../CTABar';
import { PermissionConfirmSheet } from '../PermissionConfirmSheet';
import { PermissionDeniedSheet } from '../../PermissionDeniedSheet';

/** Steps mit Gate davor. VPN/Geräteadmin/AppLock/URL = echte System-Dialoge
 *  (welcher Button). a11y = bekommt einen reicheren Explainer (Overlay-Recht +
 *  Schalter-Suche mit Screenshot/Indikator), weil's für viele kompliziert ist.
 *  Screentime hat einen eigenen instruktiven Flow → kein Gate. */
type ConfirmStep = 'vpn' | 'deviceadmin' | 'applock' | 'urlfilter' | 'a11y' | 'usage' | 'overlay';

/**
 * Onboarding-Schutz-Step.
 *
 * WICHTIG: Dieser Step rendert EXAKT denselben Setup-Flow wie der Blocker-Screen
 * (components/blocker/SetupFlows.tsx) — die Reihenfolge + das Gating sind dort
 * die einzige Quelle der Wahrheit:
 *   Android: VPN → Geräteadmin → a11y  (a11y MUSS zuletzt, sonst blockt der
 *            Tamper-Lock die Geräteadmin-Settings-Seite).
 *   iOS:     App-Lock → Bildschirmzeit → URL-Filter.
 *
 * Die Handler hier spiegeln blocker.tsx 1:1 (Activate + Sync + Recovery-Sheets).
 * "Fertig" = der Blocker würde "Schutz aktiv" zeigen (lockedIn). Erst dann wird
 * der "Weiter"-Button aktiv und der Onboarding-Step abgeschlossen.
 */
export function ProtectionSlide({
  onDone,
  current,
  total,
}: {
  onDone: () => void;
  current: number;
  total: number;
}) {
  const { t } = useTranslation();
  const colors = useColors();
  const { state, mdmManaged, refresh, activateUrlFilter, activateFamilyControls } =
    useProtectionState();
  const { sync: syncBlocklist } = useBlocklistSync();

  const [screentimeCode, setScreentimeCode] = useState<string | null>(null);
  const [screentimeConfirmed, setScreentimeConfirmed] = useState(false);
  const [screentimeSaving, setScreentimeSaving] = useState(false);
  const [permissionDeniedOpen, setPermissionDeniedOpen] = useState(false);
  const [familyControlsErrorOpen, setFamilyControlsErrorOpen] = useState(false);
  const [confirmStep, setConfirmStep] = useState<ConfirmStep | null>(null);
  // Fallback-Ausweg: erscheint, wenn der Schutz auf diesem Gerät nicht aktiviert
  // werden kann (Timeout oder fehlgeschlagener Versuch) — sonst hängt der User
  // im Onboarding fest (z.B. Android-16-VPN-Crash). Schutz später im Blocker.
  const [showSkip, setShowSkip] = useState(false);
  // VPN-Aktivierung läuft (Android): Spinner am VPN-Step bis der Layer-State
  // bestätigt ist. Der Protection-State pollt sonst zu selten → der Step bliebe
  // ~1min „offen", obwohl der Tunnel längst läuft.
  const [vpnPending, setVpnPending] = useState(false);
  const finishedRef = useRef(false);
  const armingRef = useRef(false);
  // a11y-Explainer NUR beim ersten Tap zeigen — danach (Settings-Rückkehr →
  // nochmal tippen zum Armen) direkt durch, sonst nervt das Sheet doppelt.
  const a11yExplainerShownRef = useRef(false);

  // Persistierten Screen-Time-Status laden, damit der Step nicht erneut gefragt
  // wird, wenn der Code schon gesetzt ist (gleiche Logik wie blocker.tsx).
  useEffect(() => {
    if (Platform.OS !== 'ios') return;
    protection
      .getScreenTimePasscode()
      .then((p) => {
        if (p) setScreentimeConfirmed(true);
      })
      .catch(() => {});
  }, []);

  const urlFilterActive = state?.layers.urlFilter === true;
  const familyControlsActive = state?.layers.familyControls === true;
  const appDeletionLockActive = (state?.layers.appDeletionLock ?? familyControlsActive) === true;
  const nefilterActive = state?.layers.nefilterActive === true;
  const deviceAdminActive = state?.layers.deviceAdmin === true;
  // a11y-SERVICE an (≠ Tamper-Lock armed). Trennung kommt direkt aus dem nativen
  // getDeviceState ({accessibility} vs {tamperLock}).
  const a11yServiceOn = state?.layers.accessibility === true;
  // Akku-Ausnahme: ohne sie schläfert Samsung & Co. die App ein → a11y-Service
  // wird entbunden → Lock wertlos. Daher Pflicht-Step im Android-Flow.
  const batteryUnrestricted = state?.layers.batteryUnrestricted === true;

  // "Fertig" == blocker.tsx lockedIn. Eine Quelle der Wahrheit.
  const allDone =
    Platform.OS === 'android'
      ? urlFilterActive && appDeletionLockActive && deviceAdminActive && batteryUnrestricted
      : (nefilterActive || urlFilterActive) &&
        (mdmManaged || nefilterActive || appDeletionLockActive || !FAMILY_CONTROLS_AVAILABLE);

  async function finishProtectionStep() {
    if (finishedRef.current) return;
    finishedRef.current = true;
    await apiFetch('/api/profile/me/onboarding-step', {
      method: 'PATCH',
      body: { step: 'done' },
    }).catch(() => {});
    invalidateMe();
    onDone();
  }

  // Notausgang: Schutz noch nicht aktiv, aber User soll nicht festsitzen.
  function handleSkipProtection() {
    Alert.alert(
      t('onboarding.protection_skip.title'),
      t('onboarding.protection_skip.body'),
      [
        { text: t('common.cancel'), style: 'cancel' },
        {
          text: t('onboarding.protection_skip.confirm'),
          style: 'destructive',
          onPress: () => {
            void finishProtectionStep();
          },
        },
      ],
    );
  }

  // Foreground-Return → State neu laden. a11y/Geräteadmin/Bildschirmzeit werden in
  // den System-Settings gesetzt; beim Zurückkommen pollen wir den neuen Layer-State,
  // damit die Cards umschalten und "Weiter" freigeschaltet wird.
  useEffect(() => {
    const sub = AppState.addEventListener('change', (next) => {
      if (next === 'active') refresh();
    });
    return () => sub.remove();
  }, [refresh]);

  // Sicherheitsnetz: Ist der Schutz nach 30 s noch nicht aktiv (z.B. weil die
  // Aktivierung auf diesem OS scheitert), den "Später einrichten"-Ausweg zeigen.
  // (Failed-Aktivierungen blenden ihn sofort ein, siehe Handler unten.)
  useEffect(() => {
    if (allDone) {
      setShowSkip(false);
      return;
    }
    const id = setTimeout(() => setShowSkip(true), 30000);
    return () => clearTimeout(id);
  }, [allDone]);

  // Nach VPN-Freigabe schneller nachpollen, bis urlFilter aktiv ist (sonst ~1min,
  // bis der Step grün wird). Spinner läuft, solange vpnPending. Deckel ~60s.
  useEffect(() => {
    if (urlFilterActive) {
      setVpnPending(false);
      return;
    }
    if (!vpnPending) return;
    let ticks = 0;
    const id = setInterval(() => {
      ticks += 1;
      refresh();
      if (ticks >= 20) {
        clearInterval(id);
        setVpnPending(false);
      }
    }, 3000);
    return () => clearInterval(id);
  }, [vpnPending, urlFilterActive, refresh]);

  // Auto-Arm (Android): kam der User aus den a11y-Settings zurück und hat den
  // Service aktiviert (accessibility=true), war der Tamper-Lock bisher NICHT armed
  // — das passierte erst beim ZWEITEN Tap auf den a11y-Button (Two-Step-Design).
  // Hier ziehen wir das automatisch nach: sobald a11y-Service an + noch nicht
  // armed, einmal activateFamilyControls() → geht bei aktivem a11y direkt in den
  // Arm-Pfad (kein Settings-Öffnen) → Step wird grün ohne zweiten Tap.
  useEffect(() => {
    if (Platform.OS !== 'android') return;
    if (!a11yServiceOn || appDeletionLockActive || armingRef.current) return;
    armingRef.current = true;
    activateFamilyControls()
      .catch(() => {})
      .finally(() => {
        armingRef.current = false;
        refresh();
      });
  }, [a11yServiceOn, appDeletionLockActive, activateFamilyControls, refresh]);

  // ─── Handler (1:1 wie blocker.tsx) ──────────────────────────────────────────

  async function handleActivateUrlFilter() {
    try {
      const result = await activateUrlFilter();
      if (!result.enabled) {
        // Aktivierung fehlgeschlagen → Notausgang sofort anbieten (nicht erst nach 30s).
        setShowSkip(true);
        setVpnPending(false);
        const isPermissionDenied =
          Platform.OS === 'ios' &&
          typeof result.error === 'string' &&
          /NEFilterErrorDomain:\s*5/i.test(result.error);
        if (isPermissionDenied) {
          setPermissionDeniedOpen(true);
          return result;
        }
        Alert.alert(
          t('blocker.activate_url_failed_title'),
          result.error ?? t('blocker.activate_url_failed_msg'),
          [
            { text: t('common.ok') },
            { text: t('blocker.activate_settings_btn'), onPress: () => protection.openSystemSettings() },
          ],
        );
      } else {
        const sync = await syncBlocklist();
        if (sync.ok) {
          await refresh();
        } else {
          Alert.alert(
            t('blocker.sync_list_failed_title'),
            sync.error ?? t('blocker.sync_list_failed_msg'),
          );
        }
      }
      return result;
    } catch (e: any) {
      setShowSkip(true);
      setVpnPending(false);
      Alert.alert(t('blocker.activation_failed_title'), e?.message ?? t('common.unknown_error'));
      return { enabled: false };
    }
  }

  async function handleActivateFamilyControls() {
    try {
      const result = await activateFamilyControls();
      if (!result.enabled && result.error !== 'accessibility_pending') {
        const isXpcFailure =
          Platform.OS === 'ios' &&
          typeof result.error === 'string' &&
          /NSCocoaErrorDomain:\s*4099/i.test(result.error);
        if (isXpcFailure) {
          setFamilyControlsErrorOpen(true);
          return result;
        }
        Alert.alert(
          t('blocker.activate_app_lock_failed_title'),
          result.error ?? t('blocker.activate_app_lock_failed_msg'),
        );
      }
      if (result.enabled) await refresh();
      return result;
    } catch (e: any) {
      Alert.alert(t('blocker.activation_failed_title'), e?.message ?? t('common.unknown_error'));
      return { enabled: false };
    }
  }

  function handleGenerateScreentimeCode() {
    setScreentimeCode(Math.floor(1000 + Math.random() * 9000).toString());
    setScreentimeConfirmed(false);
  }

  async function handleScreentimeConfirm() {
    if (!screentimeCode) return;
    setScreentimeSaving(true);
    try {
      await protection.saveScreenTimePasscode(screentimeCode);
      setScreentimeConfirmed(true);
      setScreentimeCode(null);
    } catch (e: any) {
      Alert.alert(t('common.error'), e?.message ?? t('common.unknown_error'));
    } finally {
      setScreentimeSaving(false);
    }
  }

  async function handleRequestDeviceAdmin() {
    try {
      const result = await protection.requestDeviceAdmin();
      if (!result.launched) {
        Alert.alert(t('blocker.android_admin_failed_title'), t('blocker.android_admin_failed_msg'));
      } else {
        await refresh();
      }
      return result;
    } catch (e: any) {
      Alert.alert(t('blocker.activation_failed_title'), e?.message ?? t('common.unknown_error'));
      return { launched: false };
    }
  }

  // ─── Anti-Blind-Klick-Gate ──────────────────────────────────────────────────
  // Statt direkt die Permission zu feuern, öffnet der Card-Button erst das
  // Confirm-Sheet. Erst nach Häkchen + „Weiter" läuft der echte Handler. Die
  // gated-Wrapper geben sofort ein neutrales Result zurück (kein Fehler → kein
  // Alert); die Card-done-States kommen ohnehin aus den Layer-Flags, nicht aus
  // dem Return-Wert.
  const gatedVpn = async () => {
    setConfirmStep('vpn');
    return { enabled: false };
  };
  const gatedDeviceAdmin = async () => {
    setConfirmStep('deviceadmin');
    return { launched: false };
  };
  // Akku-Ausnahme: System-Dialog direkt öffnen (ein Tap „Zulassen"); der
  // Step-Card-Text erklärt das Warum. Return-Refresh via AppState-'active'.
  const gatedBattery = async () => protection.requestIgnoreBatteryOptimizations();
  // Samsung-Sonderweg: App-Detail-Settings (Akku → „Uneingeschränkt" + raus aus
  // „Schlafende Apps") — das deckt der reine AOSP-Whitelist-Dialog nicht ab.
  const openBatteryDetails = async () => protection.openAppDetailsSettings();
  const gatedApplock = async () => {
    setConfirmStep('applock');
    return { enabled: false };
  };
  const gatedUrlFilter = async () => {
    setConfirmStep('urlfilter');
    return { enabled: false };
  };
  const gatedA11y = async () => {
    // Einmalig Nutzungszugriff holen — DAMIT erkennt die native Guide-Notification
    // den aktuellen Samsung-Screen und führt Schritt für Schritt. Ohne das gäbe es
    // nur dumme Toasts. Erst freigeben, dann zurück + a11y nochmal tippen.
    if (!(await protection.hasUsageAccess())) {
      setConfirmStep('usage');
      return { enabled: false };
    }
    // Dann „Über anderen Apps anzeigen" — damit der Hinweis als sichtbares Overlay
    // VOR den Settings schwebt (statt nur als leicht übersehbare Notification).
    if (!(await protection.hasOverlayPermission())) {
      setConfirmStep('overlay');
      return { enabled: false };
    }
    // Erster Tap → Explainer (Installierte Dienste → ReBreak → Schalter, Screenshot).
    // Folge-Taps (nach Settings-Rückkehr zum Armen) → direkt, ohne Sheet.
    if (!a11yExplainerShownRef.current) {
      a11yExplainerShownRef.current = true;
      setConfirmStep('a11y');
      return { enabled: false };
    }
    return handleActivateFamilyControls();
  };

  function runConfirmedAction(step: ConfirmStep) {
    switch (step) {
      case 'vpn':
        setVpnPending(true);
        return handleActivateUrlFilter();
      case 'urlfilter':
        return handleActivateUrlFilter();
      case 'deviceadmin':
        return handleRequestDeviceAdmin();
      case 'applock':
      case 'a11y':
        return handleActivateFamilyControls();
      case 'usage':
        // Nutzungszugriff-Settings öffnen. User gibt frei, kommt zurück, tippt
        // a11y nochmal → hasUsageAccess true → nächstes Gate / Explainer.
        return protection.openUsageAccessSettings();
      case 'overlay':
        // „Über anderen Apps anzeigen"-Settings öffnen. Danach a11y nochmal tippen.
        return protection.openOverlayPermissionSettings();
    }
  }

  // ─── Render ─────────────────────────────────────────────────────────────────

  return (
    <OnboardingShell
      current={current}
      total={total}
      cta={
        <CTABar
          primaryLabel={t('common.continue')}
          onPrimary={finishProtectionStep}
          primaryDisabled={!allDone}
          secondaryLabel={!allDone && showSkip ? t('onboarding.protection_skip.label') : undefined}
          onSecondary={!allDone && showSkip ? handleSkipProtection : undefined}
        />
      }
    >
      <LyraBubble text={t('onboarding.lyra.protection.body')} emotion="empathy" />

      <View style={{ marginTop: 16 }}>
        {Platform.OS === 'android' ? (
          <AndroidSetupFlow
            vpnActive={urlFilterActive}
            vpnActivating={vpnPending}
            accessibilityLocked={appDeletionLockActive}
            deviceAdminActive={deviceAdminActive}
            batteryUnrestricted={batteryUnrestricted}
            onActivateVpn={gatedVpn}
            onActivateAccessibility={gatedA11y}
            onRequestDeviceAdmin={gatedDeviceAdmin}
            onRequestBattery={gatedBattery}
            onOpenAppDetails={openBatteryDetails}
            colors={colors}
            t={t}
          />
        ) : FAMILY_CONTROLS_AVAILABLE && !mdmManaged && !nefilterActive ? (
          <IosUnsupervisedSetupFlow
            familyControlsActive={appDeletionLockActive}
            screentimeCode={screentimeCode}
            screentimeConfirmed={screentimeConfirmed}
            screentimeSaving={screentimeSaving}
            urlFilterActive={urlFilterActive}
            onActivateFamilyControls={gatedApplock}
            onGenerateScreentimeCode={handleGenerateScreentimeCode}
            onConfirmScreentime={handleScreentimeConfirm}
            onActivateUrlFilter={gatedUrlFilter}
            colors={colors}
            t={t}
          />
        ) : (
          /* iOS Distribution ohne Family-Controls-Entitlement (oder MDM/NEFilter):
             nur der URL-Filter als einzelner Layer — exakt wie der Blocker-Fallback. */
          <LayerSwitchCard
            icon="globe-outline"
            title={t('blocker.layers_url_filter_title')}
            subtitle={
              urlFilterActive
                ? t('blocker.layers_url_filter_subtitle_active')
                : t('blocker.layers_url_filter_subtitle_inactive')
            }
            active={urlFilterActive}
            onActivate={gatedUrlFilter}
          />
        )}
      </View>

      <PermissionConfirmSheet
        visible={confirmStep !== null}
        title={confirmStep ? t(`onboarding.protection_confirm.${confirmStep}_title`) : ''}
        body={confirmStep ? t(`onboarding.protection_confirm.${confirmStep}_body`) : ''}
        // a11y ist der komplizierte Step → reicher Explainer mit nummerierten
        // Schritten (erst Overlay erlauben, dann ReBreak-Schalter) + Screenshot
        // + Indikator. Die anderen Steps bleiben reiner Text.
        // Keine Text-Schritte mehr im a11y-Sheet — das passive ReBreak-Overlay führt
        // in den Settings Schritt für Schritt. Sheet bleibt dezent (Lyra-Satz + Bild).
        steps={undefined}
        screenshot={
          confirmStep === 'a11y'
            ? getPermissionScreenshot('android_a11y_overview', i18n.language || 'de')
            : undefined
        }
        indicatorCaption={
          confirmStep === 'a11y' ? t('onboarding.protection_confirm.a11y_indicator') : undefined
        }
        onClose={() => setConfirmStep(null)}
        onConfirm={() => {
          const step = confirmStep;
          setConfirmStep(null);
          // Erst Sheet schließen lassen, DANN die Permission feuern. Auf iOS kann
          // ein System-Dialog, der über ein noch wegslidendes Modal präsentiert
          // wird, still fehlschlagen — exakt die Bug-Klasse, die wir vermeiden wollen.
          if (step) setTimeout(() => runConfirmedAction(step), 350);
        }}
      />

      <PermissionDeniedSheet
        visible={permissionDeniedOpen}
        onClose={() => setPermissionDeniedOpen(false)}
        onRetry={async () => {
          const res = await protection.resetUrlFilter();
          if (res.enabled) await refresh();
          return res;
        }}
      />
      <PermissionDeniedSheet
        visible={familyControlsErrorOpen}
        onClose={() => setFamilyControlsErrorOpen(false)}
        variant="family_controls"
        onRetry={async () => {
          const res = await protection.activateFamilyControls();
          if (res.enabled) await refresh();
          return res;
        }}
      />
    </OnboardingShell>
  );
}
