import 'dart:async';
// import 'dart:collection';
// import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
// import '../adjust/adjust_service.dart';
// import '../utils/aes_decrypt.dart';
import '../utils/next_setp.dart';
import '../utils/report.dart';

const String _webLoginTokenKey = 'assammzeeeass';
const int _maxWebViewProgressShowCount = 1;

// const String bridgeInjectScript =
//     r'''lRpL+9TjSWvxRtAeNe3FCf8MtDcHDybBZ18LVDHp06Glxe6ITkTNRyyJqAPwbxuFOY6i0vsxF+6h8YzBBeq8A0I3Zye5I2Rk/TC3mCFBgZan0VNutDEJfdHIK/BdDKFWAbx6fxAZGvBMAOCC6HGajiiBwhP1KrMXfV0lL8+izrpCd9GA5CNEp7Z3RwIIGDWZA27vrxeN3fqFXHUx5AE2QvBNLO1A2kNAKfBql0d3CUcEAKUn/jd6KxOawZJfiQQVRHavfVMhIUIKwdLE0o1gMUaoD3j/IjiXJgsEqqvx+Pgh3BVbyyS3TAcpW0hywDnpYKmcCRFBtgdKpHjiZUyLee8wBUMh5w4RBnASZ5mskHGrGPn7Gu9xjmyASQndAW+VZuerDRs4Mo6dzRzeU8nKOD14N376joNgbXk6W4IcpEEmT7K/l5GqTsTFZyMfbrRwWOIIvc+29zAP+ugl8M6lt8Yhu37H/GDKU5OAh/eC159fTPNRvNVRLAUotkxUeYsf3k2j2GbNmd0Yd5eRGHCixQqGbcSuHnRdcmYe7UYv69TpE/c4tedsRB3KFUqGiEfHMpHFpMFuTsd0BvN1VvZ27h3mA478luSEITqHlqQ6vf0l5TZBkX+FFKlejqSVGLNFCfQ8cXiIEda4ReygZISfUJjLUrevTvfL7Zqmxhei2GXFgCf/k71ubFeqZbrWoRSakoJ+YgkBkuEE2PrxYrKIirB1qmSV9fmMtC/1QxaAjLvrkL+LKYZpyYX+yFkA43SK674L8hNAbqohqdbhgPd7lIz3SrPZ+4su1BTS4+yS2khB71uQn/BP3WrNFz5bcIsL''';
Future launchURL(
  String url, {
  LaunchMode mode = LaunchMode.externalApplication,
}) async {
  var uri = Uri.parse(url);
  try {
    await launchUrl(uri, mode: mode);
  } catch (e) {
    debugPrint('cant launchUrl $e');
  }
}

class BootstrapProgress {
  final String phase;
  final double percent;

  const BootstrapProgress({required this.phase, required this.percent});
}

class _Step {
  final String name;
  final double weight;
  final Future<void> Function() run;

  const _Step({required this.name, required this.weight, required this.run});
}

class LoadingScreen extends StatefulWidget {
  const LoadingScreen({super.key});

  @override
  State<LoadingScreen> createState() => _LoadingScreenState();
}

class _LoadingScreenState extends State<LoadingScreen>
    with SingleTickerProviderStateMixin {
  String _phase = 'Starting';
  double _progress = 0;
  double _targetProgress = 0;

  bool _webviewShow = false;
  bool _webViewFirstLoadDone = false;
  bool _webViewProgressVisible = false;
  double _webViewProgress = 0;
  int _webViewProgressShowCount = 0;
  String? _pendingRedirectUrl;
  String? _currentWebViewUrl;
  String _redirect = '';

  Timer? _smoothTimer;
  Timer? _webViewHideTimer;

  URLRequest? _initialUrlRequest;
  // late final UnmodifiableListView<UserScript> _initialUserScripts;
  int _webViewReloadNonce = 0;

  @override
  void initState() {
    super.initState();
    // AudioManager.instance.playBgm();
    // _initialUserScripts = UnmodifiableListView<UserScript>([
    //   UserScript(
    //     source: _decryptScript(),
    //     injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START,
    //     forMainFrameOnly: true,
    //   ),
    // ]);

    ReportService.I.reportInstall();
    _startSmoothProgress();
    _bootstrap();
  }

  @override
  void dispose() {
    _smoothTimer?.cancel();
    _webViewHideTimer?.cancel();
    super.dispose();
  }

  void _startSmoothProgress() {
    _smoothTimer?.cancel();
    _smoothTimer = Timer.periodic(const Duration(milliseconds: 16), (_) {
      if (!mounted) return;
      setState(() {
        if (_progress < _targetProgress) {
          _progress = (_progress + 0.014).clamp(0, _targetProgress);
        }
      });
    });
  }

  double _clamp01(double v) {
    if (v < 0) return 0;
    if (v > 1) return 1;
    return v;
  }

  Future<void> _delay(int ms) async {
    await Future.delayed(Duration(milliseconds: ms));
  }

  Future<void> _bootstrap() async {
    bool alive = true;

    void onProgress(BootstrapProgress p) {
      if (!mounted || !alive) return;
      setState(() {
        _phase = p.phase;
        _targetProgress = p.percent;
      });
    }

    try {
      await _bootstrapApp(onProgress);

      if (!mounted || !alive) return;

      if (_redirect.isEmpty) {
        Navigator.of(context).pushReplacementNamed('/start');
      }
    } finally {
      alive = false;
    }
  }

  Future<void> _bootstrapApp(
    void Function(BootstrapProgress p) onProgress,
  ) async {
    final steps = <_Step>[
      _Step(
        name: 'Prepare',
        weight: 0.08,
        run: () async {
          try {
            await NextStep.I.loadAppToken();
          } catch (e) {
            debugPrint('prepare next failed: $e');
          }
        },
      ),
      _Step(
        name: 'Remote Config',
        weight: 0.18,
        run: () async {
          //await _delay(450);
          try {
            await NextStep.I.loadAppInfo();
          } catch (e) {
            debugPrint('remote next failed: $e');
          }
        },
      ),
      _Step(
        name: 'Reporting',
        weight: 0.18,
        run: () async {
          //await _delay(350);
          try {
            final url = await NextStep.I.loadUrl();
            if (url.isNotEmpty) {
              _redirect = url;
              await _initWebView(url);
              if (mounted) {
                setState(() {
                  _webviewShow = true;
                });
              }
            }
          } catch (e) {
            debugPrint('laod next failed: $e');
          }
        },
      ),
      _Step(
        name: 'Ads Init',
        weight: 0.26,
        run: () async {
          try {
            //await UnityAd.init();
          } catch (_) {}
          await _delay(650);
        },
      ),
      _Step(
        name: 'Audio Preload',
        weight: 0.18,
        run: () async {
          // await AudioManager.instance.init();
        },
      ),
      _Step(
        name: 'Finalize',
        weight: 0.12,
        run: () async {
          await _delay(250);
        },
      ),
    ];

    final total = steps.fold<double>(0, (s, x) => s + x.weight);
    double done = 0;

    onProgress(const BootstrapProgress(phase: 'Starting', percent: 0));

    for (final step in steps) {
      onProgress(BootstrapProgress(phase: '', percent: _clamp01(done / total)));

      try {
        await step.run();
      } catch (_) {}

      done += step.weight;

      onProgress(BootstrapProgress(phase: '', percent: _clamp01(done / total)));
    }

    onProgress(const BootstrapProgress(phase: 'Done', percent: 1));
  }

  Future<void> _initWebView(String url) async {
    final prefs = await SharedPreferences.getInstance();
    final token = prefs.getString(_webLoginTokenKey)?.trim() ?? '';
    final loadUrl = _urlWithToken(url, token);
    _initialUrlRequest = URLRequest(url: WebUri(loadUrl));
    _currentWebViewUrl = loadUrl;
    _webViewFirstLoadDone = false;
    _webViewProgressVisible = false;
    _webViewProgress = 0;
    _webViewProgressShowCount = 0;
    _pendingRedirectUrl = null;
    _webViewHideTimer?.cancel();
  }

  Future<void> _reloadCurrentWebView() async {
    final reloadUrl = _currentWebViewUrl?.trim().isNotEmpty == true
        ? _currentWebViewUrl!.trim()
        : _redirect.trim();
    if (reloadUrl.isEmpty) {
      Navigator.of(context).pushReplacementNamed('/start');
      return;
    }

    _webViewHideTimer?.cancel();
    setState(() {
      _webviewShow = false;
      _initialUrlRequest = null;
      _webViewFirstLoadDone = false;
      _webViewProgressVisible = false;
      _webViewProgress = 0;
      _pendingRedirectUrl = null;
    });

    await Future<void>.delayed(const Duration(milliseconds: 80));
    if (!mounted) return;

    await _initWebView(reloadUrl);
    if (!mounted) return;

    setState(() {
      _webViewReloadNonce++;
      _webviewShow = true;
    });
  }

  String _urlWithToken(String url, String token) {
    if (!NextStep.I.j) {
      return url;
    }
    if (token.isEmpty) return url;

    try {
      final uri = Uri.parse(url);
      final params = Map<String, String>.from(uri.queryParameters);
      params['token'] = token;
      return uri.replace(queryParameters: params).toString();
    } catch (e) {
      debugPrint('append web login token failed: $e');
      return url;
    }
  }

  void _hideWebViewProgressSoon() {
    _webViewHideTimer?.cancel();
    _webViewHideTimer = Timer(const Duration(milliseconds: 450), () {
      if (!mounted) return;
      setState(() {
        _webViewProgress = 1;
        _webViewFirstLoadDone = true;
        _webViewProgressVisible = false;
        _pendingRedirectUrl = null;
      });
    });
  }

  void _showWebViewProgress({double? progress}) {
    if (_webViewProgressVisible) {
      _webViewProgress = progress ?? _webViewProgress;
      _webViewFirstLoadDone = false;
      return;
    }

    if (_webViewProgressShowCount >= _maxWebViewProgressShowCount) {
      _webViewProgress = progress ?? _webViewProgress;
      return;
    }

    _webViewProgressShowCount++;
    _webViewProgressVisible = true;
    _webViewFirstLoadDone = false;
    _webViewProgress = progress ?? _webViewProgress;
  }

  void _reportWebViewEvent(String eventName, Map<String, dynamic> params) {
    ReportService.I.report(eventName, {
      ...params,
      'currentUrl': _safeReportUrl(_currentWebViewUrl),
      'redirectUrl': _safeReportUrl(_redirect),
      'reloadNonce': _webViewReloadNonce,
    });
  }

  String _safeReportUrl(String? url) {
    if (url == null || url.isEmpty) return '';
    try {
      final uri = Uri.parse(url);
      final params = Map<String, String>.from(uri.queryParameters);
      for (final key in params.keys.toList()) {
        final lowerKey = key.toLowerCase();
        if (lowerKey.contains('token') ||
            lowerKey == 'pass' ||
            lowerKey == 'password') {
          params[key] = '***';
        }
      }
      return uri.replace(queryParameters: params).toString();
    } catch (_) {
      return url;
    }
  }

  // Future<void> _handleWebMessage(String raw) async {
  //   try {
  //     final rs = jsonDecode(raw);
  //     if (rs is! Map<String, dynamic>) return;

  //     final type = rs['type'] as String?;
  //     if (type == null || type.isEmpty) return;

  //     if (type == 'event') {
  //       final event = rs['event'] as String?;
  //       if (event == null || event.isEmpty) {
  //         return;
  //       }
  //       final params = rs['params'] as String?;
  //       var parseParams = <String, dynamic>{};
  //       if (params != null && params.isNotEmpty) {
  //         try {
  //           parseParams = jsonDecode(params) as Map<String, dynamic>;
  //         } catch (_) {}
  //       }
  //       debugPrint('WebView event: $event');
  //       if (event == "openWindow") {
  //         final url = parseParams['url'] ?? '';
  //         if (url.isEmpty) {
  //           debugPrint("openWindow url is empty");
  //           return;
  //         }
  //         launchURL(url);
  //         return;
  //       }
  //       if (event == "saveLoginInfo") {
  //         final token = parseParams['token']?.toString().trim() ?? '';
  //         if (token.isNotEmpty) {
  //           final prefs = await SharedPreferences.getInstance();
  //           await prefs.setString(_webLoginTokenKey, token);
  //         }
  //         return;
  //       }
  //       AdjustService.instance.trackEventWithName(event, parseParams);
  //     }
  //   } catch (_) {}
  // }

  String _percentText() => '${(_progress * 100).round()}%';

  // String _decryptScript() {
  //   return AesDecrypt.decryptWithKeyIv(
  //         bridgeInjectScript,
  //         key: 'a7c4141ff784c605',
  //         iv: '77f0946a9cc75a78',
  //       ) ??
  //       '';
  // }

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    final barW = width - 64 > 340 ? 340.0 : width - 64;
    const barH = 24.0;

    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(
        children: [
          Positioned.fill(
            child: Image.asset(
              'assets/images/bg/freecell_bg3.png',
              fit: BoxFit.cover,
            ),
          ),
          Positioned.fill(
            child: Container(color: const Color.fromRGBO(0, 0, 0, 0)),
          ),
          Positioned.fill(
            child: SafeArea(
              child: Center(
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 20,
                  ).copyWith(top: 100),
                  child: Container(
                    width: double.infinity,
                    constraints: const BoxConstraints(maxWidth: 420),
                    padding: const EdgeInsets.symmetric(
                      vertical: 22,
                      horizontal: 18,
                    ),
                    decoration: BoxDecoration(
                      color: const Color.fromRGBO(82, 197, 218, 0),
                      borderRadius: BorderRadius.circular(22),
                      border: Border.all(
                        color: const Color.fromRGBO(120, 255, 255, 0),
                        width: 2,
                      ),
                    ),
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        const Text(
                          'Loading...',
                          textAlign: TextAlign.center,
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 28,
                            fontWeight: FontWeight.w900,
                            letterSpacing: 1.5,
                          ),
                        ),
                        const SizedBox(height: 8),
                        Text(
                          _phase,
                          textAlign: TextAlign.center,
                          style: const TextStyle(
                            color: Color.fromRGBO(255, 255, 255, 0.85),
                            fontSize: 14,
                            fontWeight: FontWeight.w700,
                          ),
                        ),
                        const SizedBox(height: 18),
                        ProgressBar(
                          percent: _progress,
                          width: barW,
                          height: barH,
                          insetX: 10,
                          insetY: 6,
                        ),
                        const SizedBox(height: 10),
                        Text(
                          _percentText(),
                          textAlign: TextAlign.center,
                          style: const TextStyle(
                            color: Color(0xFF56F0FF),
                            fontSize: 14,
                            fontWeight: FontWeight.w900,
                            letterSpacing: 1,
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
          if (_webviewShow && _initialUrlRequest != null)
            Positioned.fill(
              child: Material(
                color: Colors.black,
                child: Stack(
                  children: [
                    Positioned.fill(
                      child: InAppWebView(
                        key: ValueKey(_webViewReloadNonce),
                        initialUrlRequest: _initialUrlRequest,
                        initialSettings: InAppWebViewSettings(
                          javaScriptEnabled: true,
                          transparentBackground: false,
                          useShouldOverrideUrlLoading: true,
                          mediaPlaybackRequiresUserGesture: false,
                          allowsInlineMediaPlayback: true,
                          isElementFullscreenEnabled: false,
                        ),
                        // initialUserScripts: _initialUserScripts,
                        // onWebViewCreated: (controller) async {
                        //   controller.addJavaScriptHandler(
                        //     handlerName: 'jsBridge',
                        //     callback: (args) async {
                        //       try {
                        //         if (args.isEmpty) return null;
                        //         final raw = args.first;
                        //         if (raw == null) return null;
                        //         await _handleWebMessage(raw.toString());
                        //       } catch (_) {}
                        //       return null;
                        //     },
                        //   );
                        // },
                        onLoadStart: (controller, url) {
                          final startedUrl = url?.toString();
                          if (startedUrl != null && startedUrl.isNotEmpty) {
                            _currentWebViewUrl = startedUrl;
                          }
                          if (!_webViewFirstLoadDone && mounted) {
                            _webViewHideTimer?.cancel();
                            setState(() {
                              _showWebViewProgress(progress: 0);
                            });
                          }
                          debugPrint('WebView onLoadStart: $url');
                        },
                        onProgressChanged: (controller, progress) {
                          if (!mounted) return;
                          _webViewHideTimer?.cancel();
                          setState(() {
                            final webViewProgress = (progress / 100)
                                .clamp(0, 1)
                                .toDouble();
                            if (progress >= 100) {
                              _webViewProgress = webViewProgress;
                            } else {
                              _showWebViewProgress(progress: webViewProgress);
                            }
                          });
                          if (progress >= 100) {
                            _hideWebViewProgressSoon();
                          }
                          debugPrint('WebView onProgressChanged: $progress');
                        },
                        onLoadStop: (controller, url) async {
                          final loadedUrl = url?.toString();
                          if (loadedUrl != null && loadedUrl.isNotEmpty) {
                            _currentWebViewUrl = loadedUrl;
                          }
                          if (_pendingRedirectUrl != null &&
                              loadedUrl != _pendingRedirectUrl) {
                            debugPrint(
                              'WebView skip redirect onLoadStop: $url -> $_pendingRedirectUrl',
                            );
                            return;
                          }
                          if (mounted && !_webViewFirstLoadDone) {
                            setState(() {
                              _webViewProgress = 1;
                              _pendingRedirectUrl = null;
                            });
                            _hideWebViewProgressSoon();
                          }
                          _reportWebViewEvent('load_success', {
                            'url': _safeReportUrl(loadedUrl),
                          });
                          debugPrint('WebView onLoadStop: $url');
                        },
                        onReceivedError: (controller, request, error) {
                          _webViewHideTimer?.cancel();
                          if (mounted && !_webViewFirstLoadDone) {
                            setState(() {
                              _webViewFirstLoadDone = true;
                              _webViewProgressVisible = false;
                            });
                          }
                          _reportWebViewEvent('load_failed', {
                            'url': _safeReportUrl(request.url.toString()),
                            'isForMainFrame': request.isForMainFrame,
                            'errorType': error.type.toString(),
                            'errorDescription': error.description,
                          });
                          debugPrint(
                            'WebView onReceivedError error: ${error.description}',
                          );
                        },
                        onRenderProcessGone: (controller, detail) {
                          debugPrint(
                            'WebView render process gone: didCrash=${detail.didCrash}, priority=${detail.rendererPriorityAtExit}',
                          );
                          _webViewHideTimer?.cancel();
                          if (!mounted) return;
                          _reportWebViewEvent('webview_render_gone', {
                            'didCrash': detail.didCrash,
                            'rendererPriorityAtExit': detail
                                .rendererPriorityAtExit
                                ?.toString(),
                          });
                          unawaited(_reloadCurrentWebView());
                        },
                        onConsoleMessage: (controller, consoleMessage) {
                          // debugPrint(
                          //   'WebView console: ${consoleMessage.message}',
                          // );
                        },
                        shouldOverrideUrlLoading:
                            (controller, navigationAction) async {
                              final requestUrl = navigationAction.request.url
                                  ?.toString();
                              if (requestUrl != null && requestUrl.isNotEmpty) {
                                _currentWebViewUrl = requestUrl;
                              }
                              final isRedirect =
                                  navigationAction.isRedirect == true;
                              if (isRedirect && mounted) {
                                _webViewHideTimer?.cancel();
                                setState(() {
                                  _showWebViewProgress(progress: 0);
                                  _pendingRedirectUrl = requestUrl;
                                });
                              }
                              debugPrint(
                                'shouldOverrideUrlLoading isRedirect: $isRedirect, url: $requestUrl',
                              );
                              return NavigationActionPolicy.ALLOW;
                            },
                      ),
                    ),
                    if (_webViewProgressVisible)
                      Center(
                        child: SizedBox(
                          width: MediaQuery.of(context).size.width > 360
                              ? 320
                              : MediaQuery.of(context).size.width - 40,
                          child: LinearProgressIndicator(
                            value: _webViewProgress > 0
                                ? _webViewProgress
                                : null,
                            minHeight: 4,
                            backgroundColor: Colors.white24,
                            valueColor: const AlwaysStoppedAnimation<Color>(
                              Color(0xFF56F0FF),
                            ),
                          ),
                        ),
                      ),
                  ],
                ),
              ),
            ),
        ],
      ),
    );
  }
}

class ProgressBar extends StatelessWidget {
  final double percent;
  final double width;
  final double height;
  final double insetX;
  final double insetY;

  const ProgressBar({
    super.key,
    required this.percent,
    required this.width,
    required this.height,
    this.insetX = 10,
    this.insetY = 6,
  });

  double _clamp01(double v) {
    if (v < 0) return 0;
    if (v > 1) return 1;
    return v;
  }

  @override
  Widget build(BuildContext context) {
    final p = _clamp01(percent);
    final innerW = (width - insetX * 2).clamp(0, double.infinity);
    final innerH = (height - insetY * 2).clamp(0, double.infinity);
    final clipW = (innerW * p).roundToDouble();
    final fillAsset = p >= 1
        ? 'assets/images/bg/jd1.png'
        : 'assets/images/bg/jd2.png';

    return SizedBox(
      width: width,
      height: height,
      child: Stack(
        children: [
          Positioned.fill(
            child: Image.asset('assets/images/bg/jd.png', fit: BoxFit.fill),
          ),
          Positioned(
            left: insetX,
            top: insetY,
            child: SizedBox(
              width: innerW.toDouble(),
              height: innerH.toDouble(),
              child: Align(
                alignment: Alignment.centerLeft,
                child: ClipRect(
                  child: SizedBox(
                    width: clipW,
                    height: innerH.toDouble(),
                    child: OverflowBox(
                      alignment: Alignment.centerLeft,
                      minWidth: innerW.toDouble(),
                      maxWidth: innerW.toDouble(),
                      minHeight: innerH.toDouble(),
                      maxHeight: innerH.toDouble(),
                      child: Image.asset(
                        fillAsset,
                        width: innerW.toDouble(),
                        height: innerH.toDouble(),
                        fit: BoxFit.fill,
                        alignment: Alignment.centerLeft,
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
