import { create } from 'zustand';
import { Platform } from 'react-native';
import type { Session, User } from '@supabase/supabase-js';
import * as WebBrowser from 'expo-web-browser';
import * as Linking from 'expo-linking';
import * as AppleAuthentication from 'expo-apple-authentication';
import { supabase } from '../lib/supabase';
import { apiFetch } from '../lib/api';
import i18n from '../lib/i18n';
import { syncLanguageFromUserMetadata } from './language';

const SUPPORTED_LOCALES = ['de', 'en', 'fr', 'ar'] as const;
type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];

function currentLocale(): SupportedLocale {
  const raw = (i18n.language ?? 'en').split('-')[0].toLowerCase();
  return (SUPPORTED_LOCALES as readonly string[]).includes(raw) ? (raw as SupportedLocale) : 'en';
}
import { invalidateMe } from '../hooks/useMe';
import { useDevicesStore } from './devices';
import { useDeviceLimitStore } from './deviceLimit';
import { useProtectedDevicesStore } from './protectedDevices';
import { useMailConsentStore } from './mailConsent';
import { useCommunityStore } from './community';
import { useCoachStore } from './coach';
import { useNotificationStore } from './notifications';
import { useMailConnectDraft } from './mailConnectDraft';
import { useLyraVoiceStore } from './lyraVoice';
import { useNotificationPrefsStore } from './notificationPrefs';

WebBrowser.maybeCompleteAuthSession();

export type DeviceLockedError = {
  type: 'DEVICE_LOCKED';
  lockedUntil: string | null;
  releaseRequestable: boolean;
};

type SignInResult = { error?: string; deviceLocked?: DeviceLockedError };

type AuthState = {
  user: User | null;
  session: Session | null;
  loading: boolean;

  init: () => Promise<void>;
  signInWithPassword: (email: string, password: string) => Promise<SignInResult>;
  signUp: (
    email: string,
    password: string,
    metadata: { username: string; avatarId: string; avatarUrl: string }
  ) => Promise<{ error?: string }>;
  signOut: () => Promise<void>;
  signInWithOAuth: (provider: 'google' | 'apple') => Promise<{ error?: string }>;
  resetPasswordForEmail: (email: string) => Promise<{ error?: string }>;
  verifyOtp: (email: string, token: string, type?: 'signup' | 'recovery') => Promise<{ error?: string }>;
  resendConfirmation: (email: string) => Promise<{ error?: string }>;
  updatePassword: (newPassword: string) => Promise<{ error?: string }>;
};

export const useAuthStore = create<AuthState>((set) => ({
  user: null,
  session: null,
  loading: true,

  init: async () => {
    const { data } = await supabase.auth.getSession();
    set({
      session: data.session,
      user: data.session?.user ?? null,
      loading: false,
    });
    if (data.session?.user) {
      void syncLanguageFromUserMetadata(data.session.user);
    }

    supabase.auth.onAuthStateChange((_event, session) => {
      set({ session, user: session?.user ?? null });
      if (session?.user) {
        void syncLanguageFromUserMetadata(session.user);
      }
    });
  },

  signInWithPassword: async (email, password) => {
    const { data, error } = await supabase.auth.signInWithPassword({ email, password });
    if (error) return { error: error.message };
    set({ session: data.session, user: data.user });

    // After Supabase auth succeeds, check device binding via the register endpoint.
    // If the device is already bound to a different account the backend returns 409
    // DEVICE_LOCKED. We sign back out of Supabase in that case — the user cannot
    // proceed on this device until the lock is released.
    // TODO(backend): move this check into POST /api/devices/register so it fires
    // automatically with x-device-id. Currently requires explicit call here.
    try {
      await apiFetch('/api/devices/check-lock', { method: 'POST' });
    } catch (e: any) {
      const msg: string = e?.message ?? '';
      const status = parseInt(msg.match(/^API (\d+)/)?.[1] ?? '0', 10);
      if (status === 409) {
        try {
          const raw = msg.replace(/^API \d+: /, '');
          const parsed = JSON.parse(raw);
          const lockData = parsed?.data ?? parsed;
          if (lockData?.error === 'DEVICE_LOCKED') {
            await supabase.auth.signOut();
            set({ session: null, user: null });
            return {
              deviceLocked: {
                type: 'DEVICE_LOCKED',
                lockedUntil: lockData.lockedUntil ?? null,
                releaseRequestable: lockData.releaseRequestable ?? true,
              },
            };
          }
        } catch {
          // JSON parse failed — not a DEVICE_LOCKED response, ignore
        }
      }
      // Non-409 errors from the check are non-fatal (device check is best-effort)
    }

    return {};
  },

  signUp: async (email, password, metadata) => {
    const { data, error } = await supabase.auth.signUp({
      email,
      password,
      options: {
        data: {
          username: metadata.username,
          avatar_id: metadata.avatarId,
          avatar_url: metadata.avatarUrl,
          locale: currentLocale(),
        },
        // Deep-link redirect for email confirmation — scheme registered in app.config.ts
        emailRedirectTo: 'rebreak://auth/confirm',
      },
    });
    if (error) return { error: error.message };
    set({ session: data.session, user: data.user ?? null });
    return {};
  },

  signOut: async () => {
    await supabase.auth.signOut();
    try {
      await WebBrowser.coolDownAsync();
    } catch {}

    useDevicesStore.getState().reset();
    useDeviceLimitStore.getState().reset();
    useProtectedDevicesStore.getState().reset();
    useMailConsentStore.getState().reset();
    useCommunityStore.getState().reset();
    useCoachStore.getState().reset();
    useNotificationStore.getState().reset();
    useMailConnectDraft.getState().reset();
    useLyraVoiceStore.getState().reset().catch(() => {});
    useNotificationPrefsStore.getState().reset().catch(() => {});
    invalidateMe();

    set({ session: null, user: null });
  },

  signInWithOAuth: async (provider) => {
    // Apple Sign-In native flow (iOS only) — KEIN Supabase-Apple-OAuth-Provider-
    // Config nötig (Bundle-ID = Apple-Client-ID). expo-apple-authentication
    // liefert identityToken → supabase.auth.signInWithIdToken verifiziert direkt
    // gegen Apple's public keys. App-Store-Submit-Pflicht weil Google-Sign-In
    // auch da ist (Apple Guideline 4.8).
    if (provider === 'apple') {
      if (Platform.OS !== 'ios') {
        return { error: 'Apple Sign-In ist nur auf iOS verfügbar.' };
      }
      const available = await AppleAuthentication.isAvailableAsync();
      if (!available) {
        return { error: 'Apple Sign-In auf diesem Gerät nicht verfügbar.' };
      }
      try {
        const credential = await AppleAuthentication.signInAsync({
          requestedScopes: [
            AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
            AppleAuthentication.AppleAuthenticationScope.EMAIL,
          ],
        });
        if (!credential.identityToken) {
          return { error: 'Apple identityToken fehlt.' };
        }
        const { data, error } = await supabase.auth.signInWithIdToken({
          provider: 'apple',
          token: credential.identityToken,
        });
        if (error) return { error: error.message };
        set({ session: data.session, user: data.user ?? null });
        return {};
      } catch (e: any) {
        // User-Cancel ist kein Error — leere Antwort.
        if (e?.code === 'ERR_REQUEST_CANCELED') return {};
        return { error: e?.message ?? 'Apple Sign-In fehlgeschlagen.' };
      }
    }

    const redirectUri = Linking.createURL('auth/callback');
    const { data, error } = await supabase.auth.signInWithOAuth({
      provider,
      options: {
        redirectTo: redirectUri,
        skipBrowserRedirect: true,
        // Google: prompt=select_account erzwingt den Account-Picker,
        // auch wenn der Browser noch eine aktive Google-Session hat.
        ...(provider === 'google' ? { queryParams: { prompt: 'select_account' } } : {}),
      },
    });

    if (error) return { error: error.message };
    if (!data.url) return { error: 'Kein OAuth-URL erhalten' };

    // Cleanup eines evtl. noch offenen WebBrowser-Sessions aus einem vorherigen,
    // abgebrochenen OAuth-Versuch — sonst wirft openAuthSessionAsync mit
    // „Another web browser is already open". Idempotent, safe auch wenn nichts
    // offen ist.
    try {
      await WebBrowser.dismissAuthSession();
    } catch {
      // ignore
    }

    const result = await WebBrowser.openAuthSessionAsync(data.url, redirectUri);

    if (result.type !== 'success') {
      return result.type === 'cancel' ? {} : { error: 'OAuth fehlgeschlagen' };
    }

    // Extract tokens from the deep-link URL fragment
    const url = result.url;
    const params = new URLSearchParams(url.split('#')[1] ?? url.split('?')[1] ?? '');
    const accessToken = params.get('access_token');
    const refreshToken = params.get('refresh_token');

    if (!accessToken || !refreshToken) {
      // Session may already be set via onAuthStateChange — check
      const { data: sessionData } = await supabase.auth.getSession();
      if (sessionData.session) {
        set({ session: sessionData.session, user: sessionData.session.user });
        return {};
      }
      return { error: 'Session konnte nicht gelesen werden' };
    }

    const { data: sessionData, error: sessionError } = await supabase.auth.setSession({
      access_token: accessToken,
      refresh_token: refreshToken,
    });

    if (sessionError) return { error: sessionError.message };
    set({ session: sessionData.session, user: sessionData.session?.user ?? null });
    return {};
  },

  resetPasswordForEmail: async (email) => {
    const { error } = await supabase.auth.resetPasswordForEmail(email, {
      redirectTo: 'rebreak://auth/reset-password',
    });
    if (error) return { error: error.message };
    return {};
  },

  verifyOtp: async (email, token, type = 'signup') => {
    const { data, error } = await supabase.auth.verifyOtp({
      email,
      token,
      type,
    });
    if (error) return { error: error.message };
    if (!data.session) return { error: 'Bestätigung fehlgeschlagen – bitte erneut versuchen.' };
    set({ session: data.session, user: data.user ?? null });
    return {};
  },

  resendConfirmation: async (email) => {
    const { error } = await supabase.auth.resend({ type: 'signup', email });
    if (error) return { error: error.message };
    return {};
  },

  updatePassword: async (newPassword) => {
    const { error } = await supabase.auth.updateUser({ password: newPassword });
    if (error) return { error: error.message };
    return {};
  },
}));
