import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:puzzleweave/models/api_helper.dart';
import 'package:puzzleweave/utils/utils.dart';
import 'package:logging/logging.dart';

final Logger _log = Logger('cached_request.dart');

typedef TransformFunction = Future<dynamic> Function(dynamic json);

class CachedRequest with WidgetsBindingObserver {
  /// ✅ 优化：网络状态跟踪
  bool _hasRecentSuccessfulFetch = false;
  bool get hasRecentSuccessfulFetch => _hasRecentSuccessfulFetch;

  /// ✅ 优化：防抖机制
  Timer? _refreshDebouncer;
  static const _refreshDebounceDelay = Duration(seconds: 2);

  /// ✅ 优化：重试机制
  int _retryCount = 0;
  static const _maxRetries = 3;
  static const _retryDelay = Duration(seconds: 5);

  static final Map<String, CachedRequest> _cache = {};

  final String url;
  TransformFunction? transformFunction;
  final StreamController _streamController = StreamController.broadcast();

  dynamic _transformed;
  dynamic get cachedData => _transformed;

  /// ✅ 优化：请求状态跟踪
  bool _isLoading = false;
  bool get isLoading => _isLoading;

  CachedRequest._internal(this.url, this.transformFunction) {
    _log.info('New cached request: $url');
    WidgetsBinding.instance.addObserver(this);
    _init();
  }

  factory CachedRequest.fromUrl(String url, {TransformFunction? transformFunction}) {
    if (!_cache.containsKey(url)) {
      _cache[url] = CachedRequest._internal(url, transformFunction);
    }
    return _cache[url]!;
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      _log.info('App Resumed from background. Scheduling refresh for $url');
      /// ✅ 优化：使用防抖刷新而不是立即刷新
      _debouncedRefresh();
    }
  }

  _init() {
    _cacheLoad();
    _remoteLoad();

    _streamController.onListen = () {
      _log.info('Stream listener added for $url. Current data available? ${_transformed != null}');
      if (_transformed != null) {
        Future.microtask(() => _streamController.add(_transformed));
      }
    };
  }

  /// ✅ 优化：防抖刷新
  void _debouncedRefresh() {
    _refreshDebouncer?.cancel();
    _refreshDebouncer = Timer(_refreshDebounceDelay, () {
      if (!_isLoading) {
        refresh();
      }
    });
  }

  Future<void> refresh() async {
    /// ✅ 优化：防止重复请求
    if (_isLoading) {
      _log.info('Refresh already in progress for $url, skipping');
      return;
    }
    
    _retryCount = 0;
    await _remoteLoad();
  }

  Future<void> reload() async {
    await _cacheLoad();
  }

  /// ✅ 优化：带重试机制的远程加载
  _remoteLoad() async {
    if (_isLoading) return;
    
    _isLoading = true;
    
    try {
      _log.info('Starting remote load for $url (attempt ${_retryCount + 1})');
      
      /// ✅ 优化：添加超时控制
      final response = await http.get(Uri.parse(url)).timeout(
        const Duration(seconds: 30),
        onTimeout: () => throw TimeoutException('Request timeout for $url', const Duration(seconds: 30)),
      );
      
      if (response.statusCode != 200) {
        _hasRecentSuccessfulFetch = false;
        throw Exception('Invalid status code: ${response.statusCode} when fetching: $url');
      }

      _hasRecentSuccessfulFetch = true;
      _retryCount = 0; // 重置重试计数
      _log.info('${response.statusCode}, $url, Network Success: true');

      final data = jsonDecode(response.body);
      await _emit(data);
      await saveString(cachePath, response.body);
      
    } catch (error) {
      _hasRecentSuccessfulFetch = false;
      _log.severe('Remote load failed for $url (attempt ${_retryCount + 1}): $error');
      
      /// ✅ 优化：智能重试机制
      if (_retryCount < _maxRetries && _shouldRetry(error)) {
        _retryCount++;
        _log.info('Scheduling retry ${_retryCount}/$_maxRetries for $url in ${_retryDelay.inSeconds}s');
        
        Timer(_retryDelay, () {
          if (!_isLoading) { // 确保没有其他请求在进行
            _remoteLoad();
          }
        });
      } else {
        _streamController.addError(error);
      }
    } finally {
      _isLoading = false;
    }
  }

  /// ✅ 优化：判断是否应该重试
  bool _shouldRetry(dynamic error) {
    if (error is TimeoutException) return true;
    if (error is Exception) {
      final message = error.toString().toLowerCase();
      // 网络相关错误可以重试
      if (message.contains('timeout') || 
          message.contains('connection') || 
          message.contains('network') ||
          message.contains('socket')) {
        return true;
      }
    }
    return false;
  }

  /// ✅ 优化：异步数据发射
  Future<void> _emit(dynamic data) async {
    _log.info('Emitting data for $url');
    try {
      if (transformFunction != null) {
        data = await transformFunction?.call(data);
      }

      if (_streamController.hasListener) {
        _streamController.add(data);
      }
      _transformed = data;
    } catch (error) {
      _streamController.addError(error);
      _log.severe('Data transformation or emission failed: $error');
    }
  }

  /// ✅ 优化：缓存加载错误处理
  _cacheLoad() async {
    try {
      final file = await localFile(cachePath);
      if (await file.exists()) {
        _log.info('Loading from cache: $cachePath');
        final data = await loadJson(cachePath);
        await _emit(data);
        return;
      }

      /// ✅ 优化：内置资源加载
      if (url == ApiHelper.latestUri) {
        _log.info('Loading builtin latest asset data...');
        final data = await loadJSONFromAsset('assets/builtin/latest.json');
        await _emit(data);
      } else if (url == ApiHelper.collectionUri) {
        _log.info('Loading builtin collection asset data...');
        final data = await loadJSONFromAsset('assets/builtin/collection.json');
        await _emit(data);
      }
    } catch (error) {
      _log.warning('Cache load failed for $url: $error');
      // 缓存加载失败不应该阻止远程加载，只记录警告
    }
  }

  /// ✅ 优化：清理资源
  void dispose() {
    _refreshDebouncer?.cancel();
    WidgetsBinding.instance.removeObserver(this);
    _streamController.close();
  }

  String get hash => md5Hash(url);
  String get cachePath => 'api_cache/$hash';
  Stream get stream => _streamController.stream;

  @override
  String toString() => 'CachedRequest(url=$url, loading=$_isLoading, hasRecentFetch=$_hasRecentSuccessfulFetch)';
}