import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:descope/descope.dart';
import 'package:go_router/go_router.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:qr_flutter/qr_flutter.dart';
import '../../../core/services/audit_service.dart';
import '../../../core/services/web_auth_integration.dart';
import '../../../core/services/auth_proxy_service.dart';
import '../../../core/notifiers/auth_notifier.dart';
import '../../profile/domain/notifiers/profile_notifier.dart';

class LoginScreen extends ConsumerStatefulWidget {
  final String? verificationToken;
  const LoginScreen({super.key, this.verificationToken});

  @override
  ConsumerState<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends ConsumerState<LoginScreen>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;
  final TextEditingController _linkIdController = TextEditingController();
  final TextEditingController _passwordLoginIdController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  String? _redirectUrl;

  // QR Login Variables
  String? _qrImageBase64;
  String? _qrPendingRef;
  bool _isQrLoading = false;
  Timer? _qrPollingTimer;
  int _qrRemainingSeconds = 0;
  Timer? _qrCountdownTimer;

  @override
  void initState() {
    super.initState();
    // 탭 컨트롤러: 3개 탭, 기본 선택은 두 번째 탭("로그인 링크")
    _tabController = TabController(length: 3, vsync: this, initialIndex: 1);
    _tabController.addListener(_handleTabSelection);
    
    // Check for tokens (Path Parameter or Legacy Query Parameter)
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (widget.verificationToken != null) {
        _verifyToken(widget.verificationToken!);
      } else {
        final uri = Uri.base;
        if (uri.queryParameters.containsKey('t')) {
          _verifyToken(uri.queryParameters['t']!);
        }
      }

      final uri = Uri.base;
      if (uri.queryParameters.containsKey('redirect_url')) {
        _redirectUrl = uri.queryParameters['redirect_url'];
      }
    });
  }

  // Helper to decode JWT and get loginId
  String _getLoginIdFromJwt(String jwt) {
    try {
      final parts = jwt.split('.');
      if (parts.length != 3) return 'User';
      
      final payload = utf8.decode(base64Url.decode(base64Url.normalize(parts[1])));
      final data = json.decode(payload);
      // Descope tokens usually have 'name', 'email', or 'sub'
      return data['name'] ?? data['email'] ?? data['sub'] ?? 'User';
    } catch (e) {
      debugPrint("[JWT] Decode error: $e");
      return 'User';
    }
  }

  // Helper to decode JWT and get User ID (sub claim)
  String _getUserIdFromJwt(String jwt) {
    try {
      final parts = jwt.split('.');
      if (parts.length != 3) return 'unknown';
      final payload = utf8.decode(base64Url.decode(base64Url.normalize(parts[1])));
      final data = json.decode(payload) as Map<String, dynamic>;
      return data['sub'] as String? ?? 'unknown';
    } catch (e) {
      debugPrint("[JWT] Could not extract User ID (sub): $e");
      return 'unknown';
    }
  }

  void _handleTabSelection() {
    // QR 탭 (세 번째 탭, index 2)이 선택되었을 때 QR 플로우 시작
    if (_tabController.index == 2 && _qrPendingRef == null) {
      _startQrFlow();
    } else if (_tabController.index != 2) {
      _stopQrPolling();
    }
  }

  Future<void> _startQrFlow() async {
    if (_isQrLoading) return;
    setState(() {
      _isQrLoading = true;
      _qrImageBase64 = null;
      _qrRemainingSeconds = 0;
    });

    try {
      final res = await AuthProxyService.initQrLogin();
      if (mounted) {
        setState(() {
          _qrImageBase64 = res['qrCode'];
          _qrPendingRef = res['pendingRef'];
          _qrRemainingSeconds = res['expiresIn'] ?? 300;
          _isQrLoading = false;
        });
        _startQrPolling();
        _startCountdown();
      }
    } catch (e) {
      _showError("Failed to init QR: $e");
      if (mounted) setState(() => _isQrLoading = false);
    }
  }

  void _startCountdown() {
    _qrCountdownTimer?.cancel();
    _qrCountdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (!mounted || _qrRemainingSeconds <= 0) {
        timer.cancel();
        if (_qrRemainingSeconds <= 0) _stopQrPolling();
        return;
      }
      setState(() {
        _qrRemainingSeconds--;
      });
    });
  }

  void _startQrPolling() {
    _qrPollingTimer?.cancel();
    _qrPollingTimer = Timer.periodic(const Duration(milliseconds: 1500), (timer) async {
      if (_qrPendingRef == null || !mounted || _qrRemainingSeconds <= 0) {
        timer.cancel();
        return;
      }

      try {
        final res = await AuthProxyService.pollQrStatus(_qrPendingRef!);
        if (res['status'] == 'ok' && res['sessionJwt'] != null) {
          timer.cancel();
          _qrCountdownTimer?.cancel();
          
          final jwt = res['sessionJwt'];
          final displayName = _getLoginIdFromJwt(jwt);
          // Create User & Session for Descope SDK
          final dummyUser = DescopeUser(
              'unknown', // userId
              [],        // loginIds
              0,         // createdAt
              displayName, // name
              null,      // picture (Uri?)
              '',        // email
              false,     // isVerifiedEmail
              '',        // phone
              false,     // isVerifiedPhone
              {},        // customAttributes
              '',        // givenName
              '',        // middleName
              '',        // familyName
              false,     // hasPassword
              'enabled', // status
              [],        // roleNames
              [],        // ssoAppIds
              [],        // oauthProviders (List<String>)
            );
          final session = DescopeSession.fromJwt(jwt, jwt, dummyUser);
          Descope.sessionManager.manageSession(session);

          _onLoginSuccess(jwt);
        }
      } catch (e) {
        debugPrint("[QR] Polling error: $e");
      }
    });
  }

  void _stopQrPolling() {
    _qrPollingTimer?.cancel();
    _qrPollingTimer = null;
    _qrCountdownTimer?.cancel();
    _qrCountdownTimer = null;
    _qrPendingRef = null;
  }

  String _formatTime(int seconds) {
    final m = seconds ~/ 60;
    final s = seconds % 60;
    return "${m.toString().padLeft(2, '0')}:${s.toString().padLeft(2, '0')}";
  }

  Future<void> _verifyToken(String token) async {
    debugPrint("[Auth] Starting verification for token: $token");
    try {
      // Use Backend to verify the token (Backend-Driven Flow)
      final res = await AuthProxyService.verifyMagicLink(token);
      final jwt = res['token'];
      debugPrint("[Auth] Verification successful for token: $token");
      
      if (jwt != null && mounted) {
        final displayName = _getLoginIdFromJwt(jwt);
        // Create User & Session for Descope SDK to log in this tab
        final dummyUser = DescopeUser(
          'unknown', [], 0, displayName, null, '', false, '', false, {}, '', '', '', false, 'enabled', [], [], [],
        );
        final session = DescopeSession.fromJwt(jwt, jwt, dummyUser);
        // Refresh Token을 LocalStorage에 저장
        Descope.sessionManager.manageSession(session);
        
        // Notify and Go to Dashboard
        _onLoginSuccess(jwt);
      }
    } catch (e) {
      debugPrint("[Auth] Verification FAILED for token: $token. Error: $e");
      if (mounted) {
        _showError("Verification failed: $e");
      }
    }
  }

  @override
  void dispose() {
    _stopQrPolling();
    _tabController.dispose();
    _linkIdController.dispose();
    _passwordLoginIdController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  // 이메일/비밀번호 로그인 처리
  Future<void> _handlePasswordLogin() async {
    final input = _passwordLoginIdController.text.trim();
    final password = _passwordController.text.trim();
    if (input.isEmpty || password.isEmpty) {
      _showError("이메일(또는 전화번호)와 비밀번호를 모두 입력해주세요.");
      return;
    }

    String loginId = input;
    if (!input.contains('@')) {
      // Format phone number if it's not an email
      loginId = input.replaceAll(RegExp(r'[-\s]'), '');
      if (loginId.startsWith('010')) {
        loginId = '+82${loginId.substring(1)}';
      }
    }

    // 로딩 인디케이터 표시
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) => const Center(child: CircularProgressIndicator()),
    );

    try {
      final res = await AuthProxyService.loginWithPassword(loginId, password);
      final jwt = res['sessionJwt'];
      if (jwt != null && mounted) {
        Navigator.of(context).pop(); // 로딩 닫기
        _onLoginSuccess(jwt);
      }
    } catch (e) {
      if (mounted) Navigator.of(context).pop(); // 로딩 닫기
      if (e.toString().contains("User not registered")) {
        _showUnregisteredDialog();
      } else {
        _showError("로그인 실패: ${e.toString().replaceFirst("Exception: ", "")}");
      }
    }
  }

  // 로그인 링크 전송 처리
  Future<void> _handleLinkLogin() async {
    final input = _linkIdController.text.trim();
    if (input.isEmpty) return;

    String loginId = input;
    if (!input.contains('@')) {
      // Format phone number if it's not an email
      loginId = input.replaceAll(RegExp(r'[-\s]'), '');
      if (loginId.startsWith('010')) {
        loginId = '+82${loginId.substring(1)}';
      }
    }
    
    debugPrint("[Auth] Initiating Enchanted Link for: $loginId");
    
    // 링크 전송 전 사용자 존재 여부 체크 (백엔드에서 이미 처리하지만 에러 핸들링을 위해)
    try {
      await _startEnchantedFlow(loginId, isEmail: input.contains('@'));
    } catch (e) {
      if (e.toString().contains("User not registered")) {
        _showUnregisteredDialog();
      } else {
        _showError("오류: $e");
      }
    }
  }

  Future<void> _startEnchantedFlow(String loginId, {required bool isEmail}) async {
    try {
      if (mounted) {
        showDialog(
          context: context,
          barrierDismissible: false,
          builder: (context) => const Center(child: CircularProgressIndicator()),
        );
      }

      // 1. Init via Backend API
      final initResponse = await AuthProxyService.initEnchantedLink(loginId);
      final pendingRef = initResponse['pendingRef'];
      debugPrint("[Auth] Link Sent. PendingRef: $pendingRef");

      if (mounted) {
        Navigator.of(context).pop(); // Close Loading

        showDialog(
          context: context,
          barrierDismissible: false,
          builder: (context) => AlertDialog(
            title: Text(isEmail ? "이메일 전송됨" : "SMS 전송됨"),
            content: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(isEmail 
                  ? "입력하신 이메일로 로그인 링크를 보냈습니다." 
                  : "입력하신 번호로 로그인 링크를 보냈습니다."),
                const SizedBox(height: 16),
                const LinearProgressIndicator(),
                const SizedBox(height: 16),
                TextButton(
                  onPressed: () {
                    debugPrint("[Auth] Polling canceled by user");
                    Navigator.of(context).pop();
                  }, 
                  child: const Text("취소")
                )
              ],
            ),
          ),
        );

        // 2. Poll Backend manually
        _pollForSession(pendingRef);
      }
    } catch (e) {
      debugPrint("[Auth] Initialization failed: $e");
      if (mounted && Navigator.canPop(context)) Navigator.of(context).pop();
      if (e.toString().contains("User not registered")) {
        _showUnregisteredDialog();
      } else {
        _showError("전송 실패: $e");
      }
    }
  }

  Future<void> _pollForSession(String pendingRef) async {
    int attempts = 0;
    const maxAttempts = 60; // 2 minutes
    debugPrint("[Auth] Starting poll for ref: $pendingRef");

    while (attempts < maxAttempts && mounted) {
      await Future.delayed(const Duration(seconds: 2));
      attempts++;

      try {
        final result = await AuthProxyService.pollEnchantedLink(pendingRef);
        
        if (result['status'] == 'ok') {
          final jwt = result['sessionJwt'];
          if (jwt != null) {
            debugPrint("[Auth] Polling SUCCESS. Token received.");
            
            final displayName = _getLoginIdFromJwt(jwt);
            // Descope SDK 세션 강제 주입
            final dummyUser = DescopeUser(
              'unknown', [], 0, displayName, null, '', false, '', false, {}, '', '', '', false, 'enabled', [], [], [],
            );
            final session = DescopeSession.fromJwt(jwt, jwt, dummyUser);
            Descope.sessionManager.manageSession(session);

            if (mounted) {
               Navigator.of(context).pop(); // Close Polling Dialog
               _onLoginSuccess(jwt);
            }
            return;
          }
        }
      } catch (e) {
        debugPrint("[Auth] Polling error (attempt $attempts): $e");
      }
    }

    if (mounted) {
      debugPrint("[Auth] Polling timed out for ref: $pendingRef");
      Navigator.of(context).pop(); // Close Polling Dialog
      _showError("Login timed out.");
    }
  }

  void _showError(String message) {
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message), backgroundColor: Colors.red),
    );
    try {
      AuthProxyService.logError(message);
    } catch (e) {
      // ignore
    }
  }

  void _logTokenDetails(String jwt) {
    try {
      final parts = jwt.split('.');
      if (parts.length != 3) return;

      final decodedPayload = base64Url.decode(base64Url.normalize(parts[1]));
      final payloadJson = utf8.decode(decodedPayload);
      final data = json.decode(payloadJson) as Map<String, dynamic>;
      
      final accessExpValue = data['exp'] as num?;
      final accessExp = accessExpValue != null
          ? DateTime.fromMillisecondsSinceEpoch(accessExpValue.toInt() * 1000)
          : 'N/A';
      final refreshExp = data['rexp'] ?? 'N/A';

      debugPrint("""
      [Auth] Session Token Details ---
        - Access Token Expires: $accessExp
        - Refresh Token Expires: $refreshExp
      """);
    } catch (e) {
      debugPrint("[Auth] Failed to decode or log token details: $e");
    }
  }

  void _onLoginSuccess(String token) async {
    if (!mounted) return;
    
    _logTokenDetails(token);

    final userId = _getUserIdFromJwt(token);

    // [New] 로그인 성공 직후 백엔드에서 전체 프로필 정보를 가져와 세션 업데이트
    try {
      // 임시 세션 생성 (API 호출을 위해)
      final tempUser = DescopeUser(userId, [], 0, 'User', null, '', false, '', false, {}, '', '', '', false, 'enabled', [], [], []);
      final tempSession = DescopeSession.fromJwt(token, token, tempUser);
      Descope.sessionManager.manageSession(tempSession);

      // 백엔드 GetMe 호출 (프로필 노티파이어 사용)
      final profile = await ref.read(profileProvider.notifier).loadProfile();
      if (profile != null) {
        // 실제 정보로 세션 유저 정보 교체
        final realUser = DescopeUser(
          userId, [], 0, profile.name, null, profile.email, false, profile.phone, false, {}, '', '', '', false, 'enabled', [], [], [],
        );
        final realSession = DescopeSession.fromJwt(token, token, realUser);
        Descope.sessionManager.manageSession(realSession);
      }
    } catch (e) {
      debugPrint("[Auth] Failed to pre-fetch profile: $e");
    }

    // Record Audit Log
    AuditService.logEvent(
      userId: userId,
      eventType: "LOGIN_SUCCESS",
      status: "SUCCESS",
      details: "User logged in via Baron SSO",
    );

    // 1. Handle Popup Flow
    if (WebAuthIntegration.isPopup()) {
      debugPrint("[Auth] Popup detected. Notifying opener and attempting to close.");
      WebAuthIntegration.sendLoginSuccess(token);
    } else {
      // 2. Handle Redirect Flow
      if (_redirectUrl != null && _redirectUrl!.isNotEmpty) {
        debugPrint("[Auth] Redirecting standalone window to: $_redirectUrl");
        final target = "$_redirectUrl?token=$token";
        launchUrlString(target, webOnlyWindowName: '_self');
        return;
      }
    }

    // 3. Standalone mode / Fallback
    debugPrint("[Auth] Login success. Navigating to root.");
    AuthNotifier.instance.notify();
    if (mounted) {
      context.go('/');
    }
  }

  // [New] 미등록 회원 안내 팝업
  void _showUnregisteredDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text("미등록 회원"),
        content: const Text("가입되지 않은 정보입니다.\n회원가입 후 이용해 주세요."),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text("취소"),
          ),
          FilledButton(
            onPressed: () {
              Navigator.pop(context);
              context.push('/signup');
            },
            child: const Text("회원가입 하기"),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: LayoutBuilder(
        builder: (context, constraints) {
          return SingleChildScrollView(
            child: ConstrainedBox(
              constraints: BoxConstraints(minHeight: constraints.maxHeight),
              child: Center(
                child: Container(
                  constraints: const BoxConstraints(maxWidth: 400),
                  padding: const EdgeInsets.all(24),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      Text(
                        "Baron SSO",
                        style: GoogleFonts.outfit(
                          fontSize: 32,
                          fontWeight: FontWeight.bold,
                        ),
                        textAlign: TextAlign.center,
                      ),
                      const SizedBox(height: 40),

                      TabBar(
                        controller: _tabController,
                        tabs: const [
                          Tab(text: "비밀번호"),
                          Tab(text: "로그인 링크"),
                          Tab(text: "QR 코드"),
                        ],
                      ),
                      const SizedBox(height: 24),

                      SizedBox(
                        height: 350,
                        child: TabBarView(
                          controller: _tabController,
                          children: [
                            // 1. 이메일/비밀번호 로그인 폼
                            Padding(
                              padding: const EdgeInsets.only(top: 16.0),
                              child: Column(
                                children: [
                                  TextField(
                                    controller: _passwordLoginIdController,
                                    decoration: const InputDecoration(
                                      labelText: "이메일 또는 휴대폰 번호",
                                      border: OutlineInputBorder(),
                                      prefixIcon: Icon(Icons.person_outline),
                                    ),
                                    onSubmitted: (_) => _handlePasswordLogin(),
                                  ),
                                  const SizedBox(height: 16),
                                  TextField(
                                    controller: _passwordController,
                                    obscureText: true,
                                    decoration: const InputDecoration(
                                      labelText: "비밀번호",
                                      border: OutlineInputBorder(),
                                      prefixIcon: Icon(Icons.lock_outline),
                                    ),
                                    onSubmitted: (_) => _handlePasswordLogin(),
                                  ),
                                  const SizedBox(height: 24),
                                  FilledButton(
                                    onPressed: _handlePasswordLogin,
                                    style: FilledButton.styleFrom(
                                      minimumSize: const Size.fromHeight(50),
                                    ),
                                    child: const Text("로그인"),
                                  ),
                                ],
                              ),
                            ),
                            
                            // 2. 로그인 링크 전송 폼
                            Padding(
                              padding: const EdgeInsets.only(top: 16.0),
                              child: Column(
                                children: [
                                  TextField(
                                    controller: _linkIdController,
                                    decoration: const InputDecoration(
                                      labelText: "이메일 또는 휴대폰 번호",
                                      hintText: "",
                                      border: OutlineInputBorder(),
                                      prefixIcon: Icon(Icons.person_outline),
                                    ),
                                    onSubmitted: (_) => _handleLinkLogin(),
                                  ),
                                  const SizedBox(height: 24),
                                  FilledButton(
                                    onPressed: _handleLinkLogin,
                                    style: FilledButton.styleFrom(
                                      minimumSize: const Size.fromHeight(50),
                                    ),
                                    child: const Text("로그인 링크 전송"),
                                  ),
                                  const SizedBox(height: 24),
                                  const Text(
                                    "입력하신 정보로 로그인 링크를 전송합니다.",
                                    style: TextStyle(color: Colors.grey, fontSize: 12),
                                    textAlign: TextAlign.center,
                                  ),
                                ],
                              ),
                            ),

                            // 3. QR 로그인 뷰
                            Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              crossAxisAlignment: CrossAxisAlignment.center,
                              children: [
                                if (_isQrLoading)
                                  const CircularProgressIndicator()
                                else if (_qrImageBase64 != null)
                                  Column(
                                    crossAxisAlignment: CrossAxisAlignment.center,
                                    children: [
                                      Container(
                                        padding: const EdgeInsets.all(16),
                                        decoration: BoxDecoration(
                                          border: Border.all(color: Colors.grey.shade300),
                                          borderRadius: BorderRadius.circular(12),
                                        ),
                                        child: QrImageView(
                                          data: _qrImageBase64!,
                                          version: QrVersions.auto,
                                          size: 200.0,
                                        ),
                                      ),
                                      const SizedBox(height: 12),
                                      Text(
                                        _qrRemainingSeconds > 0 
                                          ? "남은 시간: ${_formatTime(_qrRemainingSeconds)}"
                                          : "QR 코드 만료됨",
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                          color: _qrRemainingSeconds > 30 ? Colors.blue : Colors.red,
                                          fontWeight: FontWeight.bold,
                                        ),
                                      ),
                                      const SizedBox(height: 8),
                                      const Text(
                                        "모바일 앱으로 스캔하세요",
                                        textAlign: TextAlign.center,
                                        style: TextStyle(color: Colors.grey, fontSize: 12),
                                      ),
                                      TextButton(
                                        onPressed: _startQrFlow, 
                                        child: const Text("QR 코드 새로고침")
                                      ),
                                    ],
                                  )
                                else
                                  const Text("QR 코드를 불러오지 못했습니다.", textAlign: TextAlign.center),
                              ],
                            ),
                          ],
                        ),
                      ),
                      const SizedBox(height: 16),
                      Column(
                        children: [
                          TextButton(
                            onPressed: () => context.push('/forgot-password'),
                            child: const Text("비밀번호를 잊으셨나요?"),
                          ),
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              const Text("계정이 없으신가요?", style: TextStyle(color: Colors.grey, fontSize: 14)),
                              TextButton(
                                onPressed: () => context.push('/signup'),
                                child: const Text("회원가입"),
                              ),
                            ],
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}