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

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

/// Flutter → H5 桥接层。
///
/// 把 [window.avatar] 暴露的 JS API 包装成 Dart 方法。
/// 内部只通过 [evaluateJavascript] 调用，未来切到 Cubism Native 时
/// 实现这一层的另一个版本即可，UI 完全无需改动。
class AvatarBridge {
  final InAppWebViewController _ctrl;

  AvatarBridge(this._ctrl);

  /// 等待 H5 端的 window.avatar 注册完成且模型加载到 expression/motion 可用
  Future<void> waitReady({Duration timeout = const Duration(seconds: 15)}) async {
    final deadline = DateTime.now().add(timeout);
    while (DateTime.now().isBefore(deadline)) {
      final result = await _ctrl.evaluateJavascript(source: '''
        (function() {
          if (!window.avatar) return false;
          const exps = window.avatar.listExpressions();
          const mots = window.avatar.listMotions();
          return exps.length > 0 || Object.keys(mots).length > 0;
        })()
      ''');
      if (result == true) return;
      await Future.delayed(const Duration(milliseconds: 200));
    }
    if (kDebugMode) {
      debugPrint('[AvatarBridge] waitReady timed out');
    }
  }

  Future<void> setState(String state) => _eval('avatar.setState("$state")');

  Future<void> setExpression(String name) =>
      _eval('avatar.setExpression("$name")');

  Future<void> playMotion(String group, int index) =>
      _eval('avatar.playMotion("$group", $index)');

  Future<void> setMouthOpen(double value) =>
      _eval('avatar.setMouthOpen($value)');

  Future<void> playAction(String name) =>
      _eval('avatar.playAction("$name")');

  Future<void> startDance() => _eval('avatar.startDance()');

  Future<void> stopDance() => _eval('avatar.stopDance()');

  Future<void> playMockConversation() => _eval('avatar.playMockConversation()');

  /// 拉一次资产清单（表情名、动作分组、语义动作列表）
  Future<AvatarManifest> fetchManifest() async {
    final raw = await _ctrl.evaluateJavascript(source: '''
      JSON.stringify({
        expressions: avatar.listExpressions(),
        motions: avatar.listMotions(),
        actions: avatar.listActions(),
      })
    ''');
    if (raw is! String) {
      return const AvatarManifest(expressions: [], motions: {}, actions: []);
    }
    final json = jsonDecode(raw) as Map<String, dynamic>;
    final expressions =
        (json['expressions'] as List).map((e) => e as String).toList();
    final motions = (json['motions'] as Map<String, dynamic>).map(
      (k, v) => MapEntry(k, v as int),
    );
    final actions =
        (json['actions'] as List).map((e) => e as String).toList();
    return AvatarManifest(
      expressions: expressions,
      motions: motions,
      actions: actions,
    );
  }

  Future<dynamic> _eval(String source) => _ctrl.evaluateJavascript(source: source);
}

/// 当前角色资产清单（表情名 + motion 分组 + 语义动作）
class AvatarManifest {
  final List<String> expressions;
  final Map<String, int> motions;
  final List<String> actions;
  const AvatarManifest({
    required this.expressions,
    required this.motions,
    required this.actions,
  });
}
