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

import 'package:app_tracking_transparency/app_tracking_transparency.dart';
import 'package:applovin_max/applovin_max.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:logging/logging.dart';
import 'package:lottie/lottie.dart';
import 'package:provider/provider.dart';
import 'package:puzzleweave/ads/applovin_ads_controller.dart';
import 'package:puzzleweave/audio/jc_audio_controller.dart';
import 'package:puzzleweave/collection/collection_screen.dart';
import 'package:puzzleweave/config/config.dart';
import 'package:puzzleweave/config/device.dart';
import 'package:puzzleweave/firebase/adjust_helper.dart';
import 'package:puzzleweave/homepage/home_board_play.dart';
import 'package:puzzleweave/l10n/app_localizations.dart';
import 'package:puzzleweave/models/cached_request.dart';
import 'package:puzzleweave/models/data.dart';
import 'package:puzzleweave/models/download.dart';
import 'package:puzzleweave/models/items.dart';
import 'package:puzzleweave/persistence/persistence.dart';
import 'package:puzzleweave/platform/my_method_channel.dart';
import 'package:puzzleweave/play/board_play.dart';
import 'package:puzzleweave/settings/settings_screen.dart';
import 'package:puzzleweave/skin/skin.dart';
import 'package:puzzleweave/utils/mybutton.dart';
import 'package:puzzleweave/utils/utils.dart';

import '../ads/ads_state.dart';

final Logger _log = Logger('home_screen');

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

  @override
  State<StatefulWidget> createState() => _HomeScreen();
}

const int minimumRemoteLoadCount = 30; // 假设加载到 30 张图才算网络畅通

class _HomeScreen extends AdsState<HomeScreen> with TickerProviderStateMixin {
  late Device device;
  late JcAudioController audio;
  late Data data;
  List<ListItem>? latest;
  late CachedRequest latestCachedRequest;
  late StreamSubscription? latestSubscription;

  // 自定义画布控制器（可选，用于控制画布绘制逻辑）
  final _canvasKey = GlobalKey<HomeBoardPlayState>();
  // !!! 新增：用于定位 Collection 按钮的 GlobalKey
  final GlobalKey _collectionKey = GlobalKey();

  bool isLoading = true;

  // !!! 新增：Collection 按钮的动画控制器和动画
  late AnimationController _collectionController; // 左上角 collection button 的动画控制器
  late Animation<double> _collectionAnimation; // 放大/缩小动画

  bool firstRun = false;

  @override
  void initState() {
    super.initState();

    _log.info("首页初始化");

    // 在组件绘制后检查 firstRun 并导航
    if (Persistence().firstRun) {
      firstRun = true;
      WidgetsBinding.instance.addPostFrameCallback((_) {
        // 仅当未跳转过时执行
        _handleFirstRunNavigation();
      });
      Persistence().firstRun = false;
    }

    device = context.read<Device>();
    audio = context.read<JcAudioController>();
    data = context.read<Data>();
    latestCachedRequest = data.latest;
    // 主动获取缓存数据（关键）
    final cachedData = latestCachedRequest.cachedData;
    if (cachedData != null) {
      _onLatestDataUpdate(cachedData);
    }
    latestSubscription = latestCachedRequest.stream.listen(_onLatestDataUpdate, onError: _onLatestDataError);

    // !!! 改造点 1: 初始化 Collection 按钮动画
    _collectionController =
        AnimationController(
          // 设定总时长
          duration: const Duration(milliseconds: 300),
          vsync: this,
        )..addStatusListener((status) {
          if (status == AnimationStatus.completed) {
            audio.playSfx(SfxType.pop);
          }
        });

    // !!! 改造点 2: 使用 TweenSequence 实现平滑的放大和缩小
    _collectionAnimation = TweenSequence<double>([
      // 阶段 1: 放大到 1.3 (占总时长的 50%)
      TweenSequenceItem(tween: Tween<double>(begin: 1.0, end: 1.4).chain(CurveTween(curve: Curves.easeOut)), weight: 40.0),
      // 阶段 2: 缩小回 1.0 (占总时长的 50%)
      TweenSequenceItem(tween: Tween<double>(begin: 1.4, end: 1.0).chain(CurveTween(curve: Curves.easeIn)), weight: 60.0),
    ]).animate(_collectionController);

    audio.startMusic();
  }

  // 首页初始化之后的跳转，首次运行直接进入play页面，上次从play页面退出有缓存存在也跳转到play页面
  void _handleFirstRunNavigation() async {
    _log.info('First run detected, navigating to initial play page.');
    final AssetItem initialItem = AssetItem(
      Config.firstId,
      '',
      2000,
      3000,
      3,
      false,
      'assets/builtin/${Config.firstId}.jpeg',
      'assets/builtin/${Config.firstId}.jpeg',
    );
    return gotoPlay(initialItem, firstRun: true);
  }

  // 检查是否需要跳转到boardplay
  void checkGoPlay() async {
    if (currentItem != null) {
      final jsonFile = await localFile(currentItem!.jsonPath);
      final exists = await jsonFile.exists();

      // !!! 关键修复：检查当前组件是否还在组件树中
      if (!mounted) return;

      if (exists) {
        gotoPlay(currentItem!);
      }
    }
  }

  @override
  void dispose() {
    latestSubscription?.cancel();
    _collectionController.dispose();
    super.dispose();
  }

  _onLatestDataUpdate(datalist) {
    _log.info('_onLatestDataUpdate.... ');
    if (datalist != null) {
      bool check = false;
      if (currentItem == null && datalist != null && !firstRun) {
        check = true;
      }
      latest = datalist as List<ListItem>;
      isLoading = false;
      setState(() {});

      // 1. 检查数据量是否达到最低要求 (>= 30)
      final bool hasSufficientData = datalist.length >= minimumRemoteLoadCount;

      // 2. 检查数据是否来自最近一次成功的网络请求
      final bool isNetworkActive = latestCachedRequest.hasRecentSuccessfulFetch; // !!! 关键检查点

      if (hasSufficientData) {
        // 如果数据完整，无论是否是缓存数据，都尝试初始化第三方服务（因为主页已经可以显示了）
        if (!hasInit) {
          initThird();
        }

        // !!! 核心修改：只有在数据完整且最近网络请求成功时，才启动预加载
        if (isNetworkActive) {
          _log.info('Data sufficient AND Network Active. Starting preload.');
          Future.delayed(const Duration(seconds: 3), () => _preloadNextImages());
        } else {
          // 数据完整，但来自缓存，网络状态未知，3秒后尝试刷新（refresh）
          _log.info('Data sufficient BUT Network status unknown/inactive. Attempting refresh in 3s.');
          Future.delayed(Duration(seconds: 3), () => refresh());
        }
      } else {
        // 数据不足 (例如，只有内置图)，无论是缓存还是远程失败，都需要重试
        _log.info('Data insufficient (only ${datalist.length} items). Attempting refresh in 3s.');
        Future.delayed(Duration(seconds: 3), () => refresh());
      }

      if (check) {
        checkGoPlay();
      }
    }
  }

  _onLatestDataError(error) {
    _log.info('_onLatestDataError.... $error');
    if (latest == null || latest!.isEmpty || latest!.length < 20) {
      // 列表数据如果少于20，说明只是内置图，仍然刷新远程请求
      _log.warning("_onLatestDataError, retry again");
      // refresh();
      Future.delayed(Duration(seconds: 3), () => refresh());
    }
  }

  Future<void> refresh() async {
    _log.info('refresh...');
    await latestCachedRequest.refresh();
  }

  // ListItem? get currentItem {
  //   if (latest != null && latest!.isNotEmpty && data.currentLevel < latest!.length) {
  //     // return latest![data.currentLevel]; // 原来的逻辑，太过简单，如果后台图片有调整顺序变了，用户可能会遇到重复的图
  //     // todo... 改成从latest列表中查找首个 data.completedWorks 中不存在的图（即首个未完成图）
  //   }
  //   return null;
  // }

  ListItem? get currentItem {
    // 1. 确保 latest 数据已加载
    if (latest == null || latest!.isEmpty) {
      return null;
    }

    // 2. 获取已完成作品的唯一标识符集合，方便快速查找
    // 假设 ListItem 的 id/url/name 等属性是其唯一标识。
    // 我们使用 id 作为唯一标识符。
    final Set<String> completedIds = data.completedWorks.value.map((work) => work.id).toSet();

    // 3. 遍历 latest 列表，查找第一个未完成的 Item
    for (final item in latest!) {
      // 假设 ListItem 有一个唯一的 id 属性。
      // 如果 ListItem 没有 id，您需要使用其 URL 或其他唯一标识。
      // 这里我们假设 ListItem 是 RemoteItem/AssetItem 的基类，它们有一个 String 类型的 id 属性。
      final String itemId = item.id;

      // 检查这个 id 是否在已完成集合中
      if (!completedIds.contains(itemId)) {
        _log.info('Found current item: $itemId');
        return item; // 返回找到的第一个未完成的 Item
      }
    }

    // 4. 如果所有图片都完成了
    _log.info('All items in the latest list have been completed.');
    return null;
  }

  /// 预加载未来 N 张图片到磁盘，并最后触发当前关卡下载以最大化内存缓存命中率。
  void _preloadNextImages() {
    // 预加载数量 (包括当前关卡在内，共 20 个)
    const int totalPreloadCount = 20;

    // 1. 确保 latest 数据已加载
    if (latest == null || latest!.isEmpty || latest!.length < minimumRemoteLoadCount) {
      _log.info('Preload failed: latest list is empty.');
      return;
    }

    // 2. 查找当前未完成的第一张图片的索引 (Index of currentItem)
    final Set<String> completedIds = data.completedWorks.value.map((work) => work.id).toSet();
    int startIndex = -1;
    for (int i = 0; i < latest!.length; i++) {
      if (!completedIds.contains(latest![i].id)) {
        startIndex = i;
        break;
      }
    }

    if (startIndex == -1) {
      _log.info('Preload: All images completed, nothing to preload.');
      return;
    }

    // 确定预加载范围 (从当前图片startIndex到 totalPreloadCount 个图片)
    final int endPreloadIndex = min(startIndex + totalPreloadCount, latest!.length);

    // 3. 准备要加载的列表 (从 startIndex 开始)
    final List<ListItem> itemsToLoad = latest!.sublist(startIndex, endPreloadIndex);

    if (itemsToLoad.isEmpty) {
      _log.info('Preload: No items found in the range.');
      return;
    }

    // 4. 将当前关卡 (第一个元素) 移动到列表的末尾
    final ListItem currentItemToLoad = itemsToLoad.removeAt(0);
    itemsToLoad.add(currentItemToLoad);

    _log.info('Preloading ${itemsToLoad.length} images. Current item: ${currentItemToLoad.id} will be loaded last.');

    // 5. 循环触发 ItemLoader 加载
    int preloadCount = 0;
    for (final itemToLoad in itemsToLoad) {
      // 对远程图片进行预加载
      // 调用 ItemLoader.load，它会使用 Download 单例进行下载和缓存
      // 我们不关心返回值或 Future，只是触发下载
      if (itemToLoad is RemoteItem) {
        try {
          // 触发下载。对于非当前关卡，下载器会完成下载并写入磁盘，然后可能释放内存。
          // 对于当前关卡 (最后一个被调用的)，它留在内存中的可能性最大。
          ItemLoader.load(itemToLoad);
          preloadCount++;
        } catch (e) {
          _log.warning('Failed to load item for preloading: ${itemToLoad.id}, error: $e');
        }
      }
    }

    _log.info('Preload initiated for $preloadCount remote images, current item was last.');
  }

  @override
  Widget build(BuildContext context) {
    if (isLoading) return scrollableDummy;

    // 2. 计算画布尺寸（宽=屏幕宽-60，高=宽×3/2）
    // final canvasWidth = device.screenSize.width - 30 * 2; // 左右各30px
    // final canvasHeight = canvasWidth * 3 / 2;

    final double availableHeight = device.screenSize.height - device.appBarHeight - device.bannerHeight - 120;

    final double paddedWidth = device.screenSize.width - 2 * 30; // padding width 30
    final double paddedHeight = availableHeight;

    final double targetWidth = paddedWidth;
    final double targetHeight = targetWidth * device.aspectRatio;

    final double canvasWidth;
    final double canvasHeight;

    if (targetHeight > paddedHeight) {
      canvasHeight = paddedHeight;
      canvasWidth = paddedHeight / device.aspectRatio;
    } else {
      canvasWidth = targetWidth;
      canvasHeight = targetHeight;
    }

    return Scaffold(
      backgroundColor: SkinHelper.colorWhite,
      appBar: AppBar(
        backgroundColor: SkinHelper.colorWhite,
        // elevation: 1,
        centerTitle: true,
        leading: RepaintBoundary(
          // !!! 改造点 3: 添加 ScaleTransition
          key: _collectionKey, // 关联 GlobalKey
          child: ScaleTransition(
            scale: _collectionAnimation, // 使用定义的放大/缩小动画
            child: IconButton(
              onPressed: () {
                audio.playSfx(SfxType.click);
                Navigator.push(context, CollectionScreen.buildRoute());
              },
              icon: const Icon(Icons.collections, color: Colors.black87),
            ),
          ),
        ),
        // title: const Text(
        //   'Jigsort Solitaire',
        //   style: TextStyle(color: Colors.black87, fontWeight: FontWeight.bold, fontSize: 24),
        // ),
        // 🚀 改造点：将 Text 标题替换为 SvgPicture
        title: SvgPicture.asset(
          'assets/images/title.svg', // 替换为您的 SVG 文件路径
          height: 32, // 根据您的设计调整高度，确保它在 AppBar 中显示良好
          // colorFilter: const ColorFilter.mode(Colors.black87, BlendMode.srcIn), // 如果SVG是单色，可以设置颜色
          placeholderBuilder: (BuildContext context) => const Text(
            // 占位符，以防SVG加载失败
            'Jigsort Solitaire',
            style: TextStyle(color: Colors.black87, fontWeight: FontWeight.bold, fontSize: 24),
          ),
        ),
        actions: [
          IconButton(
            onPressed: () {
              audio.playSfx(SfxType.click);
              // Navigator.push(context, SettingsDialog.buildRoute());
              Navigator.push(context, SettingScreen.buildRoute());
              // AppLovinMAX.showMediationDebugger();
            },
            icon: const Icon(Icons.settings, color: Colors.black87),
          ),
        ],
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Expanded(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                // 2. 画布区域（固定尺寸）
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 30), // 左右30px
                  child: SizedBox(
                    width: canvasWidth,
                    height: canvasHeight,
                    child: ValueListenableBuilder(
                      valueListenable: data.completedWorks,
                      builder: (context, value, child) {
                        return HomeBoardPlay(
                          key: _canvasKey,
                          canvasWidth: canvasWidth,
                          canvasHeight: canvasHeight,
                          collectionKey: _collectionKey,
                          onCollectionDone: () {
                            // collection unlocking 动画结束，启动collection button 的接收反馈动画
                            _log.info('onCollectionDone, 启动合集收纳反馈动画');
                            audio.playSfx(SfxType.appear);
                            _collectionController.forward(from: 0.0);
                          },
                        );
                      },
                    ),
                  ),
                ),
                playButton,
              ],
            ),
          ),
          SafeArea(
            child: SizedBox(
              // 始终预留一个固定的高度，防止布局跳变
              height: context.read<Device>().bannerHeight,
              width: double.infinity,
              child: FutureBuilder<bool>(
                future: _bannerReadyAndShouldShow(),
                builder: (context, snapshot) {
                  if (snapshot.hasData && snapshot.data == true) {
                    return adBanner;
                  }
                  return Container(
                    // color: Colors.grey.shade100,
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }

  void gotoPlay(ListItem item, {bool firstRun = false}) async {
    _log.info('goto play, firstRun = $firstRun');

    // !!! 增加保护
    if (!mounted) return;

    PageRouteBuilder? pageRouteBuilder = BoardPlay.buildRoute(item, firstRun: firstRun);
    final result = await Navigator.push(context, pageRouteBuilder);

    if (!mounted) return;

    if (result != null && result == true) {
      // 通关返回, 展示翻牌
      _canvasKey.currentState?.startFlipAnimation();

      final bool hasSufficientData = latest != null && latest!.length >= minimumRemoteLoadCount;
      final bool isNetworkActive = latestCachedRequest.hasRecentSuccessfulFetch;

      if (hasSufficientData) {
        // 1. 数据完整：如果网络活跃，立即顺延预加载。
        if (isNetworkActive) {
          _log.info('Game finished, data complete & Network Active. Triggering sequential preloading...');
          _preloadNextImages();
        } else {
          // 2. 数据完整但网络不活跃/状态未知：尝试刷新，让 _onLatestDataUpdate 负责后续处理
          _log.info('Game finished, data complete but Network inactive. Attempting refresh.');
          refresh();
        }
      } else {
        // 3. 数据不完整：无论如何都需要刷新，让 _onLatestDataUpdate 重新处理
        _log.info('Game finished, remote data incomplete. Attempting refresh...');
        refresh();
      }
    } else {
      // 非关卡通关返回，在这里播放插屏广告
      // showInterstitialAd("level_exit", currentItem!.id, data.currentLevel);
    }
  }

  Widget get playButton {
    return MyElevatedButton(
      width: device.isTablet ? 300 : 200,
      height: 70,
      borderRadius: BorderRadius.circular(20),
      gradient: LinearGradient(colors: [SkinHelper.coreBgColor, SkinHelper.slotBorderColor]),
      onPressed: () async {
        audio.playSfx(SfxType.click);
        if (currentItem != null) {
          gotoPlay(currentItem!);
        } else {
          Fluttertoast.showToast(
            msg: AppLocalizations.of(context)!.noMorePicture,
            toastLength: Toast.LENGTH_SHORT,
            gravity: ToastGravity.CENTER,
            timeInSecForIosWeb: 1,
            backgroundColor: SkinHelper.slotBorderColor,
            textColor: Colors.white,
            fontSize: 16.0,
          );
        }
      },
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            AppLocalizations.of(context)!.play,
            style: TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold),
          ),
          ValueListenableBuilder<List<Work>>(
            valueListenable: data.completedWorks,
            builder: (context, isSoundOn, child) {
              return Text('${AppLocalizations.of(context)!.level} ${data.currentLevel + 1}', style: const TextStyle(color: Colors.white, fontSize: 16));
            },
          ),
        ],
      ),
    );
  }

  Widget get scrollableDummy => Scaffold(
    body: LayoutBuilder(
      builder: (p0, p1) {
        return SingleChildScrollView(
          physics: const AlwaysScrollableScrollPhysics(),
          child: SizedBox(
            height: p1.maxHeight,
            child: Center(child: ListView(shrinkWrap: true, children: [Lottie.asset('assets/lottie/loading.json', height: 100)])),
          ),
        );
      },
    ),
  );

  ///////////////////////// 初始化相关 /////////////////////////

  static bool hasInit = false;
  static MyMethodChannel platform = MyMethodChannel();

  // 在列表刷出来后才正式初始化admod等组件
  void initThird() async {
    if (hasInit) return;

    hasInit = true;

    // 有了UMP后， 这里的ATT就不需要了
    // bool auth = await initATT();
    // if (auth) {
    //   await platform.setHasUserConsent(true);
    //   await platform.setAdvertiserTrackingEnabled(true);
    // }
    // await initUMP(); // 征询欧洲用户同意 // applovin max 已经可以自动处理，这里不需要了
    TrackingStatus attStatus = await AppTrackingTransparency.trackingAuthorizationStatus;
    if (attStatus == TrackingStatus.authorized && Platform.isIOS) {
      // ATT 通过之后，ios需要调用相关的原生sdk接口做进一步的初始化
      // await platform.setHasUserConsent(true);
      // await platform.setAdvertiserTrackingEnabled(true);
    }
    initFCM(); // 消息推送许可弹窗
    initAd(); // admod 的广告加载安排在iOS ATT 之后，以便能够加载到个性化广告
    AdjustHelper.init(Persistence().uuid); // 初始化Adjust

    final idfa = await AppTrackingTransparency.getAdvertisingIdentifier();
    _log.info("idfa: $idfa");
  }

  /////////////////////////// ATT ///////////////////////////
  // Platform messages are asynchronous, so we initialize in an async method.
  Future<bool> initATT() async {
    TrackingStatus status = await AppTrackingTransparency.trackingAuthorizationStatus;
    _log.info('initATT111 $status');
    // If the system can show an authorization request dialog
    if (status == TrackingStatus.notDetermined) {
      // Show a custom explainer dialog before the system dialog
      // await showCustomTrackingDialog(context);
      // Wait for dialog popping animation
      // await Future.delayed(const Duration(milliseconds: 200));
      // Request system's tracking authorization dialog
      status = await AppTrackingTransparency.requestTrackingAuthorization();
      _log.info('initATT222 $status');
    }
    if (status == TrackingStatus.authorized) {
      return true;
    }
    return false;
  }

  // no need
  Future<void> showCustomTrackingDialog(BuildContext context) async => await showDialog<void>(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('Dear User'),
      content: const Text(
        'We care about your privacy and data security. We keep this app free by showing ads. '
        'Can we continue to use your data to tailor ads for you?\n\nYou can change your choice anytime in the app settings. '
        'Our partners will collect data and use a unique identifier on your device to show you ads.',
      ),
      actions: [TextButton(onPressed: () => Navigator.pop(context), child: const Text('Continue'))],
    ),
  );
  /////////////////////////////////////////////////////////

  /// 初始化广告模块
  initAd() {
    _log.info('initAd');
    // AdsController adsController = context.read<AdsController>();
    // adsController.initialize();
    ApplovinAdsController applovinAdsController = context.read<ApplovinAdsController>();
    applovinAdsController.initialize();
  }

  /// gallery页面加载的时候，可能广告模块还没有初始化完毕
  Future<bool> _bannerReadyAndShouldShow() async {
    bool ready = await adSDKReady();
    return ready && shouldShowBannerAd(data.currentLevel);
  }

  /////////////////////////// FCM ///////////////////////////
  // 消息推送许可弹框
  initFCM() async {
    try {
      final fcmToken = await FirebaseMessaging.instance.getToken();
      _log.info("FCM Token: $fcmToken");

      FirebaseMessaging messaging = FirebaseMessaging.instance;
      NotificationSettings settings = await messaging.requestPermission(
        alert: true,
        announcement: false,
        badge: true,
        carPlay: false,
        criticalAlert: false,
        provisional: false,
        sound: true,
      );

      _log.warning('User granted permission: ${settings.authorizationStatus}');
    } catch (e) {
      FirebaseCrashlytics.instance.log("FCM FirebaseMessaging.instance.getToken error: $e");
      _log.warning(e);
    }
  }
}
