import 'package:flutter_test/flutter_test.dart';
import 'package:smplayer/core/contracts/script_widget.dart';
import 'package:smplayer/core/domain/ports/script_widget_remote_gateway.dart';
import 'package:smplayer/core/domain/ports/script_widget_repository.dart';
import 'package:smplayer/core/domain/ports/script_widget_runtime.dart';
import 'package:smplayer/core/domain/usecases/script_widget/script_widget_service.dart';
import 'package:smplayer/core/infra/danmaku_api/script_widget_danmaku_gateway.dart';

class _SingleWidgetRepository implements ScriptWidgetRepository {
  _SingleWidgetRepository(this.widget);

  final InstalledScriptWidget widget;

  @override
  Future<InstalledScriptWidget?> findWidget(String widgetId) async {
    return widget.manifest.id == widgetId ? widget : null;
  }

  @override
  Future<List<InstalledScriptWidget>> listWidgets() async {
    return <InstalledScriptWidget>[widget];
  }

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}

class _DanmakuScriptRuntime implements ScriptWidgetRuntime {
  String? lastFunctionName;
  Map<String, Object?>? lastParams;
  bool loaded = false;

  @override
  Future<void> dispose() async {}

  @override
  Future<Object?> invokeModuleFunction(
    String widgetId,
    String functionName,
    Map<String, Object?> params,
  ) async {
    lastFunctionName = functionName;
    lastParams = Map<String, Object?>.from(params);
    return switch (functionName) {
      'searchDanmu' => <String, Object?>{
        'animes': <Object?>[
          <String, Object?>{'animeId': 42, 'animeTitle': '示例剧集'},
        ],
      },
      'getDetail' => <String, Object?>{
        'episodes': <Object?>[
          <String, Object?>{
            'episodeId': 101,
            'episodeTitle': '第 1 集',
            'episodeNumber': '1',
          },
          <String, Object?>{
            'episodeId': 102,
            'episodeTitle': '第 2 集',
            'episodeNumber': '2',
          },
        ],
      },
      'getComments' => <String, Object?>{
        'comments': <Object?>[
          <String, Object?>{'cid': 9, 'p': '1.5,1,16711680', 'm': '测试弹幕'},
        ],
      },
      _ => null,
    };
  }

  @override
  Future<ScriptWidgetManifest> inspectWidget(String scriptSource) async {
    return const ScriptWidgetManifest(id: 'danmaku-test', title: 'Danmaku');
  }

  @override
  bool isWidgetLoaded(String widgetId) => loaded && widgetId == 'danmaku-test';

  @override
  Future<ScriptWidgetManifest> loadWidget(String scriptSource) async {
    loaded = true;
    return const ScriptWidgetManifest(id: 'danmaku-test', title: 'Danmaku');
  }

  @override
  Future<void> unloadWidget(String widgetId) async {
    if (widgetId == 'danmaku-test') loaded = false;
  }
}

class _UnusedRemoteGateway implements ScriptWidgetRemoteGateway {
  @override
  Future<String> fetchText(String url) {
    throw UnsupportedError('This test does not perform remote requests.');
  }
}

void main() {
  late _DanmakuScriptRuntime runtime;
  late ScriptWidgetDanmakuGateway gateway;

  setUp(() {
    runtime = _DanmakuScriptRuntime();
    final timestamp = DateTime.utc(2026, 7, 12);
    final service = ScriptWidgetService(
      repository: _SingleWidgetRepository(
        InstalledScriptWidget(
          manifest: const ScriptWidgetManifest(
            id: 'danmaku-test',
            title: 'Danmaku',
          ),
          scriptSource: 'widget source',
          installedAt: timestamp,
          updatedAt: timestamp,
        ),
      ),
      remoteGateway: _UnusedRemoteGateway(),
      runtime: runtime,
    );
    gateway = ScriptWidgetDanmakuGateway(loadService: () async => service);
  });

  test('文件名中的季集信息映射到 searchDanmu 并筛选目标分集', () async {
    final matches = await gateway.match(
      'jsw://danmaku-test',
      '示例剧集 S02E02',
      1800,
    );

    expect(matches, hasLength(1));
    expect(matches.single.episodeId, 102);
    expect(matches.single.animeId, 42);
    expect(matches.single.animeTitle, '示例剧集');
  });

  test('getComments 响应映射为标准弹幕评论', () async {
    final comments = await gateway.fetchComments(
      'jsw://danmaku-test',
      102,
      chConvert: 1,
    );

    expect(runtime.lastFunctionName, 'getComments');
    expect(runtime.lastParams, <String, Object?>{
      'commentId': 102,
      'chConvert': 1,
    });
    expect(comments.single.cid, 9);
    expect(comments.single.time, 1.5);
    expect(comments.single.text, '测试弹幕');
    expect(comments.single.color.toARGB32(), 0xFFFF0000);
  });
}
