import 'dart:convert';
import 'dart:io';

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

import '../presentation/pages/auth/captcha_challenge_page.dart';
import '../presentation/widgets/toast_helper.dart';
import '../services/auth_service.dart';
import '../services/server_service.dart';
import 'api_service.dart';

/// 验证码服务（单例）
///
/// 管理验证码的加载、状态和 UI 构建，供登录/注册/忘记密码页面共享。
class CaptchaService {
  CaptchaService._internal();
  static final CaptchaService _instance = CaptchaService._internal();
  static CaptchaService get instance => _instance;

  final TextEditingController captchaController = TextEditingController();

  String? _captchaType;
  String? _recaptchaSiteKey;
  String? _turnstileSiteKey;
  String? _capInstanceUrl;
  String? _capSiteKey;
  String? _capAssetServer;

  String? _captchaImage;
  String? _captchaTicket;
  String? _captchaToken;
  bool _isLoadingCaptcha = false;

  // 代理配置（仅 Windows 桌面端）
  CaptchaProxyConfig? _proxyConfig;

  bool get _isDesktop => !kIsWeb && (Platform.isWindows || Platform.isLinux);

  bool get isLoadingCaptcha => _isLoadingCaptcha;
  String? get captchaImage => _captchaImage;
  String? get captchaTicket => _captchaTicket;
  String? get captchaToken => _captchaToken;

  bool get isWebCaptcha => captchaWebConfig != null;

  CaptchaWebConfig? get captchaWebConfig {
    final type = _normalizedCaptchaType;
    if (type == 'turnstile' &&
        _turnstileSiteKey != null &&
        _turnstileSiteKey!.isNotEmpty) {
      return CaptchaWebConfig.turnstile(
        siteKey: _turnstileSiteKey!,
        displayName: 'Cloudflare Turnstile',
      );
    }

    if (type == 'recaptcha' &&
        _recaptchaSiteKey != null &&
        _recaptchaSiteKey!.isNotEmpty) {
      return CaptchaWebConfig.recaptchaV2(
        siteKey: _recaptchaSiteKey!,
        displayName: 'reCAPTCHA V2',
      );
    }

    if (type == 'cap' &&
        _capInstanceUrl != null &&
        _capInstanceUrl!.isNotEmpty &&
        _capSiteKey != null &&
        _capSiteKey!.isNotEmpty) {
      return CaptchaWebConfig.cap(
        instanceUrl: _capInstanceUrl!,
        siteKey: _capSiteKey!,
        assetServer: _capAssetServer,
        displayName: 'Cap',
      );
    }

    return null;
  }

  String get _normalizedCaptchaType {
    final raw = (_captchaType ?? '').trim().toLowerCase();
    if (raw == 'recaptcha_v2' ||
        raw == 'recaptchav2' ||
        raw == 'google' ||
        raw == 'google_recaptcha' ||
        raw == 'google-recaptcha') {
      return 'recaptcha';
    }
    if (raw == 'cloudflare_turnstile' || raw == 'cloudflare-turnstile') {
      return 'turnstile';
    }
    if (raw == 'image' || raw == 'graphic' || raw == 'captcha') {
      return 'normal';
    }
    return raw;
  }

  /// 加载验证码配置和图片
  Future<void> loadCaptcha(String baseUrl) async {
    if (_isLoadingCaptcha) return;

    _isLoadingCaptcha = true;

    try {
      await ApiService.instance.setBaseUrl(baseUrl);

      Map<String, dynamic> config = <String, dynamic>{};

      try {
        config = await AuthService.instance
            .getBasicSiteConfig()
            .timeout(const Duration(seconds: 10));
      } catch (_) {}

      final captchaType = _normalizeCaptchaType(
        (config['captcha_type'] ??
                config['captchaType'] ??
                config['captcha'])
            ?.toString(),
      );

      final recaptchaKey = _firstNonEmptyString(config, const [
        'captcha_ReCaptchaKey',
        'captcha_re_captcha_key',
        'captchaReCaptchaKey',
        'recaptcha_site_key',
        'recaptchaSiteKey',
        'recaptcha_key',
        'reCaptchaKey',
      ]);

      final turnstileSiteKey = _firstNonEmptyString(config, const [
        'turnstile_site_id',
        'turnstileSiteId',
        'turnstile_site_key',
        'turnstileSiteKey',
      ]);

      final capInstanceUrl = _firstNonEmptyString(config, const [
        'captcha_cap_instance_url',
        'captchaCapInstanceUrl',
        'cap_instance_url',
        'capInstanceUrl',
      ]);

      final capSiteKey = _firstNonEmptyString(config, const [
        'captcha_cap_site_key',
        'captchaCapSiteKey',
        'cap_site_key',
        'capSiteKey',
      ]);

      final capAssetServer = _firstNonEmptyString(config, const [
        'captcha_cap_asset_server',
        'captchaCapAssetServer',
        'cap_asset_server',
        'capAssetServer',
      ]);

      final isExternalCaptcha = captchaType == 'turnstile' ||
          captchaType == 'recaptcha' ||
          captchaType == 'cap';

      if (isExternalCaptcha) {
        _captchaType = captchaType;
        _recaptchaSiteKey = recaptchaKey;
        _turnstileSiteKey = turnstileSiteKey;
        _capInstanceUrl = capInstanceUrl;
        _capSiteKey = capSiteKey;
        _capAssetServer = capAssetServer;
        _captchaToken = null;

        _captchaImage = null;
        _captchaTicket = null;
        captchaController.clear();
        return;
      }

      final captcha = await AuthService.instance.getCaptcha();

      _captchaType = captchaType.isEmpty ? 'normal' : captchaType;
      _recaptchaSiteKey = null;
      _turnstileSiteKey = null;
      _capInstanceUrl = null;
      _capSiteKey = null;
      _capAssetServer = null;
      _captchaToken = null;

      _captchaImage = captcha['image'];
      _captchaTicket = captcha['ticket'];
      captchaController.clear();
    } catch (_) {
      clearCaptcha();
    } finally {
      _isLoadingCaptcha = false;
    }
  }

  /// 重新加载图形验证码图片
  Future<void> refreshCaptcha() async {
    final server = ServerService.instance.currentServer;
    if (server == null) return;
    await loadCaptcha(server.baseUrl);
  }

  /// 跳转到 Web 验证码页面
  Future<void> openCaptchaChallenge(BuildContext context, {VoidCallback? onVerified}) async {
    final server = ServerService.instance.currentServer;
    final config = captchaWebConfig;

    if (server == null || config == null) {
      ToastHelper.failure('验证码配置无效');
      return;
    }

    final token = await Navigator.of(context).push<String>(
      MaterialPageRoute(
        builder: (_) => CaptchaChallengePage(
          config: config,
          baseUrl: server.baseUrl,
          proxyConfig: _isDesktop ? _proxyConfig : null,
        ),
      ),
    );

    if (token != null && token.isNotEmpty) {
      _captchaToken = token;
      ToastHelper.success('人机验证完成');
      onVerified?.call();
    }
  }

  /// 清空所有验证码状态
  void clearCaptcha() {
    _captchaType = null;
    _recaptchaSiteKey = null;
    _turnstileSiteKey = null;
    _capInstanceUrl = null;
    _capSiteKey = null;
    _capAssetServer = null;
    _captchaToken = null;
    _captchaImage = null;
    _captchaTicket = null;
    captchaController.clear();
  }

  /// 获取验证码参数（用于提交登录/注册/忘记密码请求）
  ///
  /// 返回 `{captcha: ..., ticket: ...}` 或空 Map（无需验证码时）。
  Map<String, String> getCaptchaParams() {
    if (isWebCaptcha) {
      if (_captchaToken == null || _captchaToken!.isEmpty) return {};
      return {
        'captcha': _captchaToken!,
        'ticket': _captchaToken!,
      };
    }

    final userInput = captchaController.text.trim();
    if (userInput.isEmpty && (_captchaTicket == null || _captchaTicket!.isEmpty)) {
      return {};
    }

    return {
      'captcha': userInput,
      'ticket': _captchaTicket ?? '',
    };
  }

  /// Web 验证码是否已通过
  bool get isWebCaptchaVerified =>
      !isWebCaptcha || (_captchaToken != null && _captchaToken!.isNotEmpty);

  /// 构建验证码输入 Widget
  Widget buildCaptchaInput(BuildContext context) {
    if (isWebCaptcha) {
      final config = captchaWebConfig;
      final displayName = config?.displayName ?? '人机验证';

      return StatefulBuilder(
        builder: (context, setState) {
          final hasProxy = _proxyConfig != null;
          return Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              OutlinedButton.icon(
                onPressed: _isLoadingCaptcha ? null : () async {
                  await openCaptchaChallenge(context);
                  setState(() {});
                },
                onLongPress: _isDesktop && Platform.isWindows
                    ? () => _showProxyDialog(context, setState)
                    : null,
                icon: Icon(
                  _captchaToken == null
                      ? Icons.verified_user_outlined
                      : Icons.verified,
                ),
                label: Text(
                  _captchaToken == null
                      ? '点击完成 $displayName'
                      : '$displayName 已完成，点击重新验证',
                ),
              ),
              const SizedBox(height: 8),
              Text(
                _isDesktop && Platform.isWindows
                    ? '当前验证码类型：$displayName${hasProxy ? '  (代理: $_proxyConfig)' : ''}\n网络问题验证失败可长按上方按钮可以设置代理(仅windows)'
                    : '当前验证码类型：$displayName',
                style: TextStyle(
                  fontSize: 12,
                  color: Theme.of(context).hintColor,
                ),
              ),
            ],
          );
        },
      );
    }

    Widget captchaPreview;

    if (_isLoadingCaptcha) {
      captchaPreview = const SizedBox(
        width: 20,
        height: 20,
        child: CircularProgressIndicator(strokeWidth: 2),
      );
    } else if (_captchaImage != null && _captchaImage!.isNotEmpty) {
      try {
        final base64Part = _captchaImage!.contains(',')
            ? _captchaImage!.split(',').last
            : _captchaImage!;

        captchaPreview = Image.memory(
          base64Decode(base64Part),
          fit: BoxFit.contain,
          gaplessPlayback: true,
        );
      } catch (_) {
        captchaPreview = const Text('刷新');
      }
    } else {
      captchaPreview = const Text('刷新');
    }

    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Expanded(
          child: TextFormField(
            controller: captchaController,
            textInputAction: TextInputAction.done,
            decoration: const InputDecoration(
              labelText: '验证码',
              hintText: '请输入验证码',
              prefixIcon: Icon(Icons.verified_user_outlined),
            ),
            validator: (value) {
              final needCaptcha =
                  _captchaTicket != null && _captchaTicket!.isNotEmpty;

              if (needCaptcha && (value == null || value.trim().isEmpty)) {
                return '请输入验证码';
              }

              return null;
            },
          ),
        ),
        const SizedBox(width: 12),
        InkWell(
          onTap: _isLoadingCaptcha ? null : refreshCaptcha,
          borderRadius: BorderRadius.circular(8),
          child: Container(
            width: 130,
            height: 56,
            alignment: Alignment.center,
            padding: const EdgeInsets.all(4),
            decoration: BoxDecoration(
              border: Border.all(color: Theme.of(context).dividerColor),
              borderRadius: BorderRadius.circular(8),
            ),
            child: captchaPreview,
          ),
        ),
      ],
    );
  }

  String _normalizeCaptchaType(String? rawType) {
    final value = (rawType ?? '').trim().toLowerCase();
    if (value.isEmpty) return 'normal';

    if (value == 'image' || value == 'graphic' || value == 'captcha') {
      return 'normal';
    }

    if (value == 'recaptcha_v2' ||
        value == 'recaptchav2' ||
        value == 'google' ||
        value == 'google_recaptcha' ||
        value == 'google-recaptcha') {
      return 'recaptcha';
    }

    if (value == 'cloudflare_turnstile' || value == 'cloudflare-turnstile') {
      return 'turnstile';
    }

    return value;
  }

  String? _firstNonEmptyString(Map<String, dynamic> source, List<String> keys) {
    for (final key in keys) {
      final value = source[key];
      if (value == null) continue;
      final text = value.toString().trim();
      if (text.isNotEmpty) return text;
    }
    return null;
  }

  /// Windows 桌面端长按弹出代理设置对话框
  void _showProxyDialog(BuildContext context, StateSetter setState) {
    final hostCtrl = TextEditingController(text: _proxyConfig?.host ?? '');
    final portCtrl = TextEditingController(text: _proxyConfig?.port.toString() ?? '');

    showDialog(
      context: context,
      builder: (ctx) {
        return AlertDialog(
          title: const Text('WebView 代理设置'),
          content: SizedBox(
            width: 320,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  '仅支持无认证代理（HTTP/SOCKS5）',
                  style: TextStyle(fontSize: 12, color: Theme.of(ctx).hintColor),
                ),
                const SizedBox(height: 16),
                TextFormField(
                  controller: hostCtrl,
                  decoration: const InputDecoration(
                    labelText: '代理地址',
                    hintText: '127.0.0.1',
                    prefixIcon: Icon(Icons.dns_outlined),
                  ),
                ),
                const SizedBox(height: 12),
                TextFormField(
                  controller: portCtrl,
                  keyboardType: TextInputType.number,
                  decoration: const InputDecoration(
                    labelText: '端口',
                    hintText: '7890',
                    prefixIcon: Icon(Icons.numbers),
                  ),
                ),
              ],
            ),
          ),
          actions: [
            TextButton(
              onPressed: () {
                _proxyConfig = null;
                setState(() {});
                Navigator.of(ctx).pop();
                ToastHelper.success('已清除代理配置');
              },
              child: const Text('清除'),
            ),
            TextButton(
              onPressed: () => Navigator.of(ctx).pop(),
              child: const Text('取消'),
            ),
            FilledButton(
              onPressed: () {
                final host = hostCtrl.text.trim();
                final port = int.tryParse(portCtrl.text.trim()) ?? 0;
                if (host.isEmpty || port <= 0) {
                  ToastHelper.failure('请输入有效的代理地址和端口');
                  return;
                }
                _proxyConfig = CaptchaProxyConfig(host: host, port: port);
                setState(() {});
                Navigator.of(ctx).pop();
                ToastHelper.success('代理已设置: $host:$port');
              },
              child: const Text('确定'),
            ),
          ],
        );
      },
    );
  }
}
