import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;

import '../../../core/config/app_environment_provider.dart';
import '../../../core/network/api_error.dart';
import '../data/auth_repository.dart';
import '../domain/auth_models.dart';
import '../../directory/presentation/directory_screen.dart';

class LoginScreen extends ConsumerStatefulWidget {
  const LoginScreen({super.key});

  static const routePath = '/login';

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

class _LoginScreenState extends ConsumerState<LoginScreen>
    with WidgetsBindingObserver {
  final _phoneController = TextEditingController();

  Timer? _pollTimer;
  Timer? _countdownTimer;

  var _isSubmitting = false;
  var _pollInFlight = false;
  String? _errorMessage;
  String? _statusMessage;
  PhoneLoginLinkInitResponse? _pendingLink;
  var _secondsUntilExpiry = 0;
  var _secondsUntilResend = 0;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    unawaited(_restorePendingLink());
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    _pollTimer?.cancel();
    _countdownTimer?.cancel();
    _phoneController.dispose();
    super.dispose();
  }

  bool get _hasPendingLink => _pendingLink != null;

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state != AppLifecycleState.resumed || !_hasPendingLink) {
      return;
    }
    _ensurePolling();
    unawaited(_pollPendingLink());
  }

  Future<void> _submit() async {
    final phoneNumber = _phoneController.text.trim();
    if (phoneNumber.isEmpty) {
      setState(() {
        _statusMessage = null;
        _errorMessage = '전화번호를 입력해 주세요.';
      });
      return;
    }

    setState(() {
      _isSubmitting = true;
      _pendingLink = null;
      _secondsUntilExpiry = 0;
      _secondsUntilResend = 0;
      _errorMessage = null;
      _statusMessage = '로그인 링크를 요청하고 있습니다.';
    });

    try {
      _pollTimer?.cancel();
      _countdownTimer?.cancel();
      await ref.read(authRepositoryProvider).clearPendingPhoneLoginLink();

      final response = await ref
          .read(authRepositoryProvider)
          .requestPhoneLoginLink(phoneNumber);
      if (!mounted) {
        return;
      }

      _startPendingLinkFlow(response);
      setState(() {
        _statusMessage = '문자 링크를 누른 뒤 TDC114PLUS 앱으로 돌아오세요.';
      });
    } catch (error) {
      if (!mounted) {
        return;
      }
      setState(() {
        _statusMessage = null;
        _errorMessage = '로그인 링크 요청 실패: ${_messageForError(error)}';
      });
    } finally {
      if (mounted) {
        setState(() => _isSubmitting = false);
      }
    }
  }

  Future<void> _restorePendingLink() async {
    final pendingLink = await ref
        .read(authRepositoryProvider)
        .loadPendingPhoneLoginLink();
    if (!mounted || pendingLink == null) {
      return;
    }
    setState(() {
      _pendingLink = pendingLink;
      _secondsUntilExpiry = pendingLink.expiresIn;
      _secondsUntilResend = pendingLink.resendAfter;
      _statusMessage = '이전 로그인 승인 상태를 확인하고 있습니다.';
      _errorMessage = null;
    });
    _startPendingTimers(pendingLink);
    unawaited(_pollPendingLink());
  }

  void _startPendingLinkFlow(PhoneLoginLinkInitResponse response) {
    _pollTimer?.cancel();
    _countdownTimer?.cancel();

    setState(() {
      _pendingLink = response;
      _secondsUntilExpiry = response.expiresIn;
      _secondsUntilResend = response.resendAfter;
    });

    _startPendingTimers(response);
  }

  void _startPendingTimers(PhoneLoginLinkInitResponse response) {
    _countdownTimer = Timer.periodic(const Duration(seconds: 1), (_) {
      if (!mounted) {
        return;
      }
      final nextExpiry = _secondsUntilExpiry > 0 ? _secondsUntilExpiry - 1 : 0;
      final nextResend = _secondsUntilResend > 0 ? _secondsUntilResend - 1 : 0;
      setState(() {
        _secondsUntilExpiry = nextExpiry;
        _secondsUntilResend = nextResend;
      });
      if (nextExpiry == 0) {
        _pollTimer?.cancel();
        _countdownTimer?.cancel();
        setState(() {
          _pendingLink = null;
          _statusMessage = null;
          _errorMessage = '로그인 링크 유효시간이 지났습니다. 다시 요청해 주세요.';
        });
        unawaited(
          ref.read(authRepositoryProvider).clearPendingPhoneLoginLink(),
        );
      }
    });

    _ensurePolling();
    unawaited(_pollPendingLink());
  }

  void _ensurePolling() {
    final pendingLink = _pendingLink;
    if (pendingLink == null || _pollTimer?.isActive == true) {
      return;
    }
    _pollTimer = Timer.periodic(
      Duration(seconds: pendingLink.interval.clamp(1, 30)),
      (_) => _pollPendingLink(),
    );
  }

  Future<void> _pollPendingLink() async {
    final pendingRef = _pendingLink?.pendingRef;
    if (pendingRef == null || _pollInFlight) {
      return;
    }

    _pollInFlight = true;
    try {
      final response = await ref
          .read(authRepositoryProvider)
          .pollPhoneLoginLink(pendingRef);
      if (!mounted) {
        return;
      }

      if (response.session != null) {
        _pollTimer?.cancel();
        _countdownTimer?.cancel();
        setState(() {
          _pendingLink = null;
          _statusMessage = '로그인이 완료되었습니다. 앱 화면으로 이동합니다.';
          _errorMessage = null;
        });
        if (mounted) {
          context.go(DirectoryScreen.routePath);
        }
        return;
      }

      if (response.isExpired) {
        _pollTimer?.cancel();
        _countdownTimer?.cancel();
        setState(() {
          _pendingLink = null;
          _statusMessage = null;
          _errorMessage = '로그인 링크 유효시간이 지났습니다. 다시 요청해 주세요.';
        });
        unawaited(
          ref.read(authRepositoryProvider).clearPendingPhoneLoginLink(),
        );
        return;
      }

      if (mounted) {
        setState(() {
          _errorMessage = null;
          _statusMessage = '문자 링크를 누른 뒤 TDC114PLUS 앱으로 돌아오세요.';
        });
      }

      final nextInterval = response.interval;
      if (nextInterval != null &&
          _pendingLink != null &&
          nextInterval != _pendingLink!.interval) {
        _pollTimer?.cancel();
        _pollTimer = Timer.periodic(
          Duration(seconds: nextInterval.clamp(1, 30)),
          (_) => _pollPendingLink(),
        );
        setState(() {
          _pendingLink = PhoneLoginLinkInitResponse(
            status: _pendingLink!.status,
            pendingRef: _pendingLink!.pendingRef,
            expiresIn: _secondsUntilExpiry,
            interval: nextInterval,
            resendAfter: _secondsUntilResend,
            provider: _pendingLink!.provider,
          );
        });
      }
    } catch (error) {
      if (!mounted) {
        return;
      }
      if (error is ApiException &&
          (error.code == 'pending_ref_not_found' ||
              error.code == 'pending_ref_expired')) {
        _pollTimer?.cancel();
        _countdownTimer?.cancel();
        unawaited(
          ref.read(authRepositoryProvider).clearPendingPhoneLoginLink(),
        );
        setState(() {
          _pendingLink = null;
          _secondsUntilExpiry = 0;
          _secondsUntilResend = 0;
          _statusMessage = null;
          _errorMessage = '이전 로그인 요청이 만료되었습니다. 다시 보내기를 눌러 주세요.';
        });
        return;
      }
      setState(() {
        _errorMessage = '승인 상태 확인 실패: ${_messageForError(error)}';
      });
    } finally {
      _pollInFlight = false;
    }
  }

  void _resetPendingState() {
    _pollTimer?.cancel();
    _countdownTimer?.cancel();
    unawaited(ref.read(authRepositoryProvider).clearPendingPhoneLoginLink());
    setState(() {
      _pendingLink = null;
      _secondsUntilExpiry = 0;
      _secondsUntilResend = 0;
      _statusMessage = null;
      _errorMessage = null;
    });
  }

  String _messageForError(Object error) {
    if (error is ApiException) {
      final message = error.apiError.error.trim();
      if (message.isNotEmpty) {
        return message;
      }
      if (error.code.isNotEmpty) {
        return error.code;
      }
      return '서버 응답 오류(${error.statusCode})';
    }
    if (error is TimeoutException) {
      return '서버 응답 시간이 초과되었습니다.';
    }
    if (error is SocketException || error is http.ClientException) {
      return '인증 서버에 연결하지 못했습니다.';
    }
    if (error is Exception &&
        error.toString().contains('invalid_phone_number')) {
      return '전화번호 형식을 확인해 주세요.';
    }
    return '로그인 링크를 처리하지 못했습니다. 잠시 후 다시 시도해 주세요.';
  }

  @override
  Widget build(BuildContext context) {
    final environment = ref.watch(appEnvironmentProvider);
    final buildTimestamp = environment.buildTimestamp.trim();
    final canResend = !_isSubmitting && _secondsUntilResend == 0;
    final keyboardInset = MediaQuery.viewInsetsOf(context).bottom;
    final keyboardVisible = keyboardInset > 0;
    const background = Color(0xFF030616);
    const surface = Color(0xFF10182A);
    const surfaceBorder = Color(0xFF1D2A44);
    const primary = Color(0xFFA8DEFF);
    const onDark = Color(0xFFE8F2FF);
    const muted = Color(0xFFA8B4C7);

    return Scaffold(
      backgroundColor: background,
      appBar: AppBar(
        backgroundColor: const Color(0xFF0E1729),
        foregroundColor: onDark,
        title: const Text('Baron SW 포털'),
        actions: const [
          Padding(
            padding: EdgeInsets.only(right: 16),
            child: Icon(Icons.dark_mode_outlined),
          ),
        ],
      ),
      bottomNavigationBar: keyboardVisible
          ? AnimatedPadding(
              duration: const Duration(milliseconds: 160),
              curve: Curves.easeOut,
              padding: EdgeInsets.only(bottom: keyboardInset),
              child: SafeArea(
                top: false,
                child: Container(
                  color: background,
                  padding: const EdgeInsets.fromLTRB(24, 10, 24, 12),
                  child: ConstrainedBox(
                    constraints: const BoxConstraints(maxWidth: 520),
                    child: _buildLoginLinkButton(canResend: canResend),
                  ),
                ),
              ),
            )
          : null,
      body: SafeArea(
        child: Center(
          child: SingleChildScrollView(
            padding: EdgeInsets.fromLTRB(24, 24, 24, keyboardVisible ? 96 : 24),
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 520),
              child: DecoratedBox(
                decoration: BoxDecoration(
                  color: surface,
                  border: Border.all(color: surfaceBorder),
                  borderRadius: BorderRadius.circular(24),
                  boxShadow: const [
                    BoxShadow(
                      color: Color(0x66000000),
                      blurRadius: 24,
                      offset: Offset(0, 16),
                    ),
                  ],
                ),
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(24, 28, 24, 24),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      const Text(
                        'TDC114PLUS',
                        textAlign: TextAlign.center,
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 28,
                          fontWeight: FontWeight.w900,
                          letterSpacing: 0,
                        ),
                      ),
                      const SizedBox(height: 6),
                      const Text(
                        'Baron SSO Login',
                        textAlign: TextAlign.center,
                        style: TextStyle(
                          color: muted,
                          fontSize: 13,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      const SizedBox(height: 24),
                      const CircleAvatar(
                        radius: 42,
                        backgroundColor: Color(0xFF26334C),
                        child: Icon(Icons.person, color: primary, size: 44),
                      ),
                      const SizedBox(height: 24),
                      Text(
                        '로그인 링크 발송',
                        textAlign: TextAlign.center,
                        style: Theme.of(context).textTheme.headlineSmall
                            ?.copyWith(
                              color: primary,
                              fontWeight: FontWeight.w800,
                            ),
                      ),
                      const SizedBox(height: 12),
                      const Text(
                        '문자 승인 후 앱으로 돌아오면 자동 로그인됩니다.',
                        textAlign: TextAlign.center,
                        style: TextStyle(color: muted, height: 1.5),
                      ),
                      if (buildTimestamp.isNotEmpty) ...[
                        const SizedBox(height: 8),
                        Text(
                          '빌드 시각: $buildTimestamp',
                          textAlign: TextAlign.center,
                          style: const TextStyle(
                            color: Color(0x99FFFFFF),
                            fontSize: 12,
                            fontWeight: FontWeight.w600,
                          ),
                        ),
                      ],
                      const SizedBox(height: 24),
                      DecoratedBox(
                        decoration: BoxDecoration(
                          color: const Color(0xFF0A5D43),
                          borderRadius: BorderRadius.circular(18),
                          border: Border.all(color: const Color(0xFF2FA977)),
                          boxShadow: const [
                            BoxShadow(
                              color: Color(0x553CD694),
                              blurRadius: 22,
                              offset: Offset(0, 10),
                            ),
                          ],
                        ),
                        child: Padding(
                          padding: const EdgeInsets.fromLTRB(18, 14, 18, 10),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.stretch,
                            children: [
                              Row(
                                children: [
                                  const Icon(
                                    Icons.phone_android,
                                    color: Colors.white,
                                    size: 44,
                                  ),
                                  const SizedBox(width: 14),
                                  Expanded(
                                    child: TextField(
                                      controller: _phoneController,
                                      enabled:
                                          !_hasPendingLink && !_isSubmitting,
                                      keyboardType: TextInputType.phone,
                                      inputFormatters: const [
                                        _PhoneNumberTextInputFormatter(),
                                      ],
                                      style: const TextStyle(
                                        color: Colors.white,
                                        fontSize: 24,
                                        fontWeight: FontWeight.w800,
                                        letterSpacing: 0,
                                      ),
                                      cursorColor: Colors.white,
                                      decoration: const InputDecoration(
                                        border: InputBorder.none,
                                        isDense: true,
                                        counterText: '',
                                        hintText: '010-0000-0000',
                                        hintStyle: TextStyle(
                                          color: Color(0x66FFFFFF),
                                          fontSize: 24,
                                          fontWeight: FontWeight.w800,
                                          letterSpacing: 0,
                                        ),
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                              const SizedBox(height: 8),
                              const Divider(
                                height: 1,
                                thickness: 3,
                                indent: 72,
                                endIndent: 12,
                                color: Color(0x553CD694),
                              ),
                              const SizedBox(height: 10),
                              const Text(
                                '문자 수신 가능한 전화번호를 입력하세요.',
                                textAlign: TextAlign.center,
                                style: TextStyle(
                                  color: Color(0xCCFFFFFF),
                                  fontSize: 13,
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                      if (_statusMessage != null) ...[
                        const SizedBox(height: 18),
                        Text(
                          _statusMessage!,
                          textAlign: TextAlign.center,
                          style: const TextStyle(color: primary, height: 1.5),
                        ),
                      ],
                      if (_errorMessage != null) ...[
                        const SizedBox(height: 12),
                        Text(
                          _errorMessage!,
                          textAlign: TextAlign.center,
                          style: const TextStyle(
                            color: Color(0xFFFF9CA3),
                            height: 1.5,
                          ),
                        ),
                      ],
                      if (_hasPendingLink) ...[
                        const SizedBox(height: 20),
                        _PendingLinkStatus(
                          expiresIn: _secondsUntilExpiry,
                          resendAfter: _secondsUntilResend,
                          provider: _pendingLink?.provider,
                        ),
                      ],
                      if (!keyboardVisible) ...[
                        const SizedBox(height: 24),
                        _buildLoginLinkButton(canResend: canResend),
                        if (_hasPendingLink) ...[
                          const SizedBox(height: 10),
                          OutlinedButton(
                            style: OutlinedButton.styleFrom(
                              foregroundColor: onDark,
                              side: const BorderSide(color: Color(0xFF34425C)),
                              minimumSize: const Size.fromHeight(48),
                              shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(14),
                              ),
                            ),
                            onPressed: _resetPendingState,
                            child: const Text('다른 번호 입력'),
                          ),
                        ],
                      ],
                    ],
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildLoginLinkButton({required bool canResend}) {
    const primary = Color(0xFFA8DEFF);
    return FilledButton.icon(
      style: FilledButton.styleFrom(
        backgroundColor: primary,
        foregroundColor: const Color(0xFF07101F),
        disabledBackgroundColor: const Color(0xFF314158),
        disabledForegroundColor: const Color(0xFF91A0B6),
        minimumSize: const Size.fromHeight(54),
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
      ),
      onPressed: _isSubmitting || (_hasPendingLink && !canResend)
          ? null
          : _submit,
      icon: _isSubmitting
          ? const SizedBox.square(
              dimension: 18,
              child: CircularProgressIndicator(strokeWidth: 2),
            )
          : Icon(_hasPendingLink ? Icons.refresh : Icons.link),
      label: Text(
        _isSubmitting
            ? '로그인 링크 요청 중'
            : _hasPendingLink
            ? '로그인 링크 다시 보내기'
            : '로그인 링크 보내기',
      ),
    );
  }
}

class _PhoneNumberTextInputFormatter extends TextInputFormatter {
  const _PhoneNumberTextInputFormatter();

  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    final digits = newValue.text.replaceAll(RegExp(r'[^0-9]'), '');
    final limited = digits.length > 11 ? digits.substring(0, 11) : digits;
    final formatted = _formatPhoneDigits(limited);
    return TextEditingValue(
      text: formatted,
      selection: TextSelection.collapsed(offset: formatted.length),
    );
  }

  String _formatPhoneDigits(String digits) {
    if (digits.length <= 3) {
      return digits;
    }
    if (digits.length <= 7) {
      return '${digits.substring(0, 3)}-${digits.substring(3)}';
    }
    return '${digits.substring(0, 3)}-${digits.substring(3, 7)}-${digits.substring(7)}';
  }
}

class _PendingLinkStatus extends StatelessWidget {
  const _PendingLinkStatus({
    required this.expiresIn,
    required this.resendAfter,
    required this.provider,
  });

  final int expiresIn;
  final int resendAfter;
  final String? provider;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: const Color(0xFF07101F),
        border: Border.all(color: const Color(0xFF263653)),
        borderRadius: BorderRadius.circular(14),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text(
            '승인 대기 중',
            style: TextStyle(
              color: Color(0xFFA8DEFF),
              fontSize: 16,
              fontWeight: FontWeight.w700,
            ),
          ),
          const SizedBox(height: 8),
          const Text(
            '문자 링크를 승인한 뒤 이 앱으로 돌아오면 자동으로 로그인됩니다.',
            style: TextStyle(color: Color(0xFFE8F2FF), height: 1.45),
          ),
          const SizedBox(height: 8),
          Text(
            '남은 유효시간: ${_formatDuration(expiresIn)}',
            style: const TextStyle(color: Color(0xFFA8B4C7)),
          ),
          Text(
            '재전송 가능까지: ${_formatDuration(resendAfter)}',
            style: const TextStyle(color: Color(0xFFA8B4C7)),
          ),
          if (provider != null && provider!.trim().isNotEmpty)
            Text(
              '인증 공급자: $provider',
              style: const TextStyle(color: Color(0xFFA8B4C7)),
            ),
        ],
      ),
    );
  }

  static String _formatDuration(int seconds) {
    final safeSeconds = seconds < 0 ? 0 : seconds;
    final minutes = safeSeconds ~/ 60;
    final remainingSeconds = safeSeconds % 60;
    return '${minutes.toString().padLeft(2, '0')}:${remainingSeconds.toString().padLeft(2, '0')}';
  }
}
