import 'package:flutter_test/flutter_test.dart';
import 'package:social_app/features/chat/data/ai/ai_decision_engine.dart';
import 'package:social_app/features/chat/data/models/ag_ui_event.dart';
import 'package:social_app/features/chat/data/tools/tool_registry.dart';
import 'package:social_app/features/chat/data/services/ag_ui_service.dart';

class TestableAgUiService extends AgUiService {
  TestableAgUiService({super.onEvent});

  @override
  Future<void> sendMessage(String content) async {
    await mockEventStream(content);
  }

  Future<void> mockEventStream(String content) async {
    final threadId = 'thread_${DateTime.now().millisecondsSinceEpoch}';
    final runId = 'run_${DateTime.now().millisecondsSinceEpoch}';
    final engine = AiDecisionEngine();

    onEvent(RunStartedEvent(threadId: threadId, runId: runId));

    final forceTrigger = engine.tryForceTrigger(content);
    if (forceTrigger != null) {
      await mockToolCallFlowWithArgs(forceTrigger.toolName, forceTrigger.args);
    } else if (engine.shouldTriggerToolCall(content)) {
      await mockToolCallFlow(content, engine);
    }

    final replies = generateReplies(content, engine);
    if (replies.isNotEmpty) {
      await mockTextMessageStream(replies);
    }

    onEvent(RunFinishedEvent(threadId: threadId, runId: runId));
  }

  Future<void> mockToolCallFlow(String content, AiDecisionEngine engine) async {
    final args = engine.getToolCallArgs(content);
    if (args == null) return;

    await mockToolCallFlowWithArgs('create_calendar_event', args);
  }

  Future<void> mockToolCallFlowWithArgs(
    String toolName,
    Map<String, dynamic> args,
  ) async {
    final toolCallId = 'tc_${DateTime.now().millisecondsSinceEpoch}';

    onEvent(ToolCallStartEvent(toolCallId: toolCallId, toolCallName: toolName));

    onEvent(ToolCallArgsEvent(toolCallId: toolCallId, delta: '{}'));

    onEvent(ToolCallEndEvent(toolCallId: toolCallId));

    final validation = ToolRegistry.validateArgs(toolName, args);
    if (!validation.ok) {
      onEvent(
        ToolCallErrorEvent(
          toolCallId: toolCallId,
          error: validation.error ?? 'Validation failed',
          code: 'VALIDATION_ERROR',
        ),
      );
      return;
    }

    try {
      ToolRegistry.initialize();
      final result = await ToolRegistry.execute(toolName, args);
      final messageId = 'msg_${DateTime.now().millisecondsSinceEpoch}';

      onEvent(
        ToolCallResultEvent(
          messageId: messageId,
          toolCallId: toolCallId,
          result: result,
        ),
      );
    } catch (e) {
      onEvent(
        ToolCallErrorEvent(
          toolCallId: toolCallId,
          error: e.toString(),
          code: 'EXECUTION_ERROR',
        ),
      );
    }
  }

  List<String> generateReplies(String content, AiDecisionEngine engine) {
    final intent = engine.matchIntent(content);

    switch (intent) {
      case Intent.createEvent:
        return ['好的，我已经为您创建了日程安排。'];
      case Intent.searchEvent:
        return ['您今天有以下日程：\n- 10:00 团队会议\n- 14:00 产品评审'];
      case Intent.unknown:
        return ['我理解了您的问题，让我来帮您处理。'];
    }
  }

  Future<void> mockTextMessageStream(List<String> replies) async {
    for (final reply in replies) {
      final messageId = 'msg_${DateTime.now().millisecondsSinceEpoch}';

      onEvent(TextMessageStartEvent(messageId: messageId, role: 'assistant'));

      onEvent(TextMessageContentEvent(messageId: messageId, delta: reply));

      onEvent(TextMessageEndEvent(messageId: messageId));
    }
  }
}

void main() {
  late TestableAgUiService service;
  late List<AgUiEvent> capturedEvents;

  setUp(() {
    capturedEvents = [];
    ToolRegistry.initialize();
    service = TestableAgUiService(
      onEvent: (event) {
        capturedEvents.add(event);
      },
    );
  });

  group('AgUiService', () {
    test('sendMessage first emits RunStartedEvent', () async {
      await service.sendMessage('你好');

      expect(capturedEvents.first, isA<RunStartedEvent>());
    });

    test('sendMessage last emits RunFinishedEvent', () async {
      await service.sendMessage('你好');

      expect(capturedEvents.last, isA<RunFinishedEvent>());
    });

    test('sendMessage emits events in correct order', () async {
      await service.sendMessage('你好');

      expect(capturedEvents.first, isA<RunStartedEvent>());
      expect(capturedEvents.last, isA<RunFinishedEvent>());

      final types = capturedEvents.map((e) => e.type).toList();
      expect(types.first, AgUiEventType.runStarted);
      expect(types.last, AgUiEventType.runFinished);
    });

    test('creating schedule text triggers tool call events', () async {
      await service.sendMessage('提醒我明天10点开会');

      final toolCallStarts = capturedEvents
          .whereType<ToolCallStartEvent>()
          .toList();
      final toolCallEnds = capturedEvents
          .whereType<ToolCallEndEvent>()
          .toList();
      final toolCallResults = capturedEvents
          .whereType<ToolCallResultEvent>()
          .toList();

      expect(toolCallStarts.isNotEmpty, true);
      expect(toolCallEnds.isNotEmpty, true);
      expect(toolCallResults.isNotEmpty, true);
      expect(toolCallStarts.first.toolCallName, 'create_calendar_event');
    });

    test('force trigger with #tool syntax', () async {
      await service.sendMessage(
        '#tool:create_calendar_event {"title": "Test", "startAt": "2026-03-01T10:00:00Z"}',
      );

      final toolCallStarts = capturedEvents
          .whereType<ToolCallStartEvent>()
          .toList();

      expect(toolCallStarts.isNotEmpty, true);
      expect(toolCallStarts.first.toolCallName, 'create_calendar_event');
    });

    test('text message events are emitted for unknown intent', () async {
      await service.sendMessage('你好');

      final textStarts = capturedEvents
          .whereType<TextMessageStartEvent>()
          .toList();
      final textContents = capturedEvents
          .whereType<TextMessageContentEvent>()
          .toList();
      final textEnds = capturedEvents.whereType<TextMessageEndEvent>().toList();

      expect(textStarts.isNotEmpty, true);
      expect(textContents.isNotEmpty, true);
      expect(textEnds.isNotEmpty, true);
    });

    test('search intent does not trigger tool calls', () async {
      await service.sendMessage('今天有什么日程');

      final toolCallStarts = capturedEvents
          .whereType<ToolCallStartEvent>()
          .toList();

      expect(toolCallStarts.isEmpty, true);
    });

    test('tool call with invalid args emits error', () async {
      await service.sendMessage('#tool:create_calendar_event {}');

      final toolCallErrors = capturedEvents
          .whereType<ToolCallErrorEvent>()
          .toList();

      expect(toolCallErrors.isNotEmpty, true);
      expect(toolCallErrors.first.error, contains('Missing required fields'));
    });
  });
}
