import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:tasq/models/task.dart';
import 'package:tasq/models/profile.dart';
import 'package:tasq/screens/tasks/task_detail_screen.dart';
import 'package:tasq/providers/tasks_provider.dart';
import 'package:tasq/providers/profile_provider.dart';
import 'package:tasq/providers/notifications_provider.dart';
import 'package:tasq/providers/tickets_provider.dart';
import 'package:tasq/utils/app_time.dart';

// Fake controller to capture updates
class FakeTasksController extends TasksController {
  FakeTasksController() : super(null);

  String? lastStatus;
  Map<String, dynamic>? lastUpdates;

  @override
  Future<void> createTask({
    required String title,
    required String description,
    String? officeId,
    String? ticketId,
    String? requestType,
    String? requestTypeOther,
    String? requestCategory,
  }) async {}

  @override
  Future<void> updateTask({
    required String taskId,
    String? requestType,
    String? requestTypeOther,
    String? requestCategory,
    String? status,
    String? requestedBy,
    String? notedBy,
    String? receivedBy,
    String? actionTaken,
  }) async {
    final m = <String, dynamic>{};
    if (requestType != null) {
      m['requestType'] = requestType;
    }
    if (requestTypeOther != null) {
      m['requestTypeOther'] = requestTypeOther;
    }
    if (requestCategory != null) {
      m['requestCategory'] = requestCategory;
    }
    if (requestedBy != null) {
      m['requestedBy'] = requestedBy;
    }
    if (notedBy != null) {
      m['notedBy'] = notedBy;
    }
    if (receivedBy != null) {
      m['receivedBy'] = receivedBy;
    }
    if (actionTaken != null) {
      m['actionTaken'] = actionTaken;
    }
    if (status != null) {
      m['status'] = status;
    }
    lastUpdates = m;
  }

  @override
  Future<void> updateTaskStatus({
    required String taskId,
    required String status,
  }) async {
    lastStatus = status;
  }
}

// lightweight notifications controller stub used in widget tests
class _FakeNotificationsController implements NotificationsController {
  @override
  Future<void> createMentionNotifications({
    required List<String> userIds,
    required String actorId,
    required int messageId,
    String? ticketId,
    String? taskId,
  }) async {}

  @override
  Future<void> markRead(String id) async {}

  @override
  Future<void> markReadForTicket(String ticketId) async {}

  @override
  Future<void> markReadForTask(String taskId) async {}
}

void main() {
  testWidgets('details badges show when metadata present', (tester) async {
    AppTime.initialize();

    // initial task without metadata
    final emptyTask = Task(
      id: 'tsk-1',
      ticketId: null,
      taskNumber: '2026-02-00002',
      title: 'No metadata',
      description: '',
      officeId: 'office-1',
      status: 'queued',
      priority: 1,
      queueOrder: null,
      createdAt: DateTime.now(),
      creatorId: 'u1',
      startedAt: null,
      completedAt: null,
      requestType: null,
      requestTypeOther: null,
      requestCategory: null,
    );

    await tester.pumpWidget(
      ProviderScope(
        overrides: [
          tasksProvider.overrideWith((ref) => Stream.value([emptyTask])),
          taskAssignmentsProvider.overrideWith((ref) => const Stream.empty()),
          currentProfileProvider.overrideWith(
            (ref) => Stream.value(
              Profile(id: 'u1', role: 'admin', fullName: 'Admin'),
            ),
          ),
          notificationsControllerProvider.overrideWithValue(
            _FakeNotificationsController(),
          ),
          notificationsProvider.overrideWith((ref) => const Stream.empty()),
          ticketsProvider.overrideWith((ref) => const Stream.empty()),
          officesProvider.overrideWith((ref) => const Stream.empty()),
          profilesProvider.overrideWith(
            (ref) => Stream.value(const <Profile>[]),
          ),
          taskMessagesProvider.overrideWith((ref, id) => const Stream.empty()),
        ],
        child: MaterialApp(home: TaskDetailScreen(taskId: 'tsk-1')),
      ),
    );
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    // metadata absent; editor controls may still show 'Type'/'Category' labels but
    // there should be no actual values present.
    expect(find.text('Repair'), findsNothing);
    expect(find.text('Hardware'), findsNothing);
  });

  testWidgets('badges show when metadata provided', (tester) async {
    AppTime.initialize();
    final task = Task(
      id: 'tsk-1',
      ticketId: null,
      taskNumber: '2026-02-00002',
      title: 'Has metadata',
      description: '',
      officeId: 'office-1',
      status: 'queued',
      priority: 1,
      queueOrder: null,
      createdAt: DateTime.now(),
      creatorId: 'u1',
      startedAt: null,
      completedAt: null,
      requestType: 'Repair',
      requestTypeOther: null,
      requestCategory: 'Hardware',
    );

    await tester.pumpWidget(
      ProviderScope(
        overrides: [
          tasksProvider.overrideWith((ref) => Stream.value([task])),
          taskAssignmentsProvider.overrideWith((ref) => const Stream.empty()),
          currentProfileProvider.overrideWith(
            (ref) => Stream.value(
              Profile(id: 'u1', role: 'admin', fullName: 'Admin'),
            ),
          ),
          notificationsControllerProvider.overrideWithValue(
            _FakeNotificationsController(),
          ),
          notificationsProvider.overrideWith((ref) => const Stream.empty()),
          ticketsProvider.overrideWith((ref) => const Stream.empty()),
          officesProvider.overrideWith((ref) => const Stream.empty()),
          profilesProvider.overrideWith(
            (ref) => Stream.value(const <Profile>[]),
          ),
          taskMessagesProvider.overrideWith((ref, id) => const Stream.empty()),
        ],
        child: MaterialApp(home: TaskDetailScreen(taskId: 'tsk-1')),
      ),
    );
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));
    // the selected values should be visible
    expect(find.text('Repair'), findsOneWidget);
    expect(find.text('Hardware'), findsOneWidget);
  });
}
