import 'dart:async';

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_remix/flutter_remix.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:url_launcher/url_launcher_string.dart';

import '../../../common/config/app_h5_urls.dart';
import '../../../common/network/api_error_message.dart';
import '../../../common/router/app_router.dart';
import '../../../common/theme/spacing.dart';
import '../../../common/widgets/circle_back_button.dart';
import '../application/auth_controller.dart';

class LoginPage extends HookConsumerWidget {
  const LoginPage({super.key, this.next});
  final String? next;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final cs = ShadTheme.of(context).colorScheme;
    final phone = useTextEditingController();
    final codeCtrl = useTextEditingController();
    final codeFocus = useFocusNode();
    final onCodeStep = useState(false);
    final agreed = useState(false);
    final sending = useState(false);
    final verifying = useState(false);
    final countdown = useState(0);
    final error = useState<String?>(null);
    final timer = useRef<Timer?>(null);
    useListenable(phone);
    useListenable(codeCtrl);
    useEffect(
      () =>
          () => timer.value?.cancel(),
      const [],
    );

    String phoneDigits() => phone.text.replaceAll(RegExp(r'\D'), '');

    Future<void> returnAfterLogin() async {
      final target = next?.trim();
      final router = GoRouter.of(context);
      if (target == null || target.isEmpty) {
        router.go(AppRoutes.profile);
        return;
      }
      router.go(target);
    }

    void startCountdown() {
      countdown.value = 60;
      timer.value?.cancel();
      timer.value = Timer.periodic(const Duration(seconds: 1), (t) {
        if (countdown.value <= 1) {
          t.cancel();
          countdown.value = 0;
        } else {
          countdown.value--;
        }
      });
    }

    Future<void> doSend() async {
      if (sending.value || countdown.value > 0) return;
      if (phoneDigits().length != 11) {
        error.value = '请输入正确的手机号';
        return;
      }
      sending.value = true;
      error.value = null;
      try {
        await ref.read(authProvider.notifier).sendCode(phoneDigits());
        startCountdown();
        onCodeStep.value = true;
        codeFocus.requestFocus();
      } catch (e) {
        error.value = kratosDisplayMessage(e, fallback: '发送失败，请稍后重试');
      } finally {
        sending.value = false;
      }
    }

    Future<void> doVerify() async {
      if (verifying.value) return;
      final code = codeCtrl.text.trim();
      if (code.length != 6) {
        error.value = '请输入 6 位验证码';
        return;
      }
      verifying.value = true;
      error.value = null;
      try {
        await ref.read(authProvider.notifier).verifyCode(phoneDigits(), code);
        if (!context.mounted) return;
        await returnAfterLogin();
      } catch (e) {
        error.value = kratosDisplayMessage(e, fallback: '验证失败，请重试');
      } finally {
        verifying.value = false;
      }
    }

    void onBack() {
      if (onCodeStep.value) {
        onCodeStep.value = false;
        error.value = null;
      } else if (context.canPop()) {
        context.pop();
      } else {
        context.go(AppRoutes.profile);
      }
    }

    void showPrivacySheet(VoidCallback onAgreed) {
      showModalBottomSheet<void>(
        context: context,
        backgroundColor: cs.card,
        barrierColor: Colors.black.withValues(alpha: 0.6),
        shape: const RoundedRectangleBorder(
          borderRadius: BorderRadius.vertical(
            top: Radius.circular(Spacing.radiusCard),
          ),
        ),
        builder: (ctx) => SafeArea(
          child: Padding(
            padding: const EdgeInsets.fromLTRB(22, 28, 22, 24),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  '请阅读并同意以下条款',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.w600,
                    color: cs.foreground,
                  ),
                ),
                const SizedBox(height: 14),
                Text.rich(
                  textAlign: TextAlign.center,
                  _policySpan(context, cs, fontSize: 12.5),
                ),
                const SizedBox(height: 22),
                _PrimaryButton(
                  label: '同意并继续',
                  enabled: true,
                  onTap: () {
                    Navigator.of(ctx).pop();
                    onAgreed();
                  },
                ),
              ],
            ),
          ),
        ),
      );
    }

    void onSendTap() {
      if (sending.value || countdown.value > 0) return;
      if (phoneDigits().length != 11) {
        error.value = '请输入正确的手机号';
        return;
      }
      error.value = null;
      if (!agreed.value) {
        showPrivacySheet(() {
          agreed.value = true;
          doSend();
        });
        return;
      }
      doSend();
    }

    final phoneReady = phoneDigits().length == 11;
    final codeReady = codeCtrl.text.trim().length == 6;

    return Scaffold(
      backgroundColor: cs.background,
      appBar: AppBar(
        backgroundColor: cs.background,
        surfaceTintColor: Colors.transparent,
        elevation: 0,
        scrolledUnderElevation: 0,
        automaticallyImplyLeading: false,
        toolbarHeight: 46,
        titleSpacing: 0,
        title: CircleBackButton(onTap: onBack),
      ),
      body: SafeArea(
        top: false,
        child: SingleChildScrollView(
          padding: const EdgeInsets.fromLTRB(22, 8, 22, 28),
          child: onCodeStep.value
              ? _CodeStep(
                  cs: cs,
                  phone: phoneDigits(),
                  codeCtrl: codeCtrl,
                  codeFocus: codeFocus,
                  countdown: countdown.value,
                  verifying: verifying.value,
                  codeReady: codeReady,
                  error: error.value,
                  onVerify: doVerify,
                  onResend: doSend,
                )
              : _PhoneStep(
                  cs: cs,
                  phone: phone,
                  sending: sending.value,
                  countdown: countdown.value,
                  phoneReady: phoneReady,
                  error: error.value,
                  agreed: agreed.value,
                  onToggleAgreed: () => agreed.value = !agreed.value,
                  onSend: onSendTap,
                ),
        ),
      ),
    );
  }
}

class _PhoneStep extends StatelessWidget {
  const _PhoneStep({
    required this.cs,
    required this.phone,
    required this.sending,
    required this.countdown,
    required this.phoneReady,
    required this.agreed,
    required this.onToggleAgreed,
    required this.error,
    required this.onSend,
  });

  final ShadColorScheme cs;
  final TextEditingController phone;
  final bool sending;
  final int countdown;
  final bool phoneReady;
  final bool agreed;
  final VoidCallback onToggleAgreed;
  final String? error;
  final VoidCallback onSend;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        _SheetTitle('手机号登录', cs),
        const SizedBox(height: 8),
        _SheetSub('未注册的手机号验证后将自动创建研听账号。', cs),
        const SizedBox(height: 18),
        Row(
          children: [
            SizedBox(
              height: 50,
              child: Center(
                child: Text(
                  '+86',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.w600,
                    color: cs.foreground,
                    fontFeatures: const [FontFeature.tabularFigures()],
                  ),
                ),
              ),
            ),
            const SizedBox(width: 10),
            Expanded(
              child: _BoxedField(controller: phone, hint: '请输入手机号', cs: cs),
            ),
          ],
        ),
        if (error != null) ...[
          const SizedBox(height: 10),
          _ErrorText(error!, cs),
        ],
        const SizedBox(height: 18),
        _PrimaryButton(
          label: countdown > 0 ? '$countdown s 后可重新发送' : '获取验证码',
          enabled: !sending && countdown == 0,
          loading: sending,
          dim: !phoneReady,
          onTap: onSend,
        ),
        const SizedBox(height: 18),
        _AgreeRow(agreed: agreed, onToggle: onToggleAgreed, cs: cs),
      ],
    );
  }
}

class _CodeStep extends StatelessWidget {
  const _CodeStep({
    required this.cs,
    required this.phone,
    required this.codeCtrl,
    required this.codeFocus,
    required this.countdown,
    required this.verifying,
    required this.codeReady,
    required this.error,
    required this.onVerify,
    required this.onResend,
  });

  final ShadColorScheme cs;
  final String phone;
  final TextEditingController codeCtrl;
  final FocusNode codeFocus;
  final int countdown;
  final bool verifying;
  final bool codeReady;
  final String? error;
  final VoidCallback onVerify;
  final VoidCallback onResend;

  String get _masked => phone.length == 11
      ? '${phone.substring(0, 3)}****${phone.substring(7)}'
      : phone;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        _SheetTitle('输入验证码', cs),
        const SizedBox(height: 8),
        _SheetSub('验证码已发送至 +86 $_masked', cs),
        const SizedBox(height: 20),
        _OtpInput(controller: codeCtrl, focusNode: codeFocus, cs: cs),
        if (error != null) ...[
          const SizedBox(height: 12),
          _ErrorText(error!, cs),
        ],
        const SizedBox(height: 18),
        _PrimaryButton(
          label: '验证并登录',
          enabled: !verifying,
          loading: verifying,
          dim: !codeReady,
          onTap: onVerify,
        ),
        const SizedBox(height: 16),
        Center(
          child: GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: countdown > 0 ? null : onResend,
            child: Text(
              countdown > 0 ? '$countdown s 后可重新发送' : '重新发送',
              style: TextStyle(
                fontSize: 13,
                color: countdown > 0 ? cs.mutedForeground : cs.primary,
              ),
            ),
          ),
        ),
      ],
    );
  }
}

class _SheetTitle extends StatelessWidget {
  const _SheetTitle(this.text, this.cs);
  final String text;
  final ShadColorScheme cs;
  @override
  Widget build(BuildContext context) => Text(
    text,
    style: TextStyle(
      fontSize: 19,
      fontWeight: FontWeight.w700,
      color: cs.foreground,
    ),
  );
}

class _SheetSub extends StatelessWidget {
  const _SheetSub(this.text, this.cs);
  final String text;
  final ShadColorScheme cs;
  @override
  Widget build(BuildContext context) => Text(
    text,
    style: TextStyle(fontSize: 13, height: 1.55, color: cs.mutedForeground),
  );
}

class _ErrorText extends StatelessWidget {
  const _ErrorText(this.text, this.cs);
  final String text;
  final ShadColorScheme cs;
  @override
  Widget build(BuildContext context) =>
      Text(text, style: TextStyle(fontSize: 13, color: cs.destructive));
}

class _BoxedField extends StatelessWidget {
  const _BoxedField({
    required this.controller,
    required this.hint,
    required this.cs,
  });
  final TextEditingController controller;
  final String hint;
  final ShadColorScheme cs;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 50,
      alignment: Alignment.center,
      padding: const EdgeInsets.symmetric(horizontal: 14),
      decoration: BoxDecoration(
        color: cs.background,
        borderRadius: BorderRadius.circular(Spacing.radiusBtn),
        border: Border.all(color: cs.input, width: 1),
      ),
      child: TextField(
        controller: controller,
        keyboardType: TextInputType.phone,
        inputFormatters: [_PhoneNumberFormatter()],
        style: TextStyle(
          fontSize: 16,
          color: cs.foreground,
          fontFeatures: const [FontFeature.tabularFigures()],
        ),
        cursorColor: cs.primary,
        decoration: InputDecoration(
          isCollapsed: true,
          border: InputBorder.none,
          hintText: hint,
          hintStyle: TextStyle(fontSize: 15, color: cs.mutedForeground),
        ),
      ),
    );
  }
}

class _PhoneNumberFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    var d = newValue.text.replaceAll(RegExp(r'\D'), '');
    if (d.length > 11) d = d.substring(0, 11);
    final b = StringBuffer();
    for (var i = 0; i < d.length; i++) {
      if (i == 3 || i == 7) b.write(' ');
      b.write(d[i]);
    }
    final s = b.toString();
    return TextEditingValue(
      text: s,
      selection: TextSelection.collapsed(offset: s.length),
    );
  }
}

class _OtpInput extends StatelessWidget {
  const _OtpInput({
    required this.controller,
    required this.focusNode,
    required this.cs,
  });
  final TextEditingController controller;
  final FocusNode focusNode;
  final ShadColorScheme cs;

  @override
  Widget build(BuildContext context) {
    final code = controller.text;
    return GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: focusNode.requestFocus,
      child: SizedBox(
        height: 54,
        child: Stack(
          children: [
            Row(
              children: [
                for (var i = 0; i < 6; i++) ...[
                  if (i > 0) const SizedBox(width: 8),
                  Expanded(
                    child: _OtpCell(
                      digit: i < code.length ? code[i] : '',
                      filled: i < code.length,
                      cs: cs,
                    ),
                  ),
                ],
              ],
            ),
            Positioned.fill(
              child: TextField(
                controller: controller,
                focusNode: focusNode,
                keyboardType: TextInputType.number,
                maxLength: 6,
                showCursor: false,
                autofocus: true,
                inputFormatters: [FilteringTextInputFormatter.digitsOnly],
                style: const TextStyle(color: Colors.transparent),
                decoration: const InputDecoration(
                  counterText: '',
                  border: InputBorder.none,
                  enabledBorder: InputBorder.none,
                  focusedBorder: InputBorder.none,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _OtpCell extends StatelessWidget {
  const _OtpCell({required this.digit, required this.filled, required this.cs});
  final String digit;
  final bool filled;
  final ShadColorScheme cs;

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      decoration: BoxDecoration(
        color: cs.background,
        borderRadius: BorderRadius.circular(Spacing.radiusBtn),
        border: Border.all(color: filled ? cs.foreground : cs.input, width: 1),
      ),
      child: Text(
        digit,
        style: TextStyle(
          fontSize: 22,
          fontWeight: FontWeight.w600,
          color: cs.foreground,
          fontFeatures: const [FontFeature.tabularFigures()],
        ),
      ),
    );
  }
}

class _AgreeRow extends StatelessWidget {
  const _AgreeRow({
    required this.agreed,
    required this.onToggle,
    required this.cs,
  });
  final bool agreed;
  final VoidCallback onToggle;
  final ShadColorScheme cs;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: onToggle,
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            width: 18,
            height: 18,
            margin: const EdgeInsets.only(top: 1),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(Spacing.radiusBadge),
              border: Border.all(
                color: agreed ? cs.primary : cs.border,
                width: 1.2,
              ),
              color: agreed ? cs.primary : Colors.transparent,
            ),
            child: agreed
                ? Icon(
                    FlutterRemix.check_line,
                    size: 13,
                    color: cs.primaryForeground,
                  )
                : null,
          ),
          const SizedBox(width: 8),
          Expanded(child: Text.rich(_policySpan(context, cs))),
        ],
      ),
    );
  }
}

TextSpan _policySpan(
  BuildContext context,
  ShadColorScheme cs, {
  double fontSize = 11.5,
}) {
  final isDark = Theme.of(context).brightness == Brightness.dark;
  final privacyUrl = AppH5UrlsHelper.buildUrlWithNight(
    AppH5Urls.privacyUrl,
    isDark,
  );
  final protocolUrl = AppH5UrlsHelper.buildUrlWithNight(
    AppH5Urls.userProtocolUrl,
    isDark,
  );

  TextSpan link(String text, String url) => TextSpan(
    text: text,
    style: TextStyle(
      color: cs.foreground,
      fontSize: fontSize,
      decoration: TextDecoration.underline,
      decorationColor: cs.foreground,
    ),
    recognizer: TapGestureRecognizer()
      ..onTap = () => launchUrlString(
        AppH5UrlsHelper.withCacheBuster(url),
        mode: LaunchMode.inAppBrowserView,
      ),
  );

  return TextSpan(
    style: TextStyle(
      fontSize: fontSize,
      height: 1.6,
      color: cs.mutedForeground,
    ),
    children: [
      const TextSpan(text: '已阅读并同意 '),
      link('《用户协议》', protocolUrl),
      const TextSpan(text: ' 与 '),
      link('《隐私政策》', privacyUrl),
    ],
  );
}

class _PrimaryButton extends StatelessWidget {
  const _PrimaryButton({
    required this.label,
    required this.enabled,
    required this.onTap,
    this.loading = false,
    this.dim = false,
  });
  final String label;
  final bool enabled;
  final bool loading;
  final bool dim;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    final cs = ShadTheme.of(context).colorScheme;
    final active = enabled && !dim;
    return SizedBox(
      width: double.infinity,
      child: GestureDetector(
        onTap: enabled ? onTap : null,
        behavior: HitTestBehavior.opaque,
        child: Container(
          padding: const EdgeInsets.symmetric(vertical: 15),
          alignment: Alignment.center,
          decoration: BoxDecoration(
            color: active ? cs.primary : cs.muted,
            borderRadius: BorderRadius.circular(9999),
          ),
          child: loading
              ? SizedBox(
                  width: 18,
                  height: 18,
                  child: CircularProgressIndicator(
                    strokeWidth: 2,
                    color: active ? cs.primaryForeground : cs.mutedForeground,
                  ),
                )
              : Text(
                  label,
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.w600,
                    color: active ? cs.primaryForeground : cs.mutedForeground,
                  ),
                ),
        ),
      ),
    );
  }
}
