part of '../../core_app.dart';

const MethodChannel _appShellDeviceChannel = MethodChannel('app_shell/device');

/// 承载核心 WebView 的主页面。
class WebShellPage extends StatefulWidget {
  /// 创建主壳页面。
  const WebShellPage({super.key});

  @override
  State<WebShellPage> createState() => _WebShellPageState();
}

// coverage:ignore-start
class _WebShellPageState extends State<WebShellPage>
    with WidgetsBindingObserver {
  final ImagePicker _imagePicker = ImagePicker();
  final WebViewCookieManager _cookieManager = WebViewCookieManager();

  late WebViewController _controller;
  late WebViewWidget _webViewWidget;
  late Future<void> _controllerSetupFuture;
  late final Future<void> _androidCompatibilityFuture;
  AndroidWebViewInfo? _androidWebViewInfo;
  AndroidCompatibilityPlan _androidCompatibilityPlan =
      AndroidCompatibilityPlan.fallback();
  AndroidRenderMode? _configuredRenderMode;
  int _webViewGeneration = 0;
  int _renderModeIndex = 0;

  bool _hasTriggeredInitialLoad = false;
  bool _hasAppliedCompatibilityPlan = false;
  bool _isLoadingPage = false;
  bool _hasBootstrapped = false;
  bool _hasStartedRemoteMainFrame = false;
  bool _hasMainFrameError = false;
  bool _hasMeasuredProgress = false;
  Timer? _startupWatchdogTimer;
  int _progress = 0;
  int _startupRetryCount = 0;
  String _currentUrl = _initialUrl;
  String _errorTitle = '页面加载失败';
  String _errorMessage = '请检查网络后重试。';
  String _lastWebViewEvent = '应用启动';

  @override
  void initState() {
    super.initState();
    debugPrint('WebShell 初始化，初始地址=$_initialUrl');
    WidgetsBinding.instance.addObserver(this);
    _androidCompatibilityFuture = _prepareAndroidCompatibility();
    _recreateWebView();

    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted || _hasTriggeredInitialLoad) {
        return;
      }
      _hasTriggeredInitialLoad = true;
      unawaited(_loadInitialPage());
      // 触发版本检测（如果配置了升级地址才会弹窗）
      unawaited(ShellUpgradeService.instance.checkVersion(context));
    });
  }

  // ── 渲染模式索引 ──

  int get _safeRenderModeIndex {
    if (_renderModeIndex < 0) {
      return 0;
    }
    final maxIndex = _androidCompatibilityPlan.renderModes.length - 1;
    if (_renderModeIndex > maxIndex) {
      return maxIndex;
    }
    return _renderModeIndex;
  }

  AndroidRenderMode get _activeRenderMode =>
      _androidCompatibilityPlan.renderModes[_safeRenderModeIndex];

  Duration get _effectiveStartupWatchdogDuration {
    if (defaultTargetPlatform != TargetPlatform.android) {
      return _releaseStartupWatchdogDuration;
    }
    if (kDebugMode) {
      return _debugStartupWatchdogDuration;
    }
    return _releaseStartupWatchdogDuration;
  }

  // ── Android 兼容性 ──

  Future<void> _prepareAndroidCompatibility() async {
    if (defaultTargetPlatform != TargetPlatform.android) {
      return;
    }

    try {
      final rawInfo = await _appShellDeviceChannel
          .invokeMapMethod<Object?, Object?>('getAndroidWebViewInfo');
      if (rawInfo != null) {
        _androidWebViewInfo = AndroidWebViewInfo.fromMap(rawInfo);
      }
    } on Object catch (error, stackTrace) {
      debugPrint('读取 Android WebView 信息失败：$error\n$stackTrace');
    }

    _androidCompatibilityPlan = AndroidCompatibilityPlan.fromInfo(
      _androidWebViewInfo,
    );
    _renderModeIndex = 0;
    debugPrint(
      'WebShell Android WebView 信息：'
      '${_androidWebViewInfo?.summary ?? '不可用'}',
    );
    debugPrint(
      'WebShell 兼容策略：${_androidCompatibilityPlan.describe()}',
    );
  }

  Future<void> _ensureCompatibilityPlanApplied() async {
    await _androidCompatibilityFuture;
    if (!mounted ||
        _hasAppliedCompatibilityPlan ||
        defaultTargetPlatform != TargetPlatform.android) {
      return;
    }

    _hasAppliedCompatibilityPlan = true;
    if (_configuredRenderMode == _activeRenderMode) {
      debugPrint(
        'WebShell 兼容策略保持当前 WebView '
        '(${_activeRenderMode.logName})',
      );
      return;
    }
    _recreateWebView();
  }

  bool _switchToNextRenderMode() {
    final nextIndex = _safeRenderModeIndex + 1;
    if (nextIndex >= _androidCompatibilityPlan.renderModes.length) {
      return false;
    }
    _renderModeIndex = nextIndex;
    debugPrint('WebShell 已切换渲染模式为 ${_activeRenderMode.logName}');
    return true;
  }

  String _buildCompatibilityGuidance() {
    if (defaultTargetPlatform != TargetPlatform.android) {
      return '';
    }
    final lines = <String>[
      '当前渲染策略：${_activeRenderMode.displayName}',
      if (_androidWebViewInfo?.model case final String model
          when model.isNotEmpty)
        '当前设备：$model',
      if (_androidWebViewInfo?.webViewVersionName case final String version
          when version.isNotEmpty)
        '系统 WebView：$version',
      if (_androidCompatibilityPlan.suggestWebViewUpdate)
        '如果内嵌页面仍异常，建议更新 Android System WebView 或 Chrome。',
    ];
    return lines.join('\n');
  }

  // ── WebView 创建 ──

  void _recreateWebView() {
    const controllerParams = PlatformWebViewControllerCreationParams();
    final controller = WebViewController.fromPlatformCreationParams(
      controllerParams,
    );
    final generation = ++_webViewGeneration;
    final renderMode = _activeRenderMode;

    _controller = controller;
    _controllerSetupFuture = _configureController(controller, generation);
    _configuredRenderMode = renderMode;
    debugPrint(
      'WebShell 正在以 ${renderMode.logName} 重建 WebView #$generation',
    );
    var widgetParams = PlatformWebViewWidgetCreationParams(
      key: ValueKey<String>('webview-$generation-${renderMode.logName}'),
      controller: controller.platform,
    );

    if (defaultTargetPlatform == TargetPlatform.android) {
      widgetParams = _buildAndroidWidgetParams(widgetParams, renderMode);
    }

    _webViewWidget = WebViewWidget.fromPlatformCreationParams(
      params: widgetParams,
    );
  }

  bool _isActiveWebViewGeneration(int generation) {
    return generation == _webViewGeneration;
  }

  PlatformWebViewWidgetCreationParams _buildAndroidWidgetParams(
    PlatformWebViewWidgetCreationParams widgetParams,
    AndroidRenderMode renderMode,
  ) {
    const createParams = AndroidWebViewWidgetCreationParams
        .fromPlatformWebViewWidgetCreationParams;
    return createParams(
      widgetParams,
      displayWithHybridComposition: renderMode.usesHybridComposition,
    );
  }

  Future<void> _configureController(
    WebViewController controller,
    int generation,
  ) async {
    await controller.setJavaScriptMode(JavaScriptMode.unrestricted);
    await controller.enableZoom(false);
    await controller.setBackgroundColor(Colors.white);
    await controller.addJavaScriptChannel(
      _appShellBridgeChannel,
      onMessageReceived: (message) {
        if (!_isActiveWebViewGeneration(generation)) {
          return;
        }
        unawaited(_handleBridgeMessage(message.message));
      },
    );
    await controller.setNavigationDelegate(
      _buildNavigationDelegate(generation),
    );

    if (controller.platform is AndroidWebViewController) {
      final androidController = controller.platform as AndroidWebViewController;

      await AndroidWebViewController.enableDebugging(
        kDebugMode && !_androidCompatibilityPlan.prefersAggressiveRecovery,
      );
      await androidController.setMediaPlaybackRequiresUserGesture(false);
      await androidController.setMixedContentMode(MixedContentMode.alwaysAllow);
      await androidController.setOverScrollMode(WebViewOverScrollMode.never);
      await androidController.setUseWideViewPort(
        _androidCompatibilityPlan.useWideViewPort,
      );
      await androidController.setTextZoom(100);
      await androidController.setVerticalScrollBarEnabled(false);
      await androidController.setHorizontalScrollBarEnabled(false);
      await androidController.setOnShowFileSelector(_handleFileSelector);
      await androidController.setOnPlatformPermissionRequest(
        _handlePlatformPermissionRequest,
      );
      await androidController.setGeolocationPermissionsPromptCallbacks(
        onShowPrompt: _handleGeolocationPermissionRequest,
      );
      await androidController.setOnConsoleMessage((message) {
        debugPrint(
          'WebView 控制台 [${message.level.name}] ${message.message}',
        );
      });
    }
  }

  NavigationDelegate _buildNavigationDelegate(int generation) {
    return NavigationDelegate(
      onProgress: (progress) {
        if (!_isActiveWebViewGeneration(generation)) {
          return;
        }
        if (progress == 10 ||
            progress == 30 ||
            progress == 60 ||
            progress == 90) {
          _recordWebViewEvent('加载进度 $progress%');
        }
        if (!mounted) {
          return;
        }
        setState(() {
          _progress = progress;
          if (_hasStartedRemoteMainFrame || progress >= 100) {
            _hasMeasuredProgress = true;
          }
        });
      },
      onNavigationRequest: (request) async {
        if (!_isActiveWebViewGeneration(generation)) {
          return NavigationDecision.navigate;
        }
        return _handleNavigationRequest(request);
      },
      onUrlChange: (change) {
        if (!_isActiveWebViewGeneration(generation)) {
          return;
        }
        final url = change.url;
        if (url == null || url.isEmpty) {
          return;
        }
        _recordWebViewEvent('地址变化：$url');
        if (!mounted) {
          return;
        }
        setState(() {
          _currentUrl = url;
        });
      },
      onPageStarted: (url) {
        if (!_isActiveWebViewGeneration(generation)) {
          return;
        }
        if (!_isNetworkUrl(url)) {
          debugPrint('WebView 忽略非网络页面开始事件：$url');
          return;
        }
        _hasStartedRemoteMainFrame = true;
        _cancelStartupWatchdog();
        _recordWebViewEvent('页面开始加载：$url');
        if (!mounted) {
          return;
        }
        setState(() {
          _currentUrl = url;
          if (_hasMeasuredProgress) {
            _progress = _progress < 30 ? 30 : _progress;
          }
          _isLoadingPage = true;
          _hasBootstrapped = true;
          _hasMainFrameError = false;
          _errorTitle = '页面加载失败';
          _errorMessage = '请检查网络后重试。';
        });
      },
      onPageFinished: (url) {
        if (!_isActiveWebViewGeneration(generation)) {
          return;
        }
        if (!_isNetworkUrl(url)) {
          debugPrint('WebView 忽略非网络页面完成事件：$url');
          return;
        }
        _recordWebViewEvent('页面加载完成：$url');
        _cancelStartupWatchdog();
        if (!_hasMainFrameError) {
          unawaited(_injectAppShellBridge(_controller, url));
        }
        if (!mounted) {
          return;
        }
        setState(() {
          _currentUrl = url;
          _hasMeasuredProgress = true;
          _progress = 100;
          _isLoadingPage = false;
          _hasBootstrapped = true;
          if (!_hasMainFrameError) {
            _startupRetryCount = 0;
          }
        });
      },
      onHttpError: (error) {
        if (!_isActiveWebViewGeneration(generation)) {
          return;
        }
        final statusCode = error.response?.statusCode;
        final requestUri = error.request?.uri;
        if (!_shouldTreatHttpErrorAsMainFrame(error)) {
          debugPrint(
            '忽略子资源 HTTP 错误：'
            '${statusCode ?? '未知'} ${requestUri ?? '未知'}',
          );
          return;
        }
        _recordWebViewEvent(
          'HTTP 错误：${statusCode ?? '未知'} ${requestUri ?? _currentUrl}',
        );
        _setMainFrameError(
          title: statusCode == null ? '服务器响应异常' : '服务器异常 $statusCode',
          message: statusCode == null
              ? '页面返回异常，请稍后重试。'
              : '页面返回了 $statusCode 状态码，请稍后重试。',
        );
      },
      onWebResourceError: (error) {
        if (!_isActiveWebViewGeneration(generation)) {
          return;
        }
        _recordWebViewEvent(
          '资源错误：code=${error.errorCode}, '
          'type=${error.errorType}, '
          'mainFrame=${error.isForMainFrame}, '
          'url=${error.url}, '
          'description=${error.description}',
        );
        if (!mounted || error.isForMainFrame == false) {
          return;
        }
        _setMainFrameError(
          title: _friendlyErrorTitle(error),
          message: _friendlyErrorMessage(error),
        );
      },
    );
  }

  // ── 生命周期 ──

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      unawaited(_enterImmersiveMode());
    }
  }

  @override
  void dispose() {
    _cancelStartupWatchdog();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  // ── 页面加载 ──

  Future<void> _loadInitialPage() async {
    if (!mounted) {
      return;
    }
    await _ensureCompatibilityPlanApplied();
    if (!mounted) {
      return;
    }
    debugPrint('WebShell 首帧已就绪，开始初始加载');
    await _startLoadSequence(rebuildWebView: false, resetRetryCount: true);
  }

  Future<void> _handleBackPressed() async {
    if (await _controller.canGoBack()) {
      await _controller.goBack();
      return;
    }
    await SystemNavigator.pop();
  }

  Future<NavigationDecision> _handleNavigationRequest(
    NavigationRequest request,
  ) async {
    final uri = Uri.tryParse(request.url);
    if (uri == null || _shouldStayInWebView(uri)) {
      return NavigationDecision.navigate;
    }

    final opened = await _openExternalUri(uri);
    if (!opened) {
      await _showWebAlert(_controller, '无法打开外部应用：${uri.scheme}');
    }
    return NavigationDecision.prevent;
  }

  void _recordWebViewEvent(String event) {
    _lastWebViewEvent = event;
    debugPrint('WebView 事件：$event');
  }

  // ── 看门狗 ──

  void _armStartupWatchdog() {
    _cancelStartupWatchdog();
    _startupWatchdogTimer = Timer(_effectiveStartupWatchdogDuration, () {
      unawaited(_handleStartupTimeout());
    });
  }

  void _cancelStartupWatchdog() {
    _startupWatchdogTimer?.cancel();
    _startupWatchdogTimer = null;
  }

  Future<void> _handleStartupTimeout() async {
    if (!mounted ||
        !_isLoadingPage ||
        _hasMainFrameError ||
        _hasStartedRemoteMainFrame) {
      return;
    }

    final switchedRenderMode = _switchToNextRenderMode();
    final maxRetryCount = _androidCompatibilityPlan.prefersAggressiveRecovery
        ? 2
        : 1;

    if (switchedRenderMode || _startupRetryCount < maxRetryCount) {
      final nextRetryCount = _startupRetryCount + 1;
      final recoveryAction = switchedRenderMode
          ? '切换到${_activeRenderMode.displayName}'
          : '深度清理 WebView 状态';
      _recordWebViewEvent('启动超时，$recoveryAction 并自动重试第 $nextRetryCount 次');
      setState(() {
        _startupRetryCount = nextRetryCount;
        _hasMeasuredProgress = false;
        _progress = 0;
        _isLoadingPage = true;
      });
      await _recoverFromBrokenStartupState(deepReset: true);
      await _startLoadSequence(rebuildWebView: true, resetRetryCount: false);
      return;
    }

    _setMainFrameError(
      title: '页面启动超时',
      message: <String>[
        '${_effectiveStartupWatchdogDuration.inSeconds} 秒内没有完成页面加载。',
        '最近事件：$_lastWebViewEvent',
        _buildCompatibilityGuidance(),
      ].where((line) => line.isNotEmpty).join('\n'),
    );
  }

  void _setMainFrameError({required String title, required String message}) {
    _cancelStartupWatchdog();
    if (!mounted) {
      return;
    }
    setState(() {
      _isLoadingPage = false;
      _hasMainFrameError = true;
      _hasMeasuredProgress = false;
      _errorTitle = title;
      _errorMessage = message;
      _progress = 0;
    });
  }

  Future<void> _recoverFromBrokenStartupState({bool deepReset = false}) async {
    final controllerSetupFuture = _controllerSetupFuture;
    try {
      await controllerSetupFuture;
    } on Object catch (error, stackTrace) {
      debugPrint('等待 WebView 控制器初始化失败：$error\n$stackTrace');
    }

    try {
      await _controller.clearCache();
    } on Object catch (error, stackTrace) {
      debugPrint('清理 WebView 缓存失败：$error\n$stackTrace');
    }

    try {
      await _controller.clearLocalStorage();
    } on Object catch (error, stackTrace) {
      debugPrint('清理 WebView 本地存储失败：$error\n$stackTrace');
    }

    try {
      await _cookieManager.clearCookies();
    } on Object catch (error, stackTrace) {
      debugPrint('清理 WebView Cookie 失败：$error\n$stackTrace');
    }

    if (!deepReset || defaultTargetPlatform != TargetPlatform.android) {
      return;
    }

    try {
      await _appShellDeviceChannel.invokeMethod<void>(
        'resetAndroidWebViewState',
      );
    } on Object catch (error, stackTrace) {
      debugPrint('重置 Android WebView 状态失败：$error\n$stackTrace');
    }
  }

  bool _shouldTreatHttpErrorAsMainFrame(HttpResponseError error) {
    final requestUri = error.request?.uri;
    if (requestUri == null) {
      return true;
    }
    if (!_isNetworkUrl(requestUri.toString())) {
      return false;
    }
    final currentUri = Uri.tryParse(_currentUrl);
    if (_isSameDocumentRequest(requestUri, currentUri)) {
      return true;
    }
    if (!_hasBootstrapped && _isSameDocumentRequest(requestUri, _initialUri)) {
      return true;
    }
    return false;
  }

  bool _isSameDocumentRequest(Uri left, Uri? right) {
    if (right == null) {
      return false;
    }
    return _normalizeComparableUri(left) == _normalizeComparableUri(right);
  }

  // ── Bridge 消息处理 ──

  Future<void> _handleBridgeMessage(String rawMessage) async {
    var requestId = '';

    try {
      final dynamic decoded = jsonDecode(rawMessage);
      if (decoded is! Map) {
        return;
      }

      final message = Map<String, dynamic>.from(decoded);
      requestId = (message['requestId'] ?? '').toString();
      final action = (message['action'] ?? '').toString();
      final payload = message['payload'] is Map
          ? Map<String, dynamic>.from(message['payload'] as Map)
          : <String, dynamic>{};

      if (requestId.isEmpty || action.isEmpty) {
        return;
      }

      debugPrint('AppShell 桥接请求：action=$action payload=$payload');

      late final Object? data;
      switch (action) {
        case 'pickImage':
          data = await _pickImagesFromBridge(
            source: ImageSource.gallery,
            payload: payload,
          );
        case 'captureImage':
          data = await _pickImagesFromBridge(
            source: ImageSource.camera,
            payload: payload,
          );
        case 'pickFile':
          data = await _pickFilesFromBridge(payload);
        case 'openExternal':
          data = await _openExternalFromBridge(payload);
        case 'requestPermissions':
          data = await _requestPermissionsFromBridge(payload);
        case 'reloadPage':
          await _reloadPage();
          data = true;
        case 'goBack':
          data = await _goBackFromBridge();
        case 'closeApp':
          await _sendBridgeResponse(
            _controller,
            requestId: requestId,
            success: true,
          );
          await SystemNavigator.pop();
          return;
        case 'getDeviceInfo':
          data = await _getDeviceInfoFromBridge();
        case 'getNetworkStatus':
          data = await _getNetworkStatusFromBridge();
        case 'showToast':
          _showToastFromBridge(context, payload);
          data = true;
        case 'setStatusBar':
          _setStatusBarFromBridge(payload);
          data = true;
        default:
          throw UnsupportedError('Unsupported AppShell action: $action');
      }

      await _sendBridgeResponse(
        _controller,
        requestId: requestId,
        success: true,
        data: data,
      );
    } on Object catch (error, stackTrace) {
      debugPrint('处理 AppShell 桥接请求失败：$error\n$stackTrace');
      if (requestId.isNotEmpty) {
        await _sendBridgeResponse(
          _controller,
          requestId: requestId,
          success: false,
          error: error.toString(),
        );
      }
    }
  }

  Future<Object?> _pickImagesFromBridge({
    required ImageSource source,
    required Map<String, dynamic> payload,
  }) async {
    final multiple =
        source == ImageSource.gallery && _boolValue(payload['multiple']);
    final responseType = (payload['responseType'] ?? 'dataUrl').toString();

    var files = <XFile>[];
    if (source == ImageSource.camera) {
      final file = await _pickCameraImage(
        _imagePicker,
        showPermissionAlert: true,
        controller: _controller,
      );
      if (file != null) {
        files = <XFile>[file];
      }
    } else if (multiple) {
      files = await _imagePicker.pickMultiImage(
        imageQuality: _pickedImageQuality,
        maxWidth: _pickedImageMaxWidth,
        maxHeight: _pickedImageMaxHeight,
      );
    } else {
      final file = await _imagePicker.pickImage(
        source: ImageSource.gallery,
        imageQuality: _pickedImageQuality,
        maxWidth: _pickedImageMaxWidth,
        maxHeight: _pickedImageMaxHeight,
      );
      if (file != null) {
        files = <XFile>[file];
      }
    }

    final serialized = await _serializeXFiles(
      files,
      responseType: responseType,
    );
    return multiple ? serialized : serialized.firstOrNull;
  }

  Future<Object?> _pickFilesFromBridge(Map<String, dynamic> payload) async {
    final responseType = (payload['responseType'] ?? 'uri').toString();
    final includeBinary = responseType == 'dataUrl' || responseType == 'base64';

    final result = await FilePicker.platform.pickFiles(
      allowMultiple: _boolValue(payload['multiple']),
      withData: includeBinary,
    );

    if (result == null) {
      return _boolValue(payload['multiple']) ? <Map<String, dynamic>>[] : null;
    }

    final serialized = await _serializePlatformFiles(
      result.files,
      responseType: responseType,
    );
    return _boolValue(payload['multiple'])
        ? serialized
        : serialized.firstOrNull;
  }

  Future<bool> _openExternalFromBridge(Map<String, dynamic> payload) async {
    final url = (payload['url'] ?? '').toString();
    final uri = Uri.tryParse(url);
    if (uri == null) {
      return false;
    }
    if (_isNetworkUrl(uri.toString())) {
      return false;
    }
    return _openExternalUri(uri);
  }

  Future<Map<String, String>> _requestPermissionsFromBridge(
    Map<String, dynamic> payload,
  ) async {
    final types = (payload['types'] as List<dynamic>? ?? const <dynamic>[])
        .map((type) => type.toString())
        .toList();

    final permissions = <String, Permission>{
      for (final String type in types)
        if (_permissionForType(type) case final Permission permission)
          type: permission,
    };

    if (permissions.isEmpty) {
      return <String, String>{};
    }

    final statuses = await permissions.values.toSet().toList().request();

    return <String, String>{
      for (final MapEntry<String, Permission> entry in permissions.entries)
        entry.key: (statuses[entry.value] ?? PermissionStatus.denied).name,
    };
  }

  Future<bool> _goBackFromBridge() async {
    if (await _controller.canGoBack()) {
      await _controller.goBack();
      return true;
    }
    return false;
  }

  // ── 文件选择器 ──

  Future<List<String>> _handleFileSelector(FileSelectorParams params) async {
    debugPrint(
      'WebView 文件选择： '
      'accept=${params.acceptTypes}, '
      'capture=${params.isCaptureEnabled}, '
      'mode=${params.mode.name}',
    );

    if (params.mode == FileSelectorMode.save) {
      return <String>[];
    }

    try {
      final acceptsImgs = _acceptsImages(params.acceptTypes);
      final imagesOnly = _acceptsOnlyImages(params.acceptTypes);

      if (params.isCaptureEnabled && acceptsImgs) {
        final capturedImage = await _pickCameraImage(_imagePicker);
        return _xFilesToUriStrings(
          capturedImage == null ? const <XFile>[] : <XFile>[capturedImage],
        );
      }

      if (imagesOnly) {
        if (params.mode == FileSelectorMode.openMultiple) {
          final images = await _imagePicker.pickMultiImage(
            imageQuality: _pickedImageQuality,
            maxWidth: _pickedImageMaxWidth,
            maxHeight: _pickedImageMaxHeight,
          );
          return _xFilesToUriStrings(images);
        }

        final image = await _imagePicker.pickImage(
          source: ImageSource.gallery,
          imageQuality: _pickedImageQuality,
          maxWidth: _pickedImageMaxWidth,
          maxHeight: _pickedImageMaxHeight,
        );
        return _xFilesToUriStrings(
          image == null ? const <XFile>[] : <XFile>[image],
        );
      }

      final result = await FilePicker.platform.pickFiles(
        allowMultiple: params.mode == FileSelectorMode.openMultiple,
      );

      if (result == null) {
        return <String>[];
      }

      return result.files
          .map((file) => file.path)
          .whereType<String>()
          .map((path) => Uri.file(path).toString())
          .toList();
    } on Object catch (error, stackTrace) {
      debugPrint('处理文件选择失败：$error\n$stackTrace');
      return <String>[];
    }
  }

  // ── 权限 ──

  Future<void> _handlePlatformPermissionRequest(
    PlatformWebViewPermissionRequest request,
  ) async {
    debugPrint(
      'WebView 权限请求：'
      '${request.types.map((type) => type.name).join(', ')}',
    );

    final permissions = <Permission>[
      if (request.types.contains(WebViewPermissionResourceType.camera))
        Permission.camera,
      if (request.types.contains(WebViewPermissionResourceType.microphone))
        Permission.microphone,
    ];

    if (permissions.isEmpty) {
      await request.deny();
      return;
    }

    final statuses = await permissions.request();
    final allGranted = statuses.values.every((status) => status.isGranted);

    if (allGranted) {
      await request.grant();
      return;
    }

    await request.deny();
  }

  Future<GeolocationPermissionsResponse> _handleGeolocationPermissionRequest(
    GeolocationPermissionsRequestParams request,
  ) async {
    debugPrint('WebView 地理位置权限请求：${request.origin}');
    final status = await Permission.location.request();
    return GeolocationPermissionsResponse(
      allow: status.isGranted,
      retain: status.isGranted,
    );
  }

  // ── 加载序列 ──

  Future<void> _startLoadSequence({
    required bool rebuildWebView,
    required bool resetRetryCount,
  }) async {
    _cancelStartupWatchdog();
    if (!mounted) {
      return;
    }
    if (rebuildWebView) {
      _recreateWebView();
    }

    final generation = _webViewGeneration;
    final controllerSetupFuture = _controllerSetupFuture;

    _hasStartedRemoteMainFrame = false;
    setState(() {
      _isLoadingPage = true;
      _hasMainFrameError = false;
      _hasMeasuredProgress = false;
      _progress = 0;
      if (resetRetryCount) {
        _startupRetryCount = 0;
      }
      _errorTitle = '页面加载失败';
      _errorMessage = '请检查网络后重试。';
      _currentUrl = _initialUrl;
    });

    await controllerSetupFuture;
    if (!mounted || !_isActiveWebViewGeneration(generation)) {
      return;
    }

    await _waitForWebViewMount(generation);

    debugPrint(
      'WebShell 开始在 WebView #$generation 加载真实地址 '
      '(${_activeRenderMode.logName}): $_initialUrl',
    );
    try {
      _armStartupWatchdog();
      await _controller.loadRequest(_initialUri);
    } on Object catch (error, stackTrace) {
      debugPrint('初始地址加载失败：$error\n$stackTrace');
      _setMainFrameError(
        title: '地址无法加载',
        message: '无法打开 $_initialUrl，请检查地址格式或网络后重试。',
      );
    }
  }

  Future<void> _waitForWebViewMount(int generation) async {
    final isAndroidDebug =
        kDebugMode && defaultTargetPlatform == TargetPlatform.android;
    final usesHybridComposition =
        defaultTargetPlatform == TargetPlatform.android &&
        _activeRenderMode.usesHybridComposition;
    final framesToWait = isAndroidDebug
        ? (usesHybridComposition ? 6 : 4)
        : (usesHybridComposition ? 2 : 1);
    final settleDelay = isAndroidDebug
        ? (usesHybridComposition
              ? const Duration(milliseconds: 250)
              : const Duration(milliseconds: 140))
        : (usesHybridComposition
              ? const Duration(milliseconds: 80)
              : const Duration(milliseconds: 40));

    for (var index = 0; index < framesToWait; index += 1) {
      await SchedulerBinding.instance.endOfFrame;
      if (!mounted || !_isActiveWebViewGeneration(generation)) {
        return;
      }
      await Future<void>.delayed(settleDelay);
      if (!mounted || !_isActiveWebViewGeneration(generation)) {
        return;
      }
    }
  }

  Future<void> _reloadPage() async {
    if (!mounted) {
      return;
    }
    await _ensureCompatibilityPlanApplied();
    if (!mounted) {
      return;
    }
    if (!_hasBootstrapped) {
      await _recoverFromBrokenStartupState(deepReset: true);
      await _startLoadSequence(rebuildWebView: true, resetRetryCount: true);
      return;
    }
    setState(() {
      _hasStartedRemoteMainFrame = false;
      _isLoadingPage = true;
      _hasMainFrameError = false;
      _hasMeasuredProgress = false;
      _progress = 0;
      _startupRetryCount = 0;
      _errorTitle = '页面加载失败';
      _errorMessage = '请检查网络后重试。';
    });
    try {
      _armStartupWatchdog();
      await _controller.reload();
    } on Object catch (error, stackTrace) {
      debugPrint('重新加载当前页面失败：$error\n$stackTrace');
      await _startLoadSequence(rebuildWebView: true, resetRetryCount: true);
    }
  }

  // ── UI 构建 ──

  @override
  Widget build(BuildContext context) {
    final showProgressBar =
        _isLoadingPage && (!_hasMeasuredProgress || _progress < 100);
    final showLaunchOverlay = !_hasBootstrapped && !_hasMainFrameError;

    return PopScope<void>(
      canPop: false,
      onPopInvokedWithResult: (didPop, result) {
        if (!didPop) {
          unawaited(_handleBackPressed());
        }
      },
      child: Scaffold(
        backgroundColor: _shellBackgroundColor,
        body: DecoratedBox(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: <Color>[_shellBackgroundColor, const Color(0xFFF4FBF7)],
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
            ),
          ),
          child: Stack(
            children: <Widget>[
              Visibility(
                visible: !_hasMainFrameError,
                child: _webViewWidget,
              ),
              if (showProgressBar)
                Positioned(
                  top: 0,
                  left: 0,
                  right: 0,
                  child: TopProgressBar(
                    progress: _progress,
                    hasMeasuredProgress: _hasMeasuredProgress,
                  ),
                ),
              if (showLaunchOverlay)
                Positioned.fill(
                  child: LaunchOverlay(
                    progress: _progress,
                    hasMeasuredProgress: _hasMeasuredProgress,
                  ),
                ),
              if (_hasMainFrameError)
                Positioned.fill(
                  child: ErrorOverlay(
                    title: _errorTitle,
                    message: _errorMessage,
                    currentUrl: _currentUrl,
                    onRetry: _reloadPage,
                  ),
                ),
            ],
          ),
        ),
      ),
    );
  }
}

// coverage:ignore-end
