import 'dart:async';

import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

import 'main.dart' show supabase;
import 'home_screen.dart';
import 'logged_home.dart';
import 'privacy_gate_prefs.dart';
import 'screens/privacy_gate_screen.dart';
import 'screens/terms_gate_screen.dart';
import 'terms_gate_prefs.dart';

final ValueNotifier<bool> forceHomeScreen = ValueNotifier<bool>(false);

/// Quando um cadastro (signUp) acabou de acontecer, guarda o uid da conta
/// nova aqui — o AuthGate mostra o [TermsGateScreen] em vez do LoggedHome
/// enquanto este valor corresponder à sessão ativa. É o primeiro dos dois
/// gates a ser mostrado, antes do [PrivacyGateScreen]. Aceitar limpa o
/// valor (avança para o próximo passo); recusar apaga a conta e termina a
/// sessão.
final ValueNotifier<String?> pendingTermsUserId = ValueNotifier<String?>(null);

/// Igual a [pendingTermsUserId], mas para o consentimento de privacidade
/// que o AuthGate mostra depois do TermsGateScreen.
final ValueNotifier<String?> pendingPrivacyUserId = ValueNotifier<String?>(
  null,
);

class AuthGate extends StatefulWidget {
  const AuthGate({super.key});

  @override
  State<AuthGate> createState() => _AuthGateState();
}

class _AuthGateState extends State<AuthGate> {
  String? _validatedUserId;
  String? _validatingUserId;

  @override
  void initState() {
    super.initState();
    _loadPendingTermsUid();
    _loadPendingPrivacyUid();
  }

  /// Recupera do disco o uid pendente de aceitação dos Termos (se existir),
  /// para o caso de o processo ter sido morto entre o cadastro e a
  /// aceitação — sem isto, reabrir a app perderia o estado "pendente" (que
  /// por defeito vive só em memória) e o gate seria ignorado.
  Future<void> _loadPendingTermsUid() async {
    final uid = await TermsGatePrefs.getPendingUid();
    if (uid != null && mounted) {
      pendingTermsUserId.value = uid;
    }
  }

  /// Igual a [_loadPendingTermsUid], para o consentimento de privacidade.
  Future<void> _loadPendingPrivacyUid() async {
    final uid = await PrivacyGatePrefs.getPendingUid();
    if (uid != null && mounted) {
      pendingPrivacyUserId.value = uid;
    }
  }

  /// Confirma que a sessão ativa ainda corresponde a um perfil existente na
  /// base de dados. Sessões do Supabase Auth sobrevivem mesmo que os dados
  /// da conta tenham sido apagados (ex.: "Apagar dados da conta" ou remoção
  /// manual na base de dados) — sem esta verificação, essa conta "fantasma"
  /// continuaria a conseguir entrar.
  Future<void> _validateSession(String userId) async {
    if (_validatingUserId == userId) return;
    _validatingUserId = userId;
    try {
      final profile = await supabase
          .from('profiles')
          .select('id')
          .eq('id', userId)
          .maybeSingle();

      if (!mounted) return;

      if (profile == null) {
        unawaited(
          supabase
              .from('children')
              .delete()
              .eq('owner_id', userId)
              .catchError((_) => <Map<String, dynamic>>[]),
        );
        await supabase.auth.signOut();
      } else {
        setState(() => _validatedUserId = userId);
      }
    } catch (_) {
      // Falha de rede/consulta: não força logout, tenta novamente depois.
    } finally {
      _validatingUserId = null;
    }
  }

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<bool>(
      valueListenable: forceHomeScreen,
      builder: (context, forcedHome, _) {
        return ValueListenableBuilder<String?>(
          valueListenable: pendingPrivacyUserId,
          builder: (context, pendingPrivacyUid, _) {
            return ValueListenableBuilder<String?>(
              valueListenable: pendingTermsUserId,
              builder: (context, pendingUid, _) {
                return StreamBuilder<AuthState>(
                  stream: supabase.auth.onAuthStateChange,
                  initialData: AuthState(AuthChangeEvent.initialSession, supabase.auth.currentSession),
                  builder: (context, snapshot) {
                    final user = snapshot.data?.session?.user;

                    if (user != null && user.id != _validatedUserId) {
                      WidgetsBinding.instance.addPostFrameCallback((_) {
                        if (mounted) _validateSession(user.id);
                      });
                    }

                    final Widget child;
                    if (snapshot.connectionState == ConnectionState.waiting) {
                      child = const SizedBox.shrink();
                    } else if (forcedHome || user == null || user.id != _validatedUserId) {
                      child = const HomeScreen(key: ValueKey('home_screen'));
                    } else if (pendingUid == user.id) {
                      child = TermsGateScreen(
                        key: const ValueKey('terms_gate_screen'),
                        userId: user.id,
                        onAccepted: () {
                          pendingTermsUserId.value = null;
                          TermsGatePrefs.clearPendingUid();
                        },
                      );
                    } else if (pendingPrivacyUid == user.id) {
                      child = PrivacyGateScreen(
                        key: const ValueKey('privacy_gate_screen'),
                        userId: user.id,
                        onAccepted: () {
                          pendingPrivacyUserId.value = null;
                          PrivacyGatePrefs.clearPendingUid();
                        },
                      );
                    } else {
                      child = const LoggedHomeScreen(key: ValueKey('logged_home_screen'));
                    }

                    return AnimatedSwitcher(
                      duration: const Duration(milliseconds: 280),
                      reverseDuration: const Duration(milliseconds: 240),
                      switchInCurve: Curves.easeOutCubic,
                      switchOutCurve: Curves.easeInCubic,
                      transitionBuilder: (child, animation) {
                        final fade = CurvedAnimation(parent: animation, curve: Curves.easeOut);
                        return FadeTransition(
                          opacity: fade,
                          child: ScaleTransition(
                            scale: Tween<double>(begin: 0.985, end: 1.0).animate(fade),
                            child: child,
                          ),
                        );
                      },
                      child: child,
                    );
                  },
                );
              },
            );
          },
        );
      },
    );
  }
}
