// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../models/profile.dart';
import '../../models/task.dart';
import '../../models/task_assignment.dart';
import '../../models/task_activity_log.dart';
import '../../models/ticket.dart';
import '../../models/ticket_message.dart';
import '../../models/office.dart';
import '../../providers/notifications_provider.dart';
import 'dart:async';
import 'dart:convert';
import 'package:file_picker/file_picker.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill;
import '../../providers/services_provider.dart';
import 'task_pdf.dart';
import '../../providers/supabase_provider.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import '../../providers/profile_provider.dart';
import '../../providers/tasks_provider.dart';
import '../../providers/tickets_provider.dart';
import '../../providers/typing_provider.dart';
import '../../providers/realtime_controller.dart';
import 'package:skeletonizer/skeletonizer.dart';
import '../../utils/app_time.dart';
import '../../utils/snackbar.dart';
import '../../utils/subject_suggestions.dart';
import '../../widgets/app_breakpoints.dart';
import '../../widgets/mono_text.dart';
import '../../widgets/responsive_body.dart';
import '../../widgets/status_pill.dart';
import '../../theme/app_surfaces.dart';
import '../../widgets/task_assignment_section.dart';
import '../../widgets/typing_dots.dart';
import '../../widgets/gemini_button.dart';
import '../../widgets/gemini_animated_text_field.dart';
import '../../services/ai_service.dart';

// Simple image embed builder to support data-URI and network images
class _ImageEmbedBuilder extends quill.EmbedBuilder {
  const _ImageEmbedBuilder();

  @override
  String get key => quill.BlockEmbed.imageType;

  @override
  Widget build(BuildContext context, quill.EmbedContext embedContext) {
    final data = embedContext.node.value.data as String;
    if (data.startsWith('data:image/')) {
      try {
        final base64Str = data.split(',').last;
        final bytes = base64Decode(base64Str);
        return ConstrainedBox(
          constraints: const BoxConstraints(maxHeight: 240),
          child: Image.memory(bytes, fit: BoxFit.contain),
        );
      } catch (_) {
        return const SizedBox.shrink();
      }
    }
    // Fallback to network image
    return ConstrainedBox(
      constraints: const BoxConstraints(maxHeight: 240),
      child: Image.network(data, fit: BoxFit.contain),
    );
  }
}

// Local request metadata options (kept consistent with other screens)
const List<String> requestTypeOptions = [
  'Install',
  'Repair',
  'Upgrade',
  'Replace',
  'Other',
];

const List<String> requestCategoryOptions = ['Software', 'Hardware', 'Network'];

class TaskDetailScreen extends ConsumerStatefulWidget {
  const TaskDetailScreen({super.key, required this.taskId});

  final String taskId;

  @override
  ConsumerState<TaskDetailScreen> createState() => _TaskDetailScreenState();
}

class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
    with SingleTickerProviderStateMixin {
  final _messageController = TextEditingController();
  // Controllers for editable signatories
  final _requestedController = TextEditingController();
  final _notedController = TextEditingController();
  final _receivedController = TextEditingController();
  // Rich text editor for Action taken
  quill.QuillController? _actionController;
  Timer? _actionDebounce;

  /// Tracks the last plain-text snapshot so the addListener callback can
  /// distinguish real edits from cursor / selection / focus notifications.
  String _actionLastPlain = '';
  late final FocusNode _actionFocusNode;
  late final ScrollController _actionScrollController;
  Timer? _requestedDebounce;
  Timer? _notedDebounce;
  Timer? _receivedDebounce;
  // Seeding/state tracking for signatory fields
  String? _seededTaskId;
  bool _requestedSaving = false;
  bool _requestedSaved = false;
  bool _notedSaving = false;
  bool _notedSaved = false;
  bool _receivedSaving = false;
  bool _receivedSaved = false;
  bool _typeSaving = false;
  bool _typeSaved = false;
  bool _categorySaving = false;
  bool _categorySaved = false;
  bool _actionSaving = false;
  bool _actionSaved = false;
  bool _actionProcessing = false;
  late final AnimationController _saveAnimController;
  late final Animation<double> _savePulse;
  static const List<String> _statusOptions = [
    'queued',
    'in_progress',
    'completed',
    'cancelled',
  ];
  String? _mentionQuery;
  int? _mentionStart;
  List<Profile> _mentionResults = [];
  // Attachments state
  List<String>? _attachments;
  bool _loadingAttachments = false;

  @override
  void initState() {
    super.initState();
    Future.microtask(
      () => ref
          .read(notificationsControllerProvider)
          .markReadForTask(widget.taskId),
    );
    _saveAnimController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 700),
    );
    _savePulse = Tween(begin: 1.0, end: 0.78).animate(
      CurvedAnimation(parent: _saveAnimController, curve: Curves.easeInOut),
    );
    // create an empty action controller by default; will seed per-task later
    _actionController = quill.QuillController.basic();
    _actionFocusNode = FocusNode();
    _actionScrollController = ScrollController();
    // Debugging: to enable a scroll jump detector, add a listener here.
    // Keep it disabled in production to avoid analyzer dead_code warnings.
  }

  @override
  void dispose() {
    _messageController.dispose();
    _requestedController.dispose();
    _notedController.dispose();
    _receivedController.dispose();
    _requestedDebounce?.cancel();
    _notedDebounce?.cancel();
    _receivedDebounce?.cancel();
    _actionDebounce?.cancel();
    _actionController?.dispose();
    _actionFocusNode.dispose();
    _actionScrollController.dispose();
    _saveAnimController.dispose();
    super.dispose();
  }

  bool get _anySaving =>
      _requestedSaving ||
      _notedSaving ||
      _receivedSaving ||
      _typeSaving ||
      _categorySaving ||
      _actionSaving;

  void _updateSaveAnim() {
    if (_anySaving) {
      if (!_saveAnimController.isAnimating) {
        _saveAnimController.repeat(reverse: true);
      }
    } else {
      if (_saveAnimController.isAnimating) {
        _saveAnimController.stop();
        _saveAnimController.reset();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    // Use per-item providers to avoid rebuilding when unrelated tasks/tickets
    // change.  Only the specific task/ticket for this screen triggers rebuilds.
    final task = ref.watch(taskByIdProvider(widget.taskId));
    final officesAsync = ref.watch(officesProvider);
    final profileAsync = ref.watch(currentProfileProvider);
    final assignmentsAsync = ref.watch(taskAssignmentsProvider);
    final taskMessagesAsync = ref.watch(taskMessagesProvider(widget.taskId));
    final profilesAsync = ref.watch(profilesProvider);

    // Loading state: use .select() so we only rebuild when the loading flag
    // itself changes, not when list data changes.
    final isTasksLoading = ref.watch(
      tasksProvider.select((a) => !a.hasValue && a.isLoading),
    );
    final isTicketsLoading = ref.watch(
      ticketsProvider.select((a) => !a.hasValue && a.isLoading),
    );

    if (task == null) {
      return const ResponsiveBody(
        child: Center(child: Text('Task not found.')),
      );
    }
    final ticketId = task.ticketId;
    final typingChannelId = task.id;
    final ticket = ticketId == null
        ? null
        : ref.watch(ticketByIdProvider(ticketId));
    final officeById = {
      for (final office in officesAsync.valueOrNull ?? []) office.id: office,
    };
    final officeId = ticket?.officeId ?? task.officeId;
    final officeName = officeId == null
        ? 'Unassigned office'
        : (officeById[officeId]?.name ?? officeId);
    final description = ticket?.description ?? task.description;

    final canAssign = profileAsync.maybeWhen(
      data: (profile) => profile != null && _canAssignStaff(profile.role),
      orElse: () => false,
    );
    final showAssign = canAssign && task.status != 'completed';
    final assignments = assignmentsAsync.valueOrNull ?? <TaskAssignment>[];
    final profileById = {
      for (final profile in profilesAsync.valueOrNull ?? <Profile>[])
        profile.id: profile,
    };
    final hasAssignedItStaff = assignments.any((assignment) {
      if (assignment.taskId != task.id) {
        return false;
      }
      return profileById[assignment.userId]?.role == 'it_staff';
    });
    final canUpdateStatus = _canUpdateStatus(
      profileAsync.valueOrNull,
      assignments,
      task.id,
    );
    final typingState = ref.watch(typingIndicatorProvider(typingChannelId));
    final canSendMessages = task.status != 'completed';

    final messagesAsync = _mergeMessages(
      taskMessagesAsync,
      ticketId == null ? null : ref.watch(ticketMessagesProvider(ticketId)),
    );

    WidgetsBinding.instance.addPostFrameCallback((_) => _updateSaveAnim());

    final realtime = ref.watch(realtimeControllerProvider);
    final isRetrieving =
        realtime.isChannelRecovering('tasks') ||
        realtime.isChannelRecovering('task_assignments') ||
        isTasksLoading ||
        isTicketsLoading ||
        (!officesAsync.hasValue && officesAsync.isLoading) ||
        (!profileAsync.hasValue && profileAsync.isLoading) ||
        (!assignmentsAsync.hasValue && assignmentsAsync.isLoading) ||
        (!taskMessagesAsync.hasValue && taskMessagesAsync.isLoading);

    return Skeletonizer(
      enabled: isRetrieving,
      child: ResponsiveBody(
        child: LayoutBuilder(
          builder: (context, constraints) {
            final isWide = constraints.maxWidth >= AppBreakpoints.desktop;

            // Seed controllers once per task to reflect persisted values
            if (_seededTaskId != task.id) {
              _seededTaskId = task.id;
              _requestedController.text = task.requestedBy ?? '';
              _notedController.text = task.notedBy ?? '';
              _receivedController.text = task.receivedBy ?? '';
              _requestedSaved = _requestedController.text.isNotEmpty;
              _notedSaved = _notedController.text.isNotEmpty;
              _receivedSaved = _receivedController.text.isNotEmpty;

              // Reset attachments for new task
              _attachments = null;
              _loadingAttachments = false;

              // Seed action taken plain text controller from persisted JSON or raw text
              try {
                _actionDebounce?.cancel();
                _actionController?.dispose();
                if (task.actionTaken != null && task.actionTaken!.isNotEmpty) {
                  try {
                    final docJson =
                        jsonDecode(task.actionTaken!) as List<dynamic>;
                    final doc = quill.Document.fromJson(docJson);
                    _actionController = quill.QuillController(
                      document: doc,
                      selection: const TextSelection.collapsed(offset: 0),
                    );
                  } catch (_) {
                    _actionController = quill.QuillController.basic();
                  }
                } else {
                  _actionController = quill.QuillController.basic();
                }
              } catch (_) {
                _actionController = quill.QuillController.basic();
              }

              // Snapshot current content so the listener can skip non-edit
              // notifications (cursor moves, selection changes, focus events).
              _actionLastPlain =
                  _actionController?.document.toPlainText().trim() ?? '';

              // Attach auto-save listener for action taken (debounced).
              // QuillController fires notifications on every cursor /
              // selection / formatting change — not just text edits.  We
              // compare plaintext to avoid endlessly resetting the timer.
              _actionController?.addListener(() {
                final currentPlain =
                    _actionController?.document.toPlainText().trim() ?? '';
                if (currentPlain == _actionLastPlain) return; // no text change
                _actionLastPlain = currentPlain;

                _actionDebounce?.cancel();
                _actionDebounce = Timer(
                  const Duration(milliseconds: 700),
                  () async {
                    if (!mounted) return;
                    final plain = currentPlain;
                    if (mounted) {
                      setState(() {
                        _actionSaving = true;
                        _actionSaved = false;
                      });
                    }
                    try {
                      final deltaJson = jsonEncode(
                        _actionController?.document.toDelta().toJson(),
                      );
                      await ref
                          .read(tasksControllerProvider)
                          .updateTask(taskId: task.id, actionTaken: deltaJson);
                      if (mounted) {
                        setState(() {
                          _actionSaved = plain.isNotEmpty;
                        });
                      }
                    } catch (e) {
                      debugPrint('[TasQ] action-taken auto-save error: $e');
                    } finally {
                      if (mounted) {
                        setState(() {
                          _actionSaving = false;
                        });
                      }
                      if (_actionSaved) {
                        Future.delayed(const Duration(seconds: 2), () {
                          if (mounted) {
                            setState(() => _actionSaved = false);
                          }
                        });
                      }
                    }
                  },
                );
              });
            }

            final detailsContent = Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Center(
                  child: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Text(
                        task.title.isNotEmpty
                            ? task.title
                            : 'Task ${task.taskNumber ?? task.id}',
                        textAlign: TextAlign.center,
                        style: Theme.of(context).textTheme.titleLarge?.copyWith(
                          fontWeight: FontWeight.w700,
                        ),
                      ),
                      const SizedBox(width: 8),
                      Builder(
                        builder: (ctx) {
                          final profile = profileAsync.maybeWhen(
                            data: (p) => p,
                            orElse: () => null,
                          );
                          final canEdit =
                              profile != null &&
                              (profile.role == 'admin' ||
                                  profile.role == 'dispatcher' ||
                                  profile.role == 'it_staff' ||
                                  profile.id == task.creatorId);
                          if (!canEdit) return const SizedBox.shrink();
                          return IconButton(
                            tooltip: 'Edit task',
                            onPressed: () =>
                                _showEditTaskDialog(ctx, ref, task),
                            icon: const Icon(Icons.edit),
                          );
                        },
                      ),
                    ],
                  ),
                ),
                const SizedBox(height: 6),
                Align(
                  alignment: Alignment.center,
                  child: Text(
                    _createdByLabel(profilesAsync, task, ticket),
                    textAlign: TextAlign.center,
                    style: Theme.of(context).textTheme.labelMedium,
                  ),
                ),
                const SizedBox(height: 12),
                Row(
                  children: [
                    Expanded(
                      child: Wrap(
                        spacing: 12,
                        runSpacing: 8,
                        crossAxisAlignment: WrapCrossAlignment.center,
                        children: [
                          _buildStatusChip(
                            context,
                            task,
                            canUpdateStatus,
                            hasAssignedItStaff,
                          ),
                          _MetaBadge(label: 'Office', value: officeName),
                          _MetaBadge(
                            label: 'Task #',
                            value: task.taskNumber ?? task.id,
                            isMono: true,
                          ),
                        ],
                      ),
                    ),
                    IconButton(
                      tooltip: 'Preview/print task',
                      onPressed: () async {
                        try {
                          final logsAsync = ref.read(
                            taskActivityLogsProvider(task.id),
                          );
                          final logs =
                              logsAsync.valueOrNull ?? <TaskActivityLog>[];
                          final assignmentList = assignments;
                          final profilesList =
                              profilesAsync.valueOrNull ?? <Profile>[];

                          // Read the services stream; if the office is linked to a service
                          // but the stream hasn't yielded yet, fetch once and await it
                          final servicesAsync = ref.read(servicesProvider);
                          final servicesById = <String, dynamic>{
                            for (final s in servicesAsync.valueOrNull ?? [])
                              s.id: s,
                          };

                          final officeServiceId = officeId == null
                              ? null
                              : officeById[officeId]?.serviceId;

                          if (officeServiceId != null &&
                              (servicesAsync.valueOrNull == null ||
                                  (servicesAsync.valueOrNull?.isEmpty ??
                                      true))) {
                            final servicesOnce = await ref.read(
                              servicesOnceProvider.future,
                            );
                            for (final s in servicesOnce) {
                              servicesById[s.id] = s;
                            }
                          }

                          final serviceName = officeServiceId == null
                              ? ''
                              : (servicesById[officeServiceId]?.name ?? '');

                          await showTaskPdfPreview(
                            context,
                            task,
                            ticket,
                            officeName,
                            serviceName,
                            logs,
                            assignmentList,
                            profilesList,
                          );
                        } catch (_) {}
                      },
                      icon: const Icon(Icons.print),
                    ),
                  ],
                ),
                if (description.isNotEmpty) ...[
                  const SizedBox(height: 12),
                  Text(description),
                ],

                // warning banner for completed tasks with missing metadata
                if (task.status == 'completed' &&
                    task.hasIncompleteDetails) ...[
                  const SizedBox(height: 12),
                  Row(
                    children: [
                      const Icon(
                        Icons.warning_amber_rounded,
                        color: Colors.orange,
                      ),
                      const SizedBox(width: 6),
                      Expanded(
                        child: Text(
                          'Task completed but some details are still empty.',
                          style: Theme.of(context).textTheme.bodyMedium
                              ?.copyWith(
                                color: Theme.of(
                                  context,
                                ).colorScheme.onSurfaceVariant,
                              ),
                        ),
                      ),
                    ],
                  ),
                ],
                const SizedBox(height: 16),
                // Collapsible tabbed details: Assignees / Type & Category / Signatories
                ExpansionTile(
                  title: const Text('Details'),
                  initiallyExpanded: isWide,
                  childrenPadding: const EdgeInsets.symmetric(horizontal: 0),
                  children: [
                    DefaultTabController(
                      length: 5,
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          TabBar(
                            labelColor: Theme.of(context).colorScheme.onSurface,
                            indicatorColor: Theme.of(
                              context,
                            ).colorScheme.primary,
                            tabs: isWide
                                ? const [
                                    Tab(text: 'Assignees'),
                                    Tab(text: 'Type & Category'),
                                    Tab(text: 'Signatories'),
                                    Tab(text: 'Action taken'),
                                    Tab(text: 'Attachments'),
                                  ]
                                : const [
                                    Tab(icon: Icon(Icons.person)),
                                    Tab(icon: Icon(Icons.category)),
                                    Tab(icon: Icon(Icons.check_circle)),
                                    Tab(icon: Icon(Icons.description)),
                                    Tab(icon: Icon(Icons.attach_file)),
                                  ],
                          ),
                          const SizedBox(height: 8),
                          SizedBox(
                            height: isWide ? 360 : 300,
                            child: TabBarView(
                              children: [
                                // Assignees (Tab 1)
                                SingleChildScrollView(
                                  child: Padding(
                                    padding: const EdgeInsets.only(top: 8.0),
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: [
                                        TaskAssignmentSection(
                                          taskId: task.id,
                                          canAssign: showAssign,
                                        ),
                                        const SizedBox(height: 12),
                                        const SizedBox.shrink(),
                                      ],
                                    ),
                                  ),
                                ),

                                // Type & Category
                                SingleChildScrollView(
                                  child: Padding(
                                    padding: const EdgeInsets.only(top: 8.0),
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: [
                                        if (!canUpdateStatus) ...[
                                          _MetaBadge(
                                            label: 'Type',
                                            value: task.requestType ?? 'None',
                                          ),
                                          const SizedBox(height: 8),
                                          _MetaBadge(
                                            label: 'Category',
                                            value:
                                                task.requestCategory ?? 'None',
                                          ),
                                        ] else ...[
                                          const Text('Type'),
                                          const SizedBox(height: 6),
                                          DropdownButtonFormField<String?>(
                                            initialValue: task.requestType,
                                            decoration: InputDecoration(
                                              suffixIcon: _typeSaving
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: ScaleTransition(
                                                        scale: _savePulse,
                                                        child: const Icon(
                                                          Icons.save,
                                                          size: 14,
                                                        ),
                                                      ),
                                                    )
                                                  : _typeSaved
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: Stack(
                                                        alignment:
                                                            Alignment.center,
                                                        children: const [
                                                          Icon(
                                                            Icons.save,
                                                            size: 14,
                                                            color: Colors.green,
                                                          ),
                                                          Positioned(
                                                            right: -2,
                                                            bottom: -2,
                                                            child: Icon(
                                                              Icons.check,
                                                              size: 10,
                                                              color:
                                                                  Colors.white,
                                                            ),
                                                          ),
                                                        ],
                                                      ),
                                                    )
                                                  : null,
                                            ),
                                            items: [
                                              const DropdownMenuItem(
                                                value: null,
                                                child: Text('None'),
                                              ),
                                              for (final t
                                                  in requestTypeOptions)
                                                DropdownMenuItem(
                                                  value: t,
                                                  child: Text(t),
                                                ),
                                            ],
                                            onChanged: (v) async {
                                              setState(() {
                                                _typeSaving = true;
                                                _typeSaved = false;
                                              });
                                              try {
                                                await ref
                                                    .read(
                                                      tasksControllerProvider,
                                                    )
                                                    .updateTask(
                                                      taskId: task.id,
                                                      requestType: v,
                                                    );
                                                setState(
                                                  () => _typeSaved =
                                                      v != null && v.isNotEmpty,
                                                );
                                              } catch (_) {
                                              } finally {
                                                setState(
                                                  () => _typeSaving = false,
                                                );
                                                if (_typeSaved) {
                                                  Future.delayed(
                                                    const Duration(seconds: 2),
                                                    () {
                                                      if (mounted) {
                                                        setState(
                                                          () => _typeSaved =
                                                              false,
                                                        );
                                                      }
                                                    },
                                                  );
                                                }
                                              }
                                            },
                                          ),
                                          if (task.requestType == 'Other') ...[
                                            const SizedBox(height: 8),
                                            TextFormField(
                                              initialValue:
                                                  task.requestTypeOther,
                                              decoration: InputDecoration(
                                                hintText: 'Details',
                                                suffixIcon: _typeSaving
                                                    ? SizedBox(
                                                        width: 16,
                                                        height: 16,
                                                        child: ScaleTransition(
                                                          scale: _savePulse,
                                                          child: const Icon(
                                                            Icons.save,
                                                            size: 14,
                                                          ),
                                                        ),
                                                      )
                                                    : _typeSaved
                                                    ? SizedBox(
                                                        width: 16,
                                                        height: 16,
                                                        child: Stack(
                                                          alignment:
                                                              Alignment.center,
                                                          children: const [
                                                            Icon(
                                                              Icons.save,
                                                              size: 14,
                                                              color:
                                                                  Colors.green,
                                                            ),
                                                            Positioned(
                                                              right: -2,
                                                              bottom: -2,
                                                              child: Icon(
                                                                Icons.check,
                                                                size: 10,
                                                                color: Colors
                                                                    .white,
                                                              ),
                                                            ),
                                                          ],
                                                        ),
                                                      )
                                                    : null,
                                              ),
                                              onChanged: (text) async {
                                                setState(() {
                                                  _typeSaving = true;
                                                  _typeSaved = false;
                                                });
                                                try {
                                                  await ref
                                                      .read(
                                                        tasksControllerProvider,
                                                      )
                                                      .updateTask(
                                                        taskId: task.id,
                                                        requestTypeOther:
                                                            text.isEmpty
                                                            ? null
                                                            : text,
                                                      );
                                                  setState(
                                                    () => _typeSaved =
                                                        text.isNotEmpty,
                                                  );
                                                } catch (_) {
                                                } finally {
                                                  setState(
                                                    () => _typeSaving = false,
                                                  );
                                                  if (_typeSaved) {
                                                    Future.delayed(
                                                      const Duration(
                                                        seconds: 2,
                                                      ),
                                                      () {
                                                        if (mounted) {
                                                          setState(
                                                            () => _typeSaved =
                                                                false,
                                                          );
                                                        }
                                                      },
                                                    );
                                                  }
                                                }
                                              },
                                            ),
                                          ],
                                          const SizedBox(height: 8),
                                          const Text('Category'),
                                          const SizedBox(height: 6),
                                          DropdownButtonFormField<String?>(
                                            initialValue: task.requestCategory,
                                            decoration: InputDecoration(
                                              suffixIcon: _categorySaving
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: ScaleTransition(
                                                        scale: _savePulse,
                                                        child: const Icon(
                                                          Icons.save,
                                                          size: 14,
                                                        ),
                                                      ),
                                                    )
                                                  : _categorySaved
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: Stack(
                                                        alignment:
                                                            Alignment.center,
                                                        children: const [
                                                          Icon(
                                                            Icons.save,
                                                            size: 14,
                                                            color: Colors.green,
                                                          ),
                                                          Positioned(
                                                            right: -2,
                                                            bottom: -2,
                                                            child: Icon(
                                                              Icons.check,
                                                              size: 10,
                                                              color:
                                                                  Colors.white,
                                                            ),
                                                          ),
                                                        ],
                                                      ),
                                                    )
                                                  : null,
                                            ),
                                            items: [
                                              const DropdownMenuItem(
                                                value: null,
                                                child: Text('None'),
                                              ),
                                              for (final c
                                                  in requestCategoryOptions)
                                                DropdownMenuItem(
                                                  value: c,
                                                  child: Text(c),
                                                ),
                                            ],
                                            onChanged: (v) async {
                                              setState(() {
                                                _categorySaving = true;
                                                _categorySaved = false;
                                              });
                                              try {
                                                await ref
                                                    .read(
                                                      tasksControllerProvider,
                                                    )
                                                    .updateTask(
                                                      taskId: task.id,
                                                      requestCategory: v,
                                                    );
                                                setState(
                                                  () => _categorySaved =
                                                      v != null && v.isNotEmpty,
                                                );
                                              } catch (_) {
                                              } finally {
                                                setState(
                                                  () => _categorySaving = false,
                                                );
                                                if (_categorySaved) {
                                                  Future.delayed(
                                                    const Duration(seconds: 2),
                                                    () {
                                                      if (mounted) {
                                                        setState(
                                                          () => _categorySaved =
                                                              false,
                                                        );
                                                      }
                                                    },
                                                  );
                                                }
                                              }
                                            },
                                          ),
                                        ],
                                        const SizedBox(height: 12),
                                      ],
                                    ),
                                  ),
                                ),

                                // Signatories (editable)
                                SingleChildScrollView(
                                  child: Padding(
                                    padding: const EdgeInsets.only(top: 8.0),
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: [
                                        Text(
                                          'Requested by',
                                          style: Theme.of(
                                            context,
                                          ).textTheme.bodySmall,
                                        ),
                                        const SizedBox(height: 6),
                                        TypeAheadFormField<String>(
                                          textFieldConfiguration: TextFieldConfiguration(
                                            controller: _requestedController,
                                            decoration: InputDecoration(
                                              hintText: 'Requester name or id',
                                              suffixIcon: _requestedSaving
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: ScaleTransition(
                                                        scale: _savePulse,
                                                        child: const Icon(
                                                          Icons.save,
                                                          size: 14,
                                                        ),
                                                      ),
                                                    )
                                                  : _requestedSaved
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: Stack(
                                                        alignment:
                                                            Alignment.center,
                                                        children: const [
                                                          Icon(
                                                            Icons.save,
                                                            size: 14,
                                                            color: Colors.green,
                                                          ),
                                                          Positioned(
                                                            right: -2,
                                                            bottom: -2,
                                                            child: Icon(
                                                              Icons.check,
                                                              size: 10,
                                                              color:
                                                                  Colors.white,
                                                            ),
                                                          ),
                                                        ],
                                                      ),
                                                    )
                                                  : null,
                                            ),
                                            onChanged: (v) {
                                              _requestedDebounce?.cancel();
                                              _requestedDebounce = Timer(
                                                const Duration(
                                                  milliseconds: 700,
                                                ),
                                                () async {
                                                  final name = v.trim();
                                                  setState(() {
                                                    _requestedSaving = true;
                                                    _requestedSaved = false;
                                                  });
                                                  try {
                                                    await ref
                                                        .read(
                                                          tasksControllerProvider,
                                                        )
                                                        .updateTask(
                                                          taskId: task.id,
                                                          requestedBy:
                                                              name.isEmpty
                                                              ? null
                                                              : name,
                                                        );
                                                    if (name.isNotEmpty) {
                                                      try {
                                                        await ref
                                                            .read(
                                                              supabaseClientProvider,
                                                            )
                                                            .from('clients')
                                                            .upsert({
                                                              'name': name,
                                                            });
                                                      } catch (_) {}
                                                    }
                                                    setState(() {
                                                      _requestedSaved =
                                                          name.isNotEmpty;
                                                    });
                                                  } catch (_) {
                                                  } finally {
                                                    setState(() {
                                                      _requestedSaving = false;
                                                    });
                                                    if (_requestedSaved) {
                                                      Future.delayed(
                                                        const Duration(
                                                          seconds: 2,
                                                        ),
                                                        () {
                                                          if (mounted) {
                                                            setState(
                                                              () =>
                                                                  _requestedSaved =
                                                                      false,
                                                            );
                                                          }
                                                        },
                                                      );
                                                    }
                                                  }
                                                },
                                              );
                                            },
                                          ),
                                          suggestionsCallback: (pattern) async {
                                            final profiles =
                                                ref
                                                    .watch(profilesProvider)
                                                    .valueOrNull ??
                                                [];
                                            final fromProfiles = profiles
                                                .map(
                                                  (p) => p.fullName.isEmpty
                                                      ? p.id
                                                      : p.fullName,
                                                )
                                                .where(
                                                  (n) =>
                                                      n.toLowerCase().contains(
                                                        pattern.toLowerCase(),
                                                      ),
                                                )
                                                .toList();
                                            try {
                                              final clientRows = await ref
                                                  .read(supabaseClientProvider)
                                                  .from('clients')
                                                  .select('name')
                                                  .ilike('name', '%$pattern%');
                                              final clientNames =
                                                  (clientRows as List<dynamic>?)
                                                      ?.map(
                                                        (r) =>
                                                            r['name'] as String,
                                                      )
                                                      .whereType<String>()
                                                      .toList() ??
                                                  <String>[];
                                              final merged = {
                                                ...fromProfiles,
                                                ...clientNames,
                                              }.toList();
                                              return merged;
                                            } catch (_) {
                                              return fromProfiles;
                                            }
                                          },
                                          itemBuilder: (context, suggestion) =>
                                              ListTile(title: Text(suggestion)),
                                          onSuggestionSelected: (suggestion) async {
                                            _requestedDebounce?.cancel();
                                            _requestedController.text =
                                                suggestion;
                                            setState(() {
                                              _requestedSaving = true;
                                              _requestedSaved = false;
                                            });
                                            try {
                                              await ref
                                                  .read(tasksControllerProvider)
                                                  .updateTask(
                                                    taskId: task.id,
                                                    requestedBy:
                                                        suggestion.isEmpty
                                                        ? null
                                                        : suggestion,
                                                  );
                                              if (suggestion.isNotEmpty) {
                                                try {
                                                  await ref
                                                      .read(
                                                        supabaseClientProvider,
                                                      )
                                                      .from('clients')
                                                      .upsert({
                                                        'name': suggestion,
                                                      });
                                                } catch (_) {}
                                              }
                                              setState(
                                                () => _requestedSaved =
                                                    suggestion.isNotEmpty,
                                              );
                                            } catch (_) {
                                            } finally {
                                              setState(
                                                () => _requestedSaving = false,
                                              );
                                              if (_requestedSaved) {
                                                Future.delayed(
                                                  const Duration(seconds: 2),
                                                  () {
                                                    if (mounted) {
                                                      setState(
                                                        () => _requestedSaved =
                                                            false,
                                                      );
                                                    }
                                                  },
                                                );
                                              }
                                            }
                                          },
                                        ),

                                        const SizedBox(height: 12),
                                        Text(
                                          'Noted by (Supervisor/Senior)',
                                          style: Theme.of(
                                            context,
                                          ).textTheme.bodySmall,
                                        ),
                                        const SizedBox(height: 6),
                                        TypeAheadFormField<String>(
                                          textFieldConfiguration: TextFieldConfiguration(
                                            controller: _notedController,
                                            decoration: InputDecoration(
                                              hintText: 'Supervisor/Senior',
                                              suffixIcon: _notedSaving
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: ScaleTransition(
                                                        scale: _savePulse,
                                                        child: const Icon(
                                                          Icons.save,
                                                          size: 14,
                                                        ),
                                                      ),
                                                    )
                                                  : _notedSaved
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: Stack(
                                                        alignment:
                                                            Alignment.center,
                                                        children: const [
                                                          Icon(
                                                            Icons.save,
                                                            size: 14,
                                                            color: Colors.green,
                                                          ),
                                                          Positioned(
                                                            right: -2,
                                                            bottom: -2,
                                                            child: Icon(
                                                              Icons.check,
                                                              size: 10,
                                                              color:
                                                                  Colors.white,
                                                            ),
                                                          ),
                                                        ],
                                                      ),
                                                    )
                                                  : null,
                                            ),
                                            onChanged: (v) {
                                              _notedDebounce?.cancel();
                                              _notedDebounce = Timer(
                                                const Duration(
                                                  milliseconds: 700,
                                                ),
                                                () async {
                                                  final name = v.trim();
                                                  setState(() {
                                                    _notedSaving = true;
                                                    _notedSaved = false;
                                                  });
                                                  try {
                                                    await ref
                                                        .read(
                                                          tasksControllerProvider,
                                                        )
                                                        .updateTask(
                                                          taskId: task.id,
                                                          notedBy: name.isEmpty
                                                              ? null
                                                              : name,
                                                        );
                                                    if (name.isNotEmpty) {
                                                      try {
                                                        await ref
                                                            .read(
                                                              supabaseClientProvider,
                                                            )
                                                            .from('clients')
                                                            .upsert({
                                                              'name': name,
                                                            });
                                                      } catch (_) {}
                                                    }
                                                    setState(() {
                                                      _notedSaved =
                                                          name.isNotEmpty;
                                                    });
                                                  } catch (_) {
                                                    // ignore
                                                  } finally {
                                                    setState(() {
                                                      _notedSaving = false;
                                                    });
                                                    if (_notedSaved) {
                                                      Future.delayed(
                                                        const Duration(
                                                          seconds: 2,
                                                        ),
                                                        () {
                                                          if (mounted) {
                                                            setState(
                                                              () =>
                                                                  _notedSaved =
                                                                      false,
                                                            );
                                                          }
                                                        },
                                                      );
                                                    }
                                                  }
                                                },
                                              );
                                            },
                                          ),
                                          suggestionsCallback: (pattern) async {
                                            final profiles =
                                                ref
                                                    .watch(profilesProvider)
                                                    .valueOrNull ??
                                                [];
                                            final fromProfiles = profiles
                                                .map(
                                                  (p) => p.fullName.isEmpty
                                                      ? p.id
                                                      : p.fullName,
                                                )
                                                .where(
                                                  (n) =>
                                                      n.toLowerCase().contains(
                                                        pattern.toLowerCase(),
                                                      ),
                                                )
                                                .toList();
                                            try {
                                              final clientRows = await ref
                                                  .read(supabaseClientProvider)
                                                  .from('clients')
                                                  .select('name')
                                                  .ilike('name', '%$pattern%');
                                              final clientNames =
                                                  (clientRows as List<dynamic>?)
                                                      ?.map(
                                                        (r) =>
                                                            r['name'] as String,
                                                      )
                                                      .whereType<String>()
                                                      .toList() ??
                                                  <String>[];
                                              final merged = {
                                                ...fromProfiles,
                                                ...clientNames,
                                              }.toList();
                                              return merged;
                                            } catch (_) {
                                              return fromProfiles;
                                            }
                                          },
                                          itemBuilder: (context, suggestion) =>
                                              ListTile(title: Text(suggestion)),
                                          onSuggestionSelected:
                                              (suggestion) async {
                                                _notedDebounce?.cancel();
                                                _notedController.text =
                                                    suggestion;
                                                setState(() {
                                                  _notedSaving = true;
                                                  _notedSaved = false;
                                                });
                                                try {
                                                  await ref
                                                      .read(
                                                        tasksControllerProvider,
                                                      )
                                                      .updateTask(
                                                        taskId: task.id,
                                                        notedBy:
                                                            suggestion.isEmpty
                                                            ? null
                                                            : suggestion,
                                                      );
                                                  if (suggestion.isNotEmpty) {
                                                    try {
                                                      await ref
                                                          .read(
                                                            supabaseClientProvider,
                                                          )
                                                          .from('clients')
                                                          .upsert({
                                                            'name': suggestion,
                                                          });
                                                    } catch (_) {}
                                                  }
                                                  setState(
                                                    () => _notedSaved =
                                                        suggestion.isNotEmpty,
                                                  );
                                                } catch (_) {
                                                } finally {
                                                  setState(
                                                    () => _notedSaving = false,
                                                  );
                                                  if (_notedSaved) {
                                                    Future.delayed(
                                                      const Duration(
                                                        seconds: 2,
                                                      ),
                                                      () {
                                                        if (mounted) {
                                                          setState(
                                                            () => _notedSaved =
                                                                false,
                                                          );
                                                        }
                                                      },
                                                    );
                                                  }
                                                }
                                              },
                                        ),

                                        const SizedBox(height: 12),
                                        Text(
                                          'Received by',
                                          style: Theme.of(
                                            context,
                                          ).textTheme.bodySmall,
                                        ),
                                        const SizedBox(height: 6),
                                        TypeAheadFormField<String>(
                                          textFieldConfiguration: TextFieldConfiguration(
                                            controller: _receivedController,
                                            decoration: InputDecoration(
                                              hintText: 'Receiver name or id',
                                              suffixIcon: _receivedSaving
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: ScaleTransition(
                                                        scale: _savePulse,
                                                        child: const Icon(
                                                          Icons.save,
                                                          size: 14,
                                                        ),
                                                      ),
                                                    )
                                                  : _receivedSaved
                                                  ? SizedBox(
                                                      width: 16,
                                                      height: 16,
                                                      child: Stack(
                                                        alignment:
                                                            Alignment.center,
                                                        children: const [
                                                          Icon(
                                                            Icons.save,
                                                            size: 14,
                                                            color: Colors.green,
                                                          ),
                                                          Positioned(
                                                            right: -2,
                                                            bottom: -2,
                                                            child: Icon(
                                                              Icons.check,
                                                              size: 10,
                                                              color:
                                                                  Colors.white,
                                                            ),
                                                          ),
                                                        ],
                                                      ),
                                                    )
                                                  : null,
                                            ),
                                            onChanged: (v) {
                                              _receivedDebounce?.cancel();
                                              _receivedDebounce = Timer(
                                                const Duration(
                                                  milliseconds: 700,
                                                ),
                                                () async {
                                                  final name = v.trim();
                                                  setState(() {
                                                    _receivedSaving = true;
                                                    _receivedSaved = false;
                                                  });
                                                  try {
                                                    await ref
                                                        .read(
                                                          tasksControllerProvider,
                                                        )
                                                        .updateTask(
                                                          taskId: task.id,
                                                          receivedBy:
                                                              name.isEmpty
                                                              ? null
                                                              : name,
                                                        );
                                                    if (name.isNotEmpty) {
                                                      try {
                                                        await ref
                                                            .read(
                                                              supabaseClientProvider,
                                                            )
                                                            .from('clients')
                                                            .upsert({
                                                              'name': name,
                                                            });
                                                      } catch (_) {}
                                                    }
                                                    setState(() {
                                                      _receivedSaved =
                                                          name.isNotEmpty;
                                                    });
                                                  } catch (_) {
                                                    // ignore
                                                  } finally {
                                                    setState(() {
                                                      _receivedSaving = false;
                                                    });
                                                    if (_receivedSaved) {
                                                      Future.delayed(
                                                        const Duration(
                                                          seconds: 2,
                                                        ),
                                                        () {
                                                          if (mounted) {
                                                            setState(
                                                              () =>
                                                                  _receivedSaved =
                                                                      false,
                                                            );
                                                          }
                                                        },
                                                      );
                                                    }
                                                  }
                                                },
                                              );
                                            },
                                          ),
                                          suggestionsCallback: (pattern) async {
                                            final profiles =
                                                ref
                                                    .watch(profilesProvider)
                                                    .valueOrNull ??
                                                [];
                                            final fromProfiles = profiles
                                                .map(
                                                  (p) => p.fullName.isEmpty
                                                      ? p.id
                                                      : p.fullName,
                                                )
                                                .where(
                                                  (n) =>
                                                      n.toLowerCase().contains(
                                                        pattern.toLowerCase(),
                                                      ),
                                                )
                                                .toList();
                                            try {
                                              final clientRows = await ref
                                                  .read(supabaseClientProvider)
                                                  .from('clients')
                                                  .select('name')
                                                  .ilike('name', '%$pattern%');
                                              final clientNames =
                                                  (clientRows as List<dynamic>?)
                                                      ?.map(
                                                        (r) =>
                                                            r['name'] as String,
                                                      )
                                                      .whereType<String>()
                                                      .toList() ??
                                                  <String>[];
                                              final merged = {
                                                ...fromProfiles,
                                                ...clientNames,
                                              }.toList();
                                              return merged;
                                            } catch (_) {
                                              return fromProfiles;
                                            }
                                          },
                                          itemBuilder: (context, suggestion) =>
                                              ListTile(title: Text(suggestion)),
                                          onSuggestionSelected:
                                              (suggestion) async {
                                                _receivedDebounce?.cancel();
                                                _receivedController.text =
                                                    suggestion;
                                                setState(() {
                                                  _receivedSaving = true;
                                                  _receivedSaved = false;
                                                });
                                                try {
                                                  await ref
                                                      .read(
                                                        tasksControllerProvider,
                                                      )
                                                      .updateTask(
                                                        taskId: task.id,
                                                        receivedBy:
                                                            suggestion.isEmpty
                                                            ? null
                                                            : suggestion,
                                                      );
                                                  if (suggestion.isNotEmpty) {
                                                    try {
                                                      await ref
                                                          .read(
                                                            supabaseClientProvider,
                                                          )
                                                          .from('clients')
                                                          .upsert({
                                                            'name': suggestion,
                                                          });
                                                    } catch (_) {}
                                                  }
                                                  setState(
                                                    () => _receivedSaved =
                                                        suggestion.isNotEmpty,
                                                  );
                                                } catch (_) {
                                                } finally {
                                                  setState(
                                                    () =>
                                                        _receivedSaving = false,
                                                  );
                                                  if (_receivedSaved) {
                                                    Future.delayed(
                                                      const Duration(
                                                        seconds: 2,
                                                      ),
                                                      () {
                                                        if (mounted) {
                                                          setState(
                                                            () =>
                                                                _receivedSaved =
                                                                    false,
                                                          );
                                                        }
                                                      },
                                                    );
                                                  }
                                                }
                                              },
                                        ),
                                      ],
                                    ),
                                  ),
                                ),

                                // Action taken (rich text)
                                Padding(
                                  padding: const EdgeInsets.only(top: 8.0),
                                  child: Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: [
                                      Row(
                                        children: [
                                          const Text('Action taken'),
                                          const Spacer(),
                                          IconButton(
                                            tooltip:
                                                'Improve action taken with Gemini',
                                            icon: Image.asset(
                                              'assets/gemini_icon.png',
                                              width: 24,
                                              height: 24,
                                              errorBuilder:
                                                  (context, error, stackTrace) {
                                                    return const Icon(
                                                      Icons.auto_awesome,
                                                    );
                                                  },
                                            ),
                                            onPressed: () =>
                                                _processActionTakenWithGemini(
                                                  context,
                                                  ref,
                                                ),
                                          ),
                                        ],
                                      ),
                                      const SizedBox(height: 6),
                                      // Toolbar + editor with inline save indicator
                                      GeminiAnimatedBorder(
                                        isProcessing: _actionProcessing,
                                        child: Container(
                                          height: isWide ? 260 : 220,
                                          padding: const EdgeInsets.all(8),
                                          decoration: BoxDecoration(
                                            border: Border.all(
                                              color: Theme.of(
                                                context,
                                              ).colorScheme.outline,
                                            ),
                                            borderRadius: BorderRadius.circular(
                                              8,
                                            ),
                                          ),
                                          child: Stack(
                                            children: [
                                              Column(
                                                children: [
                                                  isWide
                                                      ? Row(
                                                          children: [
                                                            IconButton(
                                                              tooltip: 'Bold',
                                                              icon: const Icon(
                                                                Icons
                                                                    .format_bold,
                                                              ),
                                                              onPressed: () =>
                                                                  _actionController
                                                                      ?.formatSelection(
                                                                        quill
                                                                            .Attribute
                                                                            .bold,
                                                                      ),
                                                            ),
                                                            IconButton(
                                                              tooltip: 'Italic',
                                                              icon: const Icon(
                                                                Icons
                                                                    .format_italic,
                                                              ),
                                                              onPressed: () =>
                                                                  _actionController
                                                                      ?.formatSelection(
                                                                        quill
                                                                            .Attribute
                                                                            .italic,
                                                                      ),
                                                            ),
                                                            IconButton(
                                                              tooltip:
                                                                  'Underline',
                                                              icon: const Icon(
                                                                Icons
                                                                    .format_underlined,
                                                              ),
                                                              onPressed: () =>
                                                                  _actionController
                                                                      ?.formatSelection(
                                                                        quill
                                                                            .Attribute
                                                                            .underline,
                                                                      ),
                                                            ),
                                                            IconButton(
                                                              tooltip:
                                                                  'Bullet list',
                                                              icon: const Icon(
                                                                Icons
                                                                    .format_list_bulleted,
                                                              ),
                                                              onPressed: () =>
                                                                  _actionController
                                                                      ?.formatSelection(
                                                                        quill
                                                                            .Attribute
                                                                            .ul,
                                                                      ),
                                                            ),
                                                            IconButton(
                                                              tooltip:
                                                                  'Numbered list',
                                                              icon: const Icon(
                                                                Icons
                                                                    .format_list_numbered,
                                                              ),
                                                              onPressed: () =>
                                                                  _actionController
                                                                      ?.formatSelection(
                                                                        quill
                                                                            .Attribute
                                                                            .ol,
                                                                      ),
                                                            ),
                                                            const SizedBox(
                                                              width: 8,
                                                            ),
                                                            IconButton(
                                                              tooltip:
                                                                  'Heading 2',
                                                              icon: const Icon(
                                                                Icons
                                                                    .format_size,
                                                              ),
                                                              onPressed: () =>
                                                                  _actionController
                                                                      ?.formatSelection(
                                                                        quill
                                                                            .Attribute
                                                                            .h2,
                                                                      ),
                                                            ),
                                                            IconButton(
                                                              tooltip:
                                                                  'Heading 3',
                                                              icon: const Icon(
                                                                Icons
                                                                    .format_size,
                                                                size: 18,
                                                              ),
                                                              onPressed: () =>
                                                                  _actionController
                                                                      ?.formatSelection(
                                                                        quill
                                                                            .Attribute
                                                                            .h3,
                                                                      ),
                                                            ),
                                                            IconButton(
                                                              tooltip: 'Undo',
                                                              icon: const Icon(
                                                                Icons.undo,
                                                              ),
                                                              onPressed: () =>
                                                                  _actionController
                                                                      ?.undo(),
                                                            ),
                                                            IconButton(
                                                              tooltip: 'Redo',
                                                              icon: const Icon(
                                                                Icons.redo,
                                                              ),
                                                              onPressed: () =>
                                                                  _actionController
                                                                      ?.redo(),
                                                            ),
                                                            IconButton(
                                                              tooltip:
                                                                  'Insert link',
                                                              icon: const Icon(
                                                                Icons.link,
                                                              ),
                                                              onPressed: () async {
                                                                final urlCtrl =
                                                                    TextEditingController();
                                                                final res = await showDialog<String?>(
                                                                  context:
                                                                      context,
                                                                  builder: (ctx) => AlertDialog(
                                                                    title: const Text(
                                                                      'Insert link',
                                                                    ),
                                                                    content: TextField(
                                                                      controller:
                                                                          urlCtrl,
                                                                      decoration: const InputDecoration(
                                                                        hintText:
                                                                            'https://',
                                                                      ),
                                                                    ),
                                                                    actions: [
                                                                      TextButton(
                                                                        onPressed: () => Navigator.of(
                                                                          ctx,
                                                                        ).pop(),
                                                                        child: const Text(
                                                                          'Cancel',
                                                                        ),
                                                                      ),
                                                                      TextButton(
                                                                        onPressed: () =>
                                                                            Navigator.of(
                                                                              ctx,
                                                                            ).pop(
                                                                              urlCtrl.text.trim(),
                                                                            ),
                                                                        child: const Text(
                                                                          'Insert',
                                                                        ),
                                                                      ),
                                                                    ],
                                                                  ),
                                                                );
                                                                if (res ==
                                                                        null ||
                                                                    res.isEmpty) {
                                                                  return;
                                                                }
                                                                final sel =
                                                                    _actionController
                                                                        ?.selection ??
                                                                    const TextSelection.collapsed(
                                                                      offset: 0,
                                                                    );
                                                                final start = sel
                                                                    .baseOffset;
                                                                final end = sel
                                                                    .extentOffset;
                                                                if (!sel.isCollapsed &&
                                                                    end >
                                                                        start) {
                                                                  final len =
                                                                      end -
                                                                      start;
                                                                  try {
                                                                    _actionController
                                                                        ?.document
                                                                        .delete(
                                                                          start,
                                                                          len,
                                                                        );
                                                                  } catch (_) {}
                                                                  _actionController
                                                                      ?.document
                                                                      .insert(
                                                                        start,
                                                                        res,
                                                                      );
                                                                } else {
                                                                  _actionController
                                                                      ?.document
                                                                      .insert(
                                                                        start,
                                                                        res,
                                                                      );
                                                                }
                                                              },
                                                            ),
                                                            IconButton(
                                                              tooltip:
                                                                  'Insert image',
                                                              icon: const Icon(
                                                                Icons.image,
                                                              ),
                                                              onPressed: () async {
                                                                try {
                                                                  final r = await FilePicker
                                                                      .platform
                                                                      .pickFiles(
                                                                        withData:
                                                                            true,
                                                                        type: FileType
                                                                            .image,
                                                                      );
                                                                  if (r ==
                                                                          null ||
                                                                      r
                                                                          .files
                                                                          .isEmpty) {
                                                                    return;
                                                                  }
                                                                  final file = r
                                                                      .files
                                                                      .first;
                                                                  final bytes =
                                                                      file.bytes;
                                                                  if (bytes ==
                                                                      null) {
                                                                    return;
                                                                  }
                                                                  final ext =
                                                                      file.extension ??
                                                                      'png';
                                                                  String? url;
                                                                  try {
                                                                    url = await ref
                                                                        .read(
                                                                          tasksControllerProvider,
                                                                        )
                                                                        .uploadActionImage(
                                                                          taskId:
                                                                              task.id,
                                                                          bytes:
                                                                              bytes,
                                                                          extension:
                                                                              ext,
                                                                        );
                                                                  } catch (e) {
                                                                    showErrorSnackBar(
                                                                      context,
                                                                      'Upload error: $e',
                                                                    );
                                                                    return;
                                                                  }
                                                                  if (url ==
                                                                      null) {
                                                                    showErrorSnackBar(
                                                                      context,
                                                                      'Image upload failed (no URL returned)',
                                                                    );
                                                                    return;
                                                                  }
                                                                  final trimmedUrl =
                                                                      url.trim();
                                                                  final idx =
                                                                      _actionController
                                                                          ?.selection
                                                                          .baseOffset ??
                                                                      0;
                                                                  // ignore: avoid_print
                                                                  print(
                                                                    'inserting image embed idx=$idx url=$trimmedUrl',
                                                                  );
                                                                  _actionController
                                                                      ?.document
                                                                      .insert(
                                                                        idx,
                                                                        quill
                                                                            .BlockEmbed.image(
                                                                          trimmedUrl,
                                                                        ),
                                                                      );
                                                                } catch (_) {}
                                                              },
                                                            ),
                                                          ],
                                                        )
                                                      : SingleChildScrollView(
                                                          scrollDirection:
                                                              Axis.horizontal,
                                                          child: Row(
                                                            children: [
                                                              IconButton(
                                                                tooltip: 'Bold',
                                                                icon: const Icon(
                                                                  Icons
                                                                      .format_bold,
                                                                ),
                                                                onPressed: () =>
                                                                    _actionController?.formatSelection(
                                                                      quill
                                                                          .Attribute
                                                                          .bold,
                                                                    ),
                                                              ),
                                                              IconButton(
                                                                tooltip:
                                                                    'Italic',
                                                                icon: const Icon(
                                                                  Icons
                                                                      .format_italic,
                                                                ),
                                                                onPressed: () =>
                                                                    _actionController?.formatSelection(
                                                                      quill
                                                                          .Attribute
                                                                          .italic,
                                                                    ),
                                                              ),
                                                              IconButton(
                                                                tooltip:
                                                                    'Underline',
                                                                icon: const Icon(
                                                                  Icons
                                                                      .format_underlined,
                                                                ),
                                                                onPressed: () =>
                                                                    _actionController?.formatSelection(
                                                                      quill
                                                                          .Attribute
                                                                          .underline,
                                                                    ),
                                                              ),
                                                              IconButton(
                                                                tooltip:
                                                                    'Bullet list',
                                                                icon: const Icon(
                                                                  Icons
                                                                      .format_list_bulleted,
                                                                ),
                                                                onPressed: () =>
                                                                    _actionController
                                                                        ?.formatSelection(
                                                                          quill
                                                                              .Attribute
                                                                              .ul,
                                                                        ),
                                                              ),
                                                              IconButton(
                                                                tooltip:
                                                                    'Numbered list',
                                                                icon: const Icon(
                                                                  Icons
                                                                      .format_list_numbered,
                                                                ),
                                                                onPressed: () =>
                                                                    _actionController
                                                                        ?.formatSelection(
                                                                          quill
                                                                              .Attribute
                                                                              .ol,
                                                                        ),
                                                              ),
                                                              const SizedBox(
                                                                width: 8,
                                                              ),
                                                              IconButton(
                                                                tooltip:
                                                                    'Heading 2',
                                                                icon: const Icon(
                                                                  Icons
                                                                      .format_size,
                                                                ),
                                                                onPressed: () =>
                                                                    _actionController
                                                                        ?.formatSelection(
                                                                          quill
                                                                              .Attribute
                                                                              .h2,
                                                                        ),
                                                              ),
                                                              IconButton(
                                                                tooltip:
                                                                    'Heading 3',
                                                                icon: const Icon(
                                                                  Icons
                                                                      .format_size,
                                                                  size: 18,
                                                                ),
                                                                onPressed: () =>
                                                                    _actionController
                                                                        ?.formatSelection(
                                                                          quill
                                                                              .Attribute
                                                                              .h3,
                                                                        ),
                                                              ),
                                                              IconButton(
                                                                tooltip: 'Undo',
                                                                icon:
                                                                    const Icon(
                                                                      Icons
                                                                          .undo,
                                                                    ),
                                                                onPressed: () =>
                                                                    _actionController
                                                                        ?.undo(),
                                                              ),
                                                              IconButton(
                                                                tooltip: 'Redo',
                                                                icon:
                                                                    const Icon(
                                                                      Icons
                                                                          .redo,
                                                                    ),
                                                                onPressed: () =>
                                                                    _actionController
                                                                        ?.redo(),
                                                              ),
                                                              IconButton(
                                                                tooltip:
                                                                    'Insert link',
                                                                icon:
                                                                    const Icon(
                                                                      Icons
                                                                          .link,
                                                                    ),
                                                                onPressed: () async {
                                                                  final urlCtrl =
                                                                      TextEditingController();
                                                                  final res = await showDialog<String?>(
                                                                    context:
                                                                        context,
                                                                    builder: (ctx) => AlertDialog(
                                                                      title: const Text(
                                                                        'Insert link',
                                                                      ),
                                                                      content: TextField(
                                                                        controller:
                                                                            urlCtrl,
                                                                        decoration: const InputDecoration(
                                                                          hintText:
                                                                              'https://',
                                                                        ),
                                                                      ),
                                                                      actions: [
                                                                        TextButton(
                                                                          onPressed: () => Navigator.of(
                                                                            ctx,
                                                                          ).pop(),
                                                                          child: const Text(
                                                                            'Cancel',
                                                                          ),
                                                                        ),
                                                                        TextButton(
                                                                          onPressed: () => Navigator.of(ctx).pop(
                                                                            urlCtrl.text.trim(),
                                                                          ),
                                                                          child: const Text(
                                                                            'Insert',
                                                                          ),
                                                                        ),
                                                                      ],
                                                                    ),
                                                                  );
                                                                  if (res ==
                                                                          null ||
                                                                      res.isEmpty) {
                                                                    return;
                                                                  }
                                                                  final sel =
                                                                      _actionController
                                                                          ?.selection ??
                                                                      const TextSelection.collapsed(
                                                                        offset:
                                                                            0,
                                                                      );
                                                                  final start =
                                                                      sel.baseOffset;
                                                                  final end = sel
                                                                      .extentOffset;
                                                                  if (!sel.isCollapsed &&
                                                                      end >
                                                                          start) {
                                                                    final len =
                                                                        end -
                                                                        start;
                                                                    try {
                                                                      _actionController
                                                                          ?.document
                                                                          .delete(
                                                                            start,
                                                                            len,
                                                                          );
                                                                    } catch (
                                                                      _
                                                                    ) {}
                                                                    _actionController
                                                                        ?.document
                                                                        .insert(
                                                                          start,
                                                                          res,
                                                                        );
                                                                  } else {
                                                                    _actionController
                                                                        ?.document
                                                                        .insert(
                                                                          start,
                                                                          res,
                                                                        );
                                                                  }
                                                                },
                                                              ),
                                                              IconButton(
                                                                tooltip:
                                                                    'Insert image',
                                                                icon: const Icon(
                                                                  Icons.image,
                                                                ),
                                                                onPressed: () async {
                                                                  try {
                                                                    final r = await FilePicker
                                                                        .platform
                                                                        .pickFiles(
                                                                          withData:
                                                                              true,
                                                                          type:
                                                                              FileType.image,
                                                                        );
                                                                    if (r ==
                                                                            null ||
                                                                        r
                                                                            .files
                                                                            .isEmpty) {
                                                                      return;
                                                                    }
                                                                    final file = r
                                                                        .files
                                                                        .first;
                                                                    final bytes =
                                                                        file.bytes;
                                                                    if (bytes ==
                                                                        null) {
                                                                      return;
                                                                    }
                                                                    final ext =
                                                                        file.extension ??
                                                                        'png';
                                                                    String? url;
                                                                    try {
                                                                      url = await ref
                                                                          .read(
                                                                            tasksControllerProvider,
                                                                          )
                                                                          .uploadActionImage(
                                                                            taskId:
                                                                                task.id,
                                                                            bytes:
                                                                                bytes,
                                                                            extension:
                                                                                ext,
                                                                          );
                                                                    } catch (
                                                                      e
                                                                    ) {
                                                                      showErrorSnackBar(
                                                                        context,
                                                                        'Upload error: $e',
                                                                      );
                                                                      return;
                                                                    }
                                                                    if (url ==
                                                                        null) {
                                                                      showErrorSnackBar(
                                                                        context,
                                                                        'Image upload failed (no URL returned)',
                                                                      );
                                                                      return;
                                                                    }
                                                                    final trimmedUrl =
                                                                        url.trim();
                                                                    final idx =
                                                                        _actionController
                                                                            ?.selection
                                                                            .baseOffset ??
                                                                        0;
                                                                    // ignore: avoid_print
                                                                    print(
                                                                      'inserting image embed idx=$idx url=$trimmedUrl',
                                                                    );
                                                                    _actionController
                                                                        ?.document
                                                                        .insert(
                                                                          idx,
                                                                          quill
                                                                              .BlockEmbed.image(
                                                                            trimmedUrl,
                                                                          ),
                                                                        );
                                                                  } catch (_) {}
                                                                },
                                                              ),
                                                            ],
                                                          ),
                                                        ),
                                                  Expanded(
                                                    child: MouseRegion(
                                                      cursor: SystemMouseCursors
                                                          .text,
                                                      child: quill.QuillEditor.basic(
                                                        controller:
                                                            _actionController!,
                                                        focusNode:
                                                            _actionFocusNode,
                                                        scrollController:
                                                            _actionScrollController,
                                                        config: quill.QuillEditorConfig(
                                                          embedBuilders: const [
                                                            _ImageEmbedBuilder(),
                                                          ],
                                                          scrollable: true,
                                                          padding:
                                                              EdgeInsets.zero,
                                                        ),
                                                      ),
                                                    ),
                                                  ),
                                                ],
                                              ),
                                              Positioned(
                                                right: 6,
                                                bottom: 6,
                                                child: _actionSaving
                                                    ? SizedBox(
                                                        width: 20,
                                                        height: 20,
                                                        child: ScaleTransition(
                                                          scale: _savePulse,
                                                          child: const Icon(
                                                            Icons.save,
                                                            size: 16,
                                                          ),
                                                        ),
                                                      )
                                                    : _actionSaved
                                                    ? SizedBox(
                                                        width: 20,
                                                        height: 20,
                                                        child: Stack(
                                                          alignment:
                                                              Alignment.center,
                                                          children: const [
                                                            Icon(
                                                              Icons.save,
                                                              size: 16,
                                                              color:
                                                                  Colors.green,
                                                            ),
                                                            Positioned(
                                                              right: -2,
                                                              bottom: -2,
                                                              child: Icon(
                                                                Icons.check,
                                                                size: 10,
                                                                color: Colors
                                                                    .white,
                                                              ),
                                                            ),
                                                          ],
                                                        ),
                                                      )
                                                    : const SizedBox.shrink(),
                                              ),
                                            ],
                                          ),
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                                // Attachments (Tab 5)
                                SingleChildScrollView(
                                  child: Padding(
                                    padding: const EdgeInsets.only(top: 8.0),
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: [
                                        const Text('File Attachments'),
                                        const SizedBox(height: 12),
                                        Center(
                                          child: FilledButton.icon(
                                            icon: const Icon(Icons.upload_file),
                                            label: const Text(
                                              'Upload File (Max 25MB)',
                                            ),
                                            onPressed: () =>
                                                _uploadTaskAttachment(task.id),
                                          ),
                                        ),
                                        const SizedBox(height: 16),
                                        Builder(
                                          builder: (context) {
                                            // Load attachments once per task
                                            if (_seededTaskId != null &&
                                                _seededTaskId == task.id &&
                                                _attachments == null &&
                                                !_loadingAttachments) {
                                              WidgetsBinding.instance
                                                  .addPostFrameCallback((_) {
                                                    _loadAttachments(task.id);
                                                  });
                                            }
                                            if (_loadingAttachments) {
                                              return const Center(
                                                child:
                                                    CircularProgressIndicator(),
                                              );
                                            }
                                            final files = _attachments ?? [];
                                            if (files.isEmpty) {
                                              return const Center(
                                                child: Padding(
                                                  padding: EdgeInsets.all(16.0),
                                                  child: Text(
                                                    'No attachments yet',
                                                    style: TextStyle(
                                                      color: Colors.grey,
                                                    ),
                                                  ),
                                                ),
                                              );
                                            }
                                            return ListView.separated(
                                              shrinkWrap: true,
                                              physics:
                                                  const NeverScrollableScrollPhysics(),
                                              itemCount: files.length,
                                              separatorBuilder:
                                                  (context, index) =>
                                                      const Divider(),
                                              itemBuilder: (context, index) {
                                                final file = files[index];
                                                return ListTile(
                                                  leading: const Icon(
                                                    Icons.insert_drive_file,
                                                  ),
                                                  title: Text(file),
                                                  subtitle: Text(
                                                    'Tap to download',
                                                    style: Theme.of(
                                                      context,
                                                    ).textTheme.bodySmall,
                                                  ),
                                                  trailing: IconButton(
                                                    icon: const Icon(
                                                      Icons.delete,
                                                      color: Colors.red,
                                                    ),
                                                    onPressed: () =>
                                                        _deleteTaskAttachment(
                                                          task.id,
                                                          file,
                                                        ),
                                                  ),
                                                  onTap: () =>
                                                      _downloadTaskAttachment(
                                                        task.id,
                                                        file,
                                                      ),
                                                );
                                              },
                                            );
                                          },
                                        ),
                                      ],
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ],
            );

            final detailsCard = Card(
              child: Padding(
                padding: const EdgeInsets.all(20),
                child: SingleChildScrollView(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Align(
                        alignment: Alignment.topLeft,
                        child: IconButton(
                          icon: const Icon(Icons.arrow_back),
                          onPressed: () => Navigator.of(context).pop(),
                        ),
                      ),
                      detailsContent,
                    ],
                  ),
                ),
              ),
            );

            // Tabbed area: Chat + Activity
            final tabbedCard = Card(
              child: DefaultTabController(
                length: 2,
                child: Column(
                  children: [
                    Material(
                      color: Theme.of(context).colorScheme.surface,
                      child: TabBar(
                        labelColor: Theme.of(context).colorScheme.onSurface,
                        indicatorColor: Theme.of(context).colorScheme.primary,
                        tabs: const [
                          Tab(text: 'Chat'),
                          Tab(text: 'Activity'),
                        ],
                      ),
                    ),
                    SizedBox(height: 8),
                    Expanded(
                      child: TabBarView(
                        children: [
                          // Chat tab (existing messages UI)
                          Padding(
                            padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
                            child: Column(
                              children: [
                                Expanded(
                                  child: messagesAsync.when(
                                    data: (messages) => _buildMessages(
                                      context,
                                      messages,
                                      profilesAsync.valueOrNull ?? [],
                                    ),
                                    loading: () => const Center(
                                      child: CircularProgressIndicator(),
                                    ),
                                    error: (error, _) => Center(
                                      child: Text(
                                        'Failed to load messages: $error',
                                      ),
                                    ),
                                  ),
                                ),
                                SafeArea(
                                  top: false,
                                  child: Padding(
                                    padding: const EdgeInsets.fromLTRB(
                                      0,
                                      8,
                                      0,
                                      12,
                                    ),
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: [
                                        if (typingState.userIds.isNotEmpty)
                                          Padding(
                                            padding: const EdgeInsets.only(
                                              bottom: 6,
                                            ),
                                            child: Container(
                                              padding:
                                                  const EdgeInsets.symmetric(
                                                    horizontal: 10,
                                                    vertical: 6,
                                                  ),
                                              decoration: BoxDecoration(
                                                color: Theme.of(context)
                                                    .colorScheme
                                                    .surfaceContainerHighest,
                                                borderRadius:
                                                    BorderRadius.circular(16),
                                              ),
                                              child: Row(
                                                mainAxisSize: MainAxisSize.min,
                                                children: [
                                                  Text(
                                                    _typingLabel(
                                                      typingState.userIds,
                                                      profilesAsync,
                                                    ),
                                                    style: Theme.of(
                                                      context,
                                                    ).textTheme.labelSmall,
                                                  ),
                                                  const SizedBox(width: 8),
                                                  TypingDots(
                                                    size: 8,
                                                    color: Theme.of(
                                                      context,
                                                    ).colorScheme.primary,
                                                  ),
                                                ],
                                              ),
                                            ),
                                          ),
                                        if (_mentionQuery != null)
                                          Padding(
                                            padding: const EdgeInsets.only(
                                              bottom: 8,
                                            ),
                                            child: _buildMentionList(
                                              profilesAsync,
                                            ),
                                          ),
                                        if (!canSendMessages)
                                          Padding(
                                            padding: const EdgeInsets.only(
                                              bottom: 8,
                                            ),
                                            child: Text(
                                              'Messaging is disabled for completed tasks.',
                                              style: Theme.of(
                                                context,
                                              ).textTheme.labelMedium,
                                            ),
                                          ),
                                        Row(
                                          children: [
                                            Expanded(
                                              child: TextField(
                                                controller: _messageController,
                                                decoration:
                                                    const InputDecoration(
                                                      hintText: 'Message...',
                                                    ),
                                                textInputAction:
                                                    TextInputAction.send,
                                                enabled: canSendMessages,
                                                onChanged: (_) =>
                                                    _handleComposerChanged(
                                                      profilesAsync
                                                              .valueOrNull ??
                                                          [],
                                                      ref.read(
                                                        currentUserIdProvider,
                                                      ),
                                                      canSendMessages,
                                                      typingChannelId,
                                                    ),
                                                onSubmitted: (_) =>
                                                    _handleSendMessage(
                                                      task,
                                                      profilesAsync
                                                              .valueOrNull ??
                                                          [],
                                                      ref.read(
                                                        currentUserIdProvider,
                                                      ),
                                                      canSendMessages,
                                                      typingChannelId,
                                                    ),
                                              ),
                                            ),
                                            const SizedBox(width: 12),
                                            IconButton(
                                              tooltip: 'Send',
                                              onPressed: canSendMessages
                                                  ? () => _handleSendMessage(
                                                      task,
                                                      profilesAsync
                                                              .valueOrNull ??
                                                          [],
                                                      ref.read(
                                                        currentUserIdProvider,
                                                      ),
                                                      canSendMessages,
                                                      typingChannelId,
                                                    )
                                                  : null,
                                              icon: const Icon(Icons.send),
                                            ),
                                          ],
                                        ),
                                      ],
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),

                          // Activity tab
                          Padding(
                            padding: const EdgeInsets.fromLTRB(16, 8, 16, 12),
                            child: _buildActivityTab(
                              task,
                              assignments,
                              messagesAsync,
                              profilesAsync.valueOrNull ?? [],
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            );

            final mainContent = isWide
                ? Row(
                    children: [
                      Expanded(flex: 2, child: detailsCard),
                      const SizedBox(width: 16),
                      Expanded(flex: 3, child: tabbedCard),
                    ],
                  )
                : Stack(
                    children: [
                      CustomScrollView(
                        slivers: [
                          SliverToBoxAdapter(child: detailsCard),
                          const SliverToBoxAdapter(child: SizedBox(height: 12)),
                          SliverFillRemaining(
                            hasScrollBody: true,
                            child: tabbedCard,
                          ),
                        ],
                      ),
                      if (isRetrieving)
                        Positioned.fill(
                          child: AbsorbPointer(
                            absorbing: true,
                            child: Container(
                              color: Theme.of(context).colorScheme.surface
                                  .withAlpha((0.35 * 255).round()),
                              alignment: Alignment.topCenter,
                              padding: const EdgeInsets.only(top: 36),
                              child: SizedBox(
                                width: 280,
                                child: Card(
                                  elevation: 4,
                                  child: Padding(
                                    padding: const EdgeInsets.all(12.0),
                                    child: Row(
                                      mainAxisSize: MainAxisSize.min,
                                      children: const [
                                        SizedBox(
                                          width: 20,
                                          height: 20,
                                          child: CircularProgressIndicator(
                                            strokeWidth: 2,
                                          ),
                                        ),
                                        SizedBox(width: 12),
                                        Expanded(
                                          child: Text('Retrieving updates…'),
                                        ),
                                      ],
                                    ),
                                  ),
                                ),
                              ),
                            ),
                          ),
                        ),
                    ],
                  );

            return mainContent;
          },
        ),
      ),
    );
  }

  String _createdByLabel(
    AsyncValue<List<Profile>> profilesAsync,
    Task task,
    Ticket? ticket,
  ) {
    final creatorId = task.creatorId ?? ticket?.creatorId;
    if (creatorId == null || creatorId.isEmpty) {
      return 'Created by: Unknown';
    }
    final profile = profilesAsync.valueOrNull
        ?.where((item) => item.id == creatorId)
        .firstOrNull;
    final name = profile?.fullName.isNotEmpty == true
        ? profile!.fullName
        : creatorId;
    return 'Created by: $name';
  }

  Widget _buildMessages(
    BuildContext context,
    List<TicketMessage> messages,
    List<Profile> profiles,
  ) {
    if (messages.isEmpty) {
      return const Center(child: Text('No messages yet.'));
    }
    final profileById = {for (final profile in profiles) profile.id: profile};
    final currentUserId = ref.read(currentUserIdProvider);

    return ListView.builder(
      reverse: true,
      padding: const EdgeInsets.fromLTRB(0, 16, 0, 72),
      itemCount: messages.length,
      itemBuilder: (context, index) {
        final message = messages[index];
        final isMe = currentUserId != null && message.senderId == currentUserId;
        final senderName = message.senderId == null
            ? 'System'
            : profileById[message.senderId]?.fullName ?? message.senderId!;
        final bubbleColor = isMe
            ? Theme.of(context).colorScheme.primaryContainer
            : Theme.of(context).colorScheme.surfaceContainerHighest;
        final textColor = isMe
            ? Theme.of(context).colorScheme.onPrimaryContainer
            : Theme.of(context).colorScheme.onSurface;

        return Align(
          alignment: isMe ? Alignment.centerRight : Alignment.centerLeft,
          child: Column(
            crossAxisAlignment: isMe
                ? CrossAxisAlignment.end
                : CrossAxisAlignment.start,
            children: [
              if (!isMe)
                Padding(
                  padding: const EdgeInsets.only(bottom: 4),
                  child: Text(
                    senderName,
                    style: Theme.of(context).textTheme.labelSmall,
                  ),
                ),
              Container(
                margin: const EdgeInsets.only(bottom: 12),
                padding: const EdgeInsets.all(12),
                constraints: const BoxConstraints(minWidth: 160, maxWidth: 520),
                decoration: BoxDecoration(
                  color: bubbleColor,
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(
                      AppSurfaces.of(context).cardRadius,
                    ),
                    topRight: Radius.circular(
                      AppSurfaces.of(context).cardRadius,
                    ),
                    bottomLeft: Radius.circular(
                      isMe ? AppSurfaces.of(context).cardRadius : 4,
                    ),
                    bottomRight: Radius.circular(
                      isMe ? 4 : AppSurfaces.of(context).cardRadius,
                    ),
                  ),
                ),
                child: _buildMentionText(message.content, textColor, profiles),
              ),
            ],
          ),
        );
      },
    );
  }

  Widget _buildActivityTab(
    Task task,
    List<TaskAssignment> assignments,
    AsyncValue<List<TicketMessage>> messagesAsync,
    List<Profile> profiles,
  ) {
    final logsAsync = ref.watch(taskActivityLogsProvider(task.id));
    final logs = logsAsync.valueOrNull ?? <TaskActivityLog>[];
    final profileById = {for (final p in profiles) p.id: p};

    // Find the latest assignment (by createdAt)
    final assignedForTask =
        assignments.where((a) => a.taskId == task.id).toList()
          ..sort((a, b) => a.createdAt.compareTo(b.createdAt));
    final latestAssignment = assignedForTask.isEmpty
        ? null
        : assignedForTask.last;

    DateTime? startedByAssignee;
    if (latestAssignment != null) {
      for (final l in logs) {
        if (l.actionType == 'started') {
          if (l.actorId == latestAssignment.userId &&
              l.createdAt.isAfter(latestAssignment.createdAt)) {
            startedByAssignee = l.createdAt;
            break;
          }
        }
      }
    }

    Duration? responseDuration;
    DateTime? responseAt;
    if (latestAssignment != null) {
      final assignedAt = latestAssignment.createdAt;
      final candidates = <DateTime>[];
      if (startedByAssignee != null) {
        candidates.add(startedByAssignee);
      }
      if (candidates.isNotEmpty) {
        candidates.sort();
        responseAt = candidates.first;
        responseDuration = responseAt.difference(assignedAt);
      }
    }

    // Render timeline (oldest -> newest)
    final timeline = <Widget>[];
    if (logs.isEmpty) {
      timeline.add(const Text('No activity yet.'));
    } else {
      final chronological = List.from(logs.reversed);
      for (final l in chronological) {
        final actorName = l.actorId == null
            ? 'System'
            : (profileById[l.actorId]?.fullName ?? l.actorId!);
        switch (l.actionType) {
          case 'created':
            timeline.add(
              _activityRow(
                'Task created',
                actorName,
                l.createdAt,
                icon: Icons.add_task,
              ),
            );
            break;
          case 'assigned':
            final meta = l.meta ?? {};
            final userId = meta['user_id'] as String?;
            final auto = meta['auto'] == true;
            final name = userId == null
                ? 'Unknown'
                : (profileById[userId]?.fullName ?? userId);
            timeline.add(
              _activityRow(
                auto ? 'Auto-assigned to $name' : 'Assigned to $name',
                actorName,
                l.createdAt,
                icon: Icons.person_add,
              ),
            );
            break;
          case 'reassigned':
            final meta = l.meta ?? {};

            final to = (meta['to'] as List?) ?? [];
            final toNames = to
                .map((id) => profileById[id]?.fullName ?? id)
                .join(', ');
            timeline.add(
              _activityRow(
                'Reassigned to $toNames',
                actorName,
                l.createdAt,
                icon: Icons.swap_horiz,
              ),
            );
            break;
          case 'started':
            {
              var label = 'Task started';
              if (latestAssignment != null &&
                  l.actorId == latestAssignment.userId &&
                  responseDuration != null) {
                final assigneeName =
                    profileById[latestAssignment.userId]?.fullName ??
                    latestAssignment.userId;
                final resp = responseAt ?? AppTime.now();
                label =
                    'Task started — Response: ${_formatDuration(responseDuration)} ($assigneeName responded at ${AppTime.formatDate(resp)} ${AppTime.formatTime(resp)})';
              }
              timeline.add(
                _activityRow(
                  label,
                  actorName,
                  l.createdAt,
                  icon: Icons.play_arrow,
                ),
              );
            }
            break;
          case 'completed':
            {
              var label = 'Task completed';
              if (task.startedAt != null) {
                final start = task.startedAt!;
                final end = task.completedAt ?? l.createdAt;
                final exec = end.difference(start);
                if (exec.inMilliseconds > 0) {
                  label =
                      'Task completed — Execution: ${_formatDuration(exec)} (${AppTime.formatDate(start)} ${AppTime.formatTime(start)} → ${AppTime.formatDate(end)} ${AppTime.formatTime(end)})';
                }
              }
              timeline.add(
                _activityRow(
                  label,
                  actorName,
                  l.createdAt,
                  icon: Icons.check_circle,
                ),
              );
            }
            break;
          case 'cancelled':
            final meta = l.meta ?? {};
            final reason = (meta['reason'] as String?) ?? '';
            final base = reason.isNotEmpty
                ? 'Task cancelled — $reason'
                : 'Task cancelled';
            timeline.add(
              _activityRow(base, actorName, l.createdAt, icon: Icons.cancel),
            );
            break;
          default:
            timeline.add(
              _activityRow(
                l.actionType,
                actorName,
                l.createdAt,
                icon: Icons.info,
              ),
            );
        }
      }
    }

    // If the task is cancelled but no explicit cancelled activity row exists,
    // show a fallback using the task's cancellation fields.
    final hasCancelledLog = logs.any((e) => e.actionType == 'cancelled');
    if (task.status == 'cancelled' && !hasCancelledLog) {
      final reason = task.cancellationReason;
      final at = task.cancelledAt ?? AppTime.now();
      String inferredActor = 'System';
      try {
        final candidates = logs
            .where((e) => e.actorId != null && e.createdAt.isBefore(at))
            .toList();
        if (candidates.isNotEmpty) {
          candidates.sort((a, b) => a.createdAt.compareTo(b.createdAt));
          final last = candidates.last;
          inferredActor = profileById[last.actorId]?.fullName ?? last.actorId!;
        }
      } catch (_) {}

      timeline.add(
        _activityRow(
          reason != null && reason.isNotEmpty
              ? 'Task cancelled — $reason'
              : 'Task cancelled',
          inferredActor,
          at,
          icon: Icons.cancel,
        ),
      );
    }

    // Response and execution times are now merged into the related
    // 'Task started' and 'Task completed' timeline entries above.

    return SingleChildScrollView(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: timeline,
      ),
    );
  }

  // TAT helpers removed; timings are shown inline in the activity timeline.

  Widget _activityRow(
    String title,
    String actor,
    DateTime at, {
    IconData icon = Icons.circle,
  }) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          SizedBox(
            width: 28,
            child: Center(
              child: Icon(
                icon,
                size: 18,
                color: Theme.of(context).colorScheme.primary,
              ),
            ),
          ),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(title, style: Theme.of(context).textTheme.bodyMedium),
                const SizedBox(height: 4),
                Text(
                  '$actor • ${AppTime.formatDate(at)} ${AppTime.formatTime(at)}',
                  style: Theme.of(context).textTheme.labelSmall,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  String _formatDuration(Duration? duration) {
    if (duration == null) {
      return 'Pending';
    }
    if (duration.inSeconds < 60) {
      return 'Less than a minute';
    }
    final hours = duration.inHours;
    final minutes = duration.inMinutes.remainder(60);
    if (hours > 0) {
      return '${hours}h ${minutes}m';
    }
    return '${minutes}m';
  }

  Widget _buildMentionText(
    String text,
    Color baseColor,
    List<Profile> profiles,
  ) {
    final mentionColor = Theme.of(context).colorScheme.primary;
    final spans = _mentionSpans(text, baseColor, mentionColor, profiles);
    return RichText(
      text: TextSpan(
        children: spans,
        style: TextStyle(color: baseColor),
      ),
    );
  }

  List<TextSpan> _mentionSpans(
    String text,
    Color baseColor,
    Color mentionColor,
    List<Profile> profiles,
  ) {
    final mentionLabels = profiles
        .map(
          (profile) => profile.fullName.isEmpty ? profile.id : profile.fullName,
        )
        .where((label) => label.isNotEmpty)
        .map(_escapeRegExp)
        .toList();
    final pattern = mentionLabels.isEmpty
        ? r'@\S+'
        : '@(?:${mentionLabels.join('|')})';
    final matches = RegExp(pattern, caseSensitive: false).allMatches(text);
    if (matches.isEmpty) {
      return [
        TextSpan(
          text: text,
          style: TextStyle(color: baseColor),
        ),
      ];
    }

    final spans = <TextSpan>[];
    var lastIndex = 0;
    for (final match in matches) {
      if (match.start > lastIndex) {
        spans.add(
          TextSpan(
            text: text.substring(lastIndex, match.start),
            style: TextStyle(color: baseColor),
          ),
        );
      }
      spans.add(
        TextSpan(
          text: text.substring(match.start, match.end),
          style: TextStyle(color: mentionColor, fontWeight: FontWeight.w700),
        ),
      );
      lastIndex = match.end;
    }
    if (lastIndex < text.length) {
      spans.add(
        TextSpan(
          text: text.substring(lastIndex),
          style: TextStyle(color: baseColor),
        ),
      );
    }
    return spans;
  }

  String _escapeRegExp(String value) {
    return value.replaceAllMapped(
      RegExp(r'[\\^$.*+?()[\]{}|]'),
      (match) => '\\${match[0]}',
    );
  }

  AsyncValue<List<TicketMessage>> _mergeMessages(
    AsyncValue<List<TicketMessage>> taskMessages,
    AsyncValue<List<TicketMessage>>? ticketMessages,
  ) {
    if (ticketMessages == null) {
      return taskMessages;
    }
    return taskMessages.when(
      data: (taskData) => ticketMessages.when(
        data: (ticketData) {
          final byId = <int, TicketMessage>{
            for (final message in taskData) message.id: message,
            for (final message in ticketData) message.id: message,
          };
          final merged = byId.values.toList()
            ..sort((a, b) => b.createdAt.compareTo(a.createdAt));
          return AsyncValue.data(merged);
        },
        loading: () => const AsyncLoading<List<TicketMessage>>(),
        error: (error, stackTrace) =>
            AsyncError<List<TicketMessage>>(error, stackTrace),
      ),
      loading: () => const AsyncLoading<List<TicketMessage>>(),
      error: (error, stackTrace) =>
          AsyncError<List<TicketMessage>>(error, stackTrace),
    );
  }

  Future<void> _handleSendMessage(
    Task task,
    List<Profile> profiles,
    String? currentUserId,
    bool canSendMessages,
    String typingChannelId,
  ) async {
    if (!canSendMessages) return;
    final content = _messageController.text.trim();
    if (content.isEmpty) {
      return;
    }

    // Safely stop typing — controller may have been auto-disposed by Riverpod.
    final typingController = _maybeTypingController(typingChannelId);
    typingController?.stopTyping();

    // Capture mentioned user ids and clear the composer immediately so the
    // UI does not block while the network call completes. Perform the send
    // and mention notification creation in a background Future.
    final mentionUserIds = _extractMentionedUserIds(
      content,
      profiles,
      currentUserId,
    );
    if (mounted) {
      _messageController.clear();
      _clearMentions();
    }

    Future(() async {
      try {
        final message = await ref
            .read(ticketsControllerProvider)
            .sendTaskMessage(
              taskId: task.id,
              ticketId: task.ticketId,
              content: content,
            );

        if (mentionUserIds.isNotEmpty && currentUserId != null) {
          try {
            await ref
                .read(notificationsControllerProvider)
                .createMentionNotifications(
                  userIds: mentionUserIds,
                  actorId: currentUserId,
                  ticketId: task.ticketId,
                  taskId: task.id,
                  messageId: message.id,
                );
          } catch (_) {}
        }
      } catch (e, st) {
        debugPrint('sendTaskMessage error: $e\n$st');
      }
    });
  }

  void _handleComposerChanged(
    List<Profile> profiles,
    String? currentUserId,
    bool canSendMessages,
    String typingChannelId,
  ) {
    if (!canSendMessages) {
      _maybeTypingController(typingChannelId)?.stopTyping();
      _clearMentions();
      return;
    }
    _maybeTypingController(typingChannelId)?.userTyping();
    final text = _messageController.text;
    final cursor = _messageController.selection.baseOffset;
    if (cursor < 0) {
      _clearMentions();
      return;
    }
    final textBeforeCursor = text.substring(0, cursor);
    final atIndex = textBeforeCursor.lastIndexOf('@');
    if (atIndex == -1) {
      _clearMentions();
      return;
    }
    if (atIndex > 0 && !_isWhitespace(textBeforeCursor[atIndex - 1])) {
      _clearMentions();
      return;
    }
    final query = textBeforeCursor.substring(atIndex + 1);
    if (query.contains(RegExp(r'\s'))) {
      _clearMentions();
      return;
    }
    final normalizedQuery = query.toLowerCase();
    final candidates = profiles.where((profile) {
      if (profile.id == currentUserId) {
        return false;
      }
      final label = profile.fullName.isEmpty ? profile.id : profile.fullName;
      return label.toLowerCase().contains(normalizedQuery);
    }).toList();
    setState(() {
      _mentionQuery = query;
      _mentionStart = atIndex;
      _mentionResults = candidates.take(6).toList();
    });
  }

  void _clearMentions() {
    if (_mentionQuery == null && _mentionResults.isEmpty) {
      return;
    }
    setState(() {
      _mentionQuery = null;
      _mentionStart = null;
      _mentionResults = [];
    });
  }

  // Safely obtain the typing controller for [channelId].
  // Returns null if the provider has been disposed or is not mounted.
  TypingIndicatorController? _maybeTypingController(String channelId) {
    try {
      final controller = ref.read(typingIndicatorProvider(channelId).notifier);
      return controller.mounted ? controller : null;
    } on StateError {
      // provider was disposed concurrently
      return null;
    } catch (_) {
      return null;
    }
  }

  bool _isWhitespace(String char) {
    return char.trim().isEmpty;
  }

  List<String> _extractMentionedUserIds(
    String content,
    List<Profile> profiles,
    String? currentUserId,
  ) {
    final lower = content.toLowerCase();
    final mentioned = <String>{};
    for (final profile in profiles) {
      if (profile.id == currentUserId) continue;
      final label = profile.fullName.isEmpty ? profile.id : profile.fullName;
      if (label.isEmpty) continue;
      final token = '@${label.toLowerCase()}';
      if (lower.contains(token)) {
        mentioned.add(profile.id);
      }
    }
    return mentioned.toList();
  }

  Widget _buildMentionList(AsyncValue<List<Profile>> profilesAsync) {
    if (_mentionResults.isEmpty) {
      return const SizedBox.shrink();
    }

    return Container(
      constraints: const BoxConstraints(maxHeight: 200),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(
          AppSurfaces.of(context).compactCardRadius,
        ),
      ),
      child: ListView.separated(
        shrinkWrap: true,
        padding: const EdgeInsets.symmetric(vertical: 8),
        itemCount: _mentionResults.length,
        separatorBuilder: (context, index) => const SizedBox(height: 4),
        itemBuilder: (context, index) {
          final profile = _mentionResults[index];
          final label = profile.fullName.isEmpty
              ? profile.id
              : profile.fullName;
          return ListTile(
            dense: true,
            title: Text(label),
            onTap: () => _insertMention(profile),
          );
        },
      ),
    );
  }

  void _insertMention(Profile profile) {
    final start = _mentionStart;
    if (start == null) {
      _clearMentions();
      return;
    }
    final text = _messageController.text;
    final cursor = _messageController.selection.baseOffset;
    final end = cursor < 0 ? text.length : cursor;
    final label = profile.fullName.isEmpty ? profile.id : profile.fullName;
    final mentionText = '@$label ';
    final updated = text.replaceRange(start, end, mentionText);
    final newCursor = start + mentionText.length;
    _messageController.text = updated;
    _messageController.selection = TextSelection.collapsed(offset: newCursor);
    _clearMentions();
  }

  String _typingLabel(
    Set<String> userIds,
    AsyncValue<List<Profile>> profilesAsync,
  ) {
    final profileById = {
      for (final profile in profilesAsync.valueOrNull ?? [])
        profile.id: profile,
    };
    final names = userIds
        .map((id) => profileById[id]?.fullName ?? id)
        .where((name) => name.isNotEmpty)
        .toList();
    if (names.isEmpty) {
      return 'Someone is typing...';
    }
    if (names.length == 1) {
      return '${names.first} is typing...';
    }
    if (names.length == 2) {
      return '${names[0]} and ${names[1]} are typing...';
    }
    return '${names[0]}, ${names[1]} and others are typing...';
  }

  Future<void> _showEditTaskDialog(
    BuildContext context,
    WidgetRef ref,
    Task task,
  ) async {
    final dialogShape = AppSurfaces.of(context).dialogShape;
    // offices will be watched inside the dialog's Consumer so the dialog
    // can rebuild independently when the provider completes.
    final titleCtrl = TextEditingController(text: task.title);
    final descCtrl = TextEditingController(text: task.description);
    final existingSubjects = <String>[
      ...((ref.read(tasksProvider).valueOrNull ?? const <Task>[]).map(
        (task) => task.title,
      )),
      ...((ref.read(ticketsProvider).valueOrNull ?? const <Ticket>[]).map(
        (ticket) => ticket.subject,
      )),
    ];
    String? selectedOffice = task.officeId;

    // ---- Title-field AI-button visibility ----
    // The button is hidden by default and shown only after the user pauses
    // manual typing (700 ms debounce).  We can NOT rely on onChanged or
    // controller listeners because TypeAheadFormField fires those
    // unpredictably (on focus, overlay teardown, suggestion selection).
    // Instead we wrap the field in a KeyboardListener and only react to
    // actual key events.
    var showTitleGemini = false;
    var titleDeepSeek = false;
    var descDeepSeek = false;
    Timer? titleTypingTimer;

    try {
      await showDialog<void>(
        context: context,
        builder: (dialogContext) {
          var saving = false;
          var titleProcessing = false;
          var descProcessing = false;
          return StatefulBuilder(
            builder: (context, setDialogState) {
              return AlertDialog(
                shape: dialogShape,
                title: const Text('Edit Task'),
                content: SingleChildScrollView(
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Row(
                        children: [
                          Expanded(
                            child: GeminiAnimatedBorder(
                              isProcessing: titleProcessing,
                              useDeepSeekColors: titleDeepSeek,
                              child: KeyboardListener(
                                focusNode: FocusNode(),
                                onKeyEvent: (event) {
                                  // Only react to actual key-down (typing).
                                  if (event is! KeyDownEvent &&
                                      event is! KeyRepeatEvent) {
                                    return;
                                  }
                                  // Skip modifier-only keys.
                                  if (event.character == null ||
                                      event.character!.isEmpty) {
                                    return;
                                  }
                                  titleTypingTimer?.cancel();
                                  if (showTitleGemini) {
                                    setDialogState(
                                      () => showTitleGemini = false,
                                    );
                                  }
                                  titleTypingTimer = Timer(
                                    const Duration(milliseconds: 700),
                                    () {
                                      if (titleCtrl.text.trim().isNotEmpty) {
                                        setDialogState(
                                          () => showTitleGemini = true,
                                        );
                                      }
                                    },
                                  );
                                },
                                child: TypeAheadFormField<String>(
                                  textFieldConfiguration:
                                      TextFieldConfiguration(
                                        controller: titleCtrl,
                                        enabled: !saving,
                                        decoration: const InputDecoration(
                                          labelText: 'Title',
                                        ),
                                      ),
                                  suggestionsCallback: (pattern) async {
                                    return SubjectSuggestionEngine.suggest(
                                      existingSubjects: existingSubjects,
                                      query: pattern,
                                      limit: 8,
                                    );
                                  },
                                  itemBuilder: (context, suggestion) =>
                                      ListTile(
                                        dense: true,
                                        title: Text(suggestion),
                                      ),
                                  onSuggestionSelected: (suggestion) {
                                    titleTypingTimer?.cancel();
                                    titleCtrl
                                      ..text = suggestion
                                      ..selection = TextSelection.collapsed(
                                        offset: suggestion.length,
                                      );
                                    setDialogState(
                                      () => showTitleGemini = false,
                                    );
                                  },
                                ),
                              ),
                            ),
                          ),
                          // Show Gemini button only after the user pauses
                          // typing and has not selected a suggestion.
                          if (showTitleGemini)
                            GeminiButton(
                              textController: titleCtrl,
                              onTextUpdated: (updatedText) {
                                titleTypingTimer?.cancel();
                                setDialogState(() {
                                  titleCtrl.text = updatedText;
                                  showTitleGemini = false;
                                });
                              },
                              onProcessingStateChanged: (isProcessing) {
                                setDialogState(() {
                                  titleProcessing = isProcessing;
                                });
                              },
                              onProviderChanged: (isDeepSeek) {
                                setDialogState(
                                  () => titleDeepSeek = isDeepSeek,
                                );
                              },
                              tooltip: 'Improve task title with Gemini',
                              promptBuilder: (_) =>
                                  'Fix the spelling and grammar of this IT '
                                  'helpdesk ticket subject. Make it concise, '
                                  'clear, and professional in English. '
                                  'Return ONLY the corrected subject, '
                                  'no explanations:',
                            ),
                        ],
                      ),
                      const SizedBox(height: 8),
                      Row(
                        children: [
                          Expanded(
                            child: GeminiAnimatedTextField(
                              controller: descCtrl,
                              enabled: !saving,
                              labelText: 'Description',
                              maxLines: 4,
                              isProcessing: descProcessing,
                              useDeepSeekColors: descDeepSeek,
                            ),
                          ),
                          Padding(
                            padding: const EdgeInsets.only(left: 8.0),
                            child: GeminiButton(
                              textController: descCtrl,
                              onTextUpdated: (updatedText) {
                                setDialogState(() {
                                  descCtrl.text = updatedText;
                                });
                              },
                              onProcessingStateChanged: (isProcessing) {
                                setDialogState(() {
                                  descProcessing = isProcessing;
                                });
                              },
                              onProviderChanged: (isDeepSeek) {
                                setDialogState(() => descDeepSeek = isDeepSeek);
                              },
                              tooltip: 'Improve description with Gemini',
                              promptBuilder: (_) {
                                final subject = titleCtrl.text.trim();
                                final hint = subject.isNotEmpty
                                    ? 'about "$subject" '
                                    : '';
                                return 'Improve this IT helpdesk ticket '
                                    'description ${hint}for clarity and '
                                    'professionalism. Fix grammar and translate '
                                    'to English. Return ONLY the improved '
                                    'description, no explanations:';
                              },
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 8),
                      Consumer(
                        builder: (dialogContext, dialogRef, _) {
                          final officesAsync = dialogRef.watch(
                            officesOnceProvider,
                          );
                          return officesAsync.when(
                            data: (offices) {
                              final officesSorted = List<Office>.from(offices)
                                ..sort(
                                  (a, b) => a.name.toLowerCase().compareTo(
                                    b.name.toLowerCase(),
                                  ),
                                );
                              return DropdownButtonFormField<String?>(
                                initialValue: selectedOffice,
                                decoration: const InputDecoration(
                                  labelText: 'Office',
                                ),
                                items: [
                                  const DropdownMenuItem(
                                    value: null,
                                    child: Text('Unassigned'),
                                  ),
                                  for (final o in officesSorted)
                                    DropdownMenuItem(
                                      value: o.id,
                                      child: Text(o.name),
                                    ),
                                ],
                                onChanged: saving
                                    ? null
                                    : (v) => setDialogState(
                                        () => selectedOffice = v,
                                      ),
                              );
                            },
                            loading: () => const Padding(
                              padding: EdgeInsets.symmetric(vertical: 12),
                              child: LinearProgressIndicator(),
                            ),
                            error: (error, _) => const SizedBox.shrink(),
                          );
                        },
                      ),
                    ],
                  ),
                ),
                actions: [
                  TextButton(
                    onPressed: saving
                        ? null
                        : () => Navigator.of(dialogContext).pop(),
                    child: const Text('Cancel'),
                  ),
                  ElevatedButton(
                    onPressed: saving
                        ? null
                        : () async {
                            final title =
                                SubjectSuggestionEngine.normalizeDisplay(
                                  titleCtrl.text.trim(),
                                );
                            final desc = descCtrl.text.trim();
                            setDialogState(() => saving = true);
                            try {
                              await ref
                                  .read(tasksControllerProvider)
                                  .updateTaskFields(
                                    taskId: task.id,
                                    title: title.isEmpty ? null : title,
                                    description: desc.isEmpty ? null : desc,
                                    officeId: selectedOffice,
                                  );
                              ref.invalidate(tasksProvider);
                              ref.invalidate(taskByIdProvider(task.id));
                              if (!mounted) return;
                              Navigator.of(dialogContext).pop();
                              showSuccessSnackBar(context, 'Task updated');
                            } catch (e) {
                              if (!mounted) return;
                              showErrorSnackBar(
                                context,
                                'Failed to update task: $e',
                              );
                            } finally {
                              if (dialogContext.mounted) {
                                setDialogState(() => saving = false);
                              }
                            }
                          },
                    child: saving
                        ? const SizedBox(
                            width: 18,
                            height: 18,
                            child: CircularProgressIndicator(strokeWidth: 2),
                          )
                        : const Text('Save'),
                  ),
                ],
              );
            },
          );
        },
      );
    } finally {
      titleTypingTimer?.cancel();
    }
  }

  /// Directly enhances the Action Taken field with Gemini — no dialog,
  /// no language detection. Builds a context-aware prompt from the task's
  /// title and description so the model understands what is being addressed.
  Future<void> _processActionTakenWithGemini(
    BuildContext context,
    WidgetRef ref,
  ) async {
    final plainText = _actionController?.document.toPlainText().trim() ?? '';
    if (plainText.isEmpty) {
      if (!context.mounted) return;
      showWarningSnackBar(context, 'Please enter some action taken text first');
      return;
    }

    // Use task title/description as context for a richer prompt.
    final task = ref.read(taskByIdProvider(widget.taskId));
    final subject = task?.title.trim() ?? '';
    final description = task?.description.trim() ?? '';

    final hint = StringBuffer(
      'This is the action taken / workaround for an IT helpdesk ticket',
    );
    if (subject.isNotEmpty) hint.write(' about "$subject"');
    if (description.isNotEmpty) {
      hint.write('. Ticket description: "$description"');
    }
    hint.write(
      '. Fix spelling and grammar, improve clarity, and translate to '
      'professional English. Return ONLY the improved text, no explanations:',
    );

    if (mounted) {
      setState(() {
        _actionSaving = true;
        _actionProcessing = true;
      });
    }
    try {
      final aiService = AiService();
      final improvedText = await aiService.enhanceText(
        plainText,
        promptInstruction: hint.toString(),
      );

      final trimmed = improvedText.trim();
      // Build delta JSON directly — [{"insert": "text\n"}] — to avoid any
      // race between replaceText() and reading toDelta() immediately after.
      final deltaJson = jsonEncode([
        <String, dynamic>{'insert': '$trimmed\n'},
      ]);

      _actionDebounce?.cancel();
      await ref
          .read(tasksControllerProvider)
          .updateTask(taskId: widget.taskId, actionTaken: deltaJson);

      if (_actionController != null) {
        // Update the snapshot BEFORE replaceText so the listener sees no
        // content change and skips the redundant auto-save.
        _actionLastPlain = trimmed;
        final docLen = _actionController!.document.length;
        _actionController!.replaceText(
          0,
          docLen - 1,
          trimmed,
          TextSelection.collapsed(offset: trimmed.length),
        );
        // Cancel any debounce that may have slipped through.
        _actionDebounce?.cancel();
      }

      if (context.mounted) {
        showSuccessSnackBar(context, 'Action taken improved successfully');
      }
    } catch (e) {
      if (context.mounted) {
        showErrorSnackBar(context, 'Error: $e');
      }
    } finally {
      if (mounted) {
        setState(() {
          _actionSaving = false;
          _actionProcessing = false;
        });
      }
    }
  }

  bool _canAssignStaff(String role) {
    return role == 'admin' || role == 'dispatcher' || role == 'it_staff';
  }

  Widget _buildStatusChip(
    BuildContext context,
    Task task,
    bool canUpdateStatus,
    bool hasAssignedItStaff,
  ) {
    final chip = StatusPill(
      label: task.status.toUpperCase(),
      isEmphasized: task.status != 'queued',
    );

    final isTerminal =
        task.status == 'completed' ||
        task.status == 'cancelled' ||
        task.status == 'closed';

    if (!canUpdateStatus || isTerminal) {
      return chip;
    }

    // Show all status options - validation happens on selection
    final statusOptions = _statusOptions;

    return PopupMenuButton<String>(
      onSelected: (value) async {
        // If cancelling, require a reason — show dialog with spinner.
        if (value == 'cancelled') {
          final reasonCtrl = TextEditingController();
          await showDialog<void>(
            context: context,
            builder: (dialogContext) {
              var isSaving = false;
              return StatefulBuilder(
                builder: (ctx, setState) {
                  return AlertDialog(
                    shape: AppSurfaces.of(context).dialogShape,
                    title: const Text('Cancel task'),
                    contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 12),
                    content: SizedBox(
                      width: 360,
                      child: Padding(
                        padding: const EdgeInsets.symmetric(vertical: 12),
                        child: TextField(
                          controller: reasonCtrl,
                          maxLines: 3,
                          decoration: const InputDecoration(
                            labelText: 'Reason',
                            hintText: 'Provide a justification for cancelling',
                          ),
                        ),
                      ),
                    ),
                    actions: [
                      TextButton(
                        onPressed: isSaving
                            ? null
                            : () => Navigator.of(dialogContext).pop(),
                        child: const Text('Cancel'),
                      ),
                      FilledButton(
                        onPressed: isSaving
                            ? null
                            : () async {
                                final reason = reasonCtrl.text.trim();
                                if (reason.isEmpty) {
                                  showErrorSnackBar(
                                    context,
                                    'Cancellation requires a reason.',
                                  );
                                  return;
                                }
                                setState(() => isSaving = true);
                                try {
                                  await ref
                                      .read(tasksControllerProvider)
                                      .updateTaskStatus(
                                        taskId: task.id,
                                        status: 'cancelled',
                                        reason: reason,
                                      );
                                  if (context.mounted) {
                                    showSuccessSnackBar(
                                      context,
                                      'Task cancelled',
                                    );
                                    Navigator.of(dialogContext).pop();
                                  }
                                } catch (e) {
                                  if (context.mounted) {
                                    showErrorSnackBar(context, e.toString());
                                  }
                                } finally {
                                  if (context.mounted) {
                                    setState(() => isSaving = false);
                                  }
                                }
                              },
                        child: isSaving
                            ? SizedBox(
                                width: 16,
                                height: 16,
                                child: CircularProgressIndicator(
                                  strokeWidth: 2,
                                  valueColor: AlwaysStoppedAnimation(
                                    Theme.of(context).colorScheme.onPrimary,
                                  ),
                                ),
                              )
                            : const Text('Save'),
                      ),
                    ],
                  );
                },
              );
            },
          );
          return;
        }

        // Validate IT staff assignment before starting or completing
        if ((value == 'in_progress' || value == 'completed') &&
            !hasAssignedItStaff) {
          showWarningSnackBar(
            context,
            'Please assign at least one IT Staff member before ${value == 'in_progress' ? 'starting' : 'completing'} this task.',
          );
          return;
        }

        // Update DB only — Supabase realtime stream will emit the
        // updated task list, so explicit invalidation here causes a
        // visible loading/refresh and is unnecessary.
        try {
          await ref
              .read(tasksControllerProvider)
              .updateTaskStatus(taskId: task.id, status: value);
        } catch (e) {
          // surface validation or other errors to user
          if (mounted) {
            showErrorSnackBar(context, e.toString());
          }
        }
      },
      itemBuilder: (context) => statusOptions
          .map(
            (status) => PopupMenuItem(
              value: status,
              child: Text(_statusMenuLabel(status)),
            ),
          )
          .toList(),
      child: chip,
    );
  }

  String _statusMenuLabel(String status) {
    return switch (status) {
      'queued' => 'Queued',
      'in_progress' => 'In progress',
      'completed' => 'Completed',
      _ => status,
    };
  }

  bool _canUpdateStatus(
    Profile? profile,
    List<TaskAssignment> assignments,
    String taskId,
  ) {
    if (profile == null) {
      return false;
    }
    final isGlobal =
        profile.role == 'admin' ||
        profile.role == 'dispatcher' ||
        profile.role == 'it_staff';
    if (isGlobal) {
      return true;
    }
    return assignments.any(
      (assignment) =>
          assignment.taskId == taskId && assignment.userId == profile.id,
    );
  }

  Future<void> _uploadTaskAttachment(String taskId) async {
    try {
      final result = await FilePicker.platform.pickFiles(
        withData: true,
        allowMultiple: false,
      );

      if (result == null || result.files.isEmpty) {
        return;
      }

      final file = result.files.first;
      final bytes = file.bytes;
      final fileName = file.name;

      if (bytes == null) {
        if (mounted) {
          showErrorSnackBar(context, 'Failed to read file');
        }
        return;
      }

      // Check file size (max 25MB)
      const maxSizeBytes = 25 * 1024 * 1024;
      if (bytes.length > maxSizeBytes) {
        if (mounted) {
          showErrorSnackBar(context, 'File size exceeds 25MB limit');
        }
        return;
      }

      if (!mounted) return;

      // Show loading dialog
      showDialog(
        context: context,
        barrierDismissible: false,
        builder: (BuildContext dialogContext) {
          return PopScope(
            canPop: false,
            child: const AlertDialog(
              title: Text('Uploading...'),
              content: SizedBox(
                height: 50,
                child: Center(child: CircularProgressIndicator()),
              ),
            ),
          );
        },
      );

      String? errorMessage;
      bool uploadSuccess = false;

      try {
        debugPrint('Starting upload for file: $fileName');
        await ref
            .read(tasksControllerProvider)
            .uploadTaskAttachment(
              taskId: taskId,
              fileName: fileName,
              bytes: bytes,
            );
        uploadSuccess = true;
        debugPrint('Upload completed successfully');
      } catch (e) {
        debugPrint('Upload failed: $e');
        errorMessage = e.toString();
      }

      // Close loading dialog first, then show feedback
      if (mounted && Navigator.of(context).canPop()) {
        debugPrint('Closing loading dialog...');
        Navigator.of(context, rootNavigator: true).pop();
        debugPrint('Dialog closed');
      }

      // Small delay to ensure dialog is fully closed before showing snackbar
      await Future.delayed(const Duration(milliseconds: 100));

      if (!mounted) return;

      if (uploadSuccess) {
        debugPrint('Showing success message and reloading attachments');
        showSuccessSnackBar(context, 'File uploaded successfully');
        // Reload attachments list (non-blocking)
        _loadAttachments(taskId);
        debugPrint('Attachment reload triggered');
      } else {
        showErrorSnackBar(context, 'Upload failed: $errorMessage');
      }
    } catch (e) {
      if (mounted) {
        showErrorSnackBar(context, 'Error: $e');
      }
    }
  }

  Future<void> _loadAttachments(String taskId) async {
    if (!mounted) return;

    setState(() {
      _loadingAttachments = true;
    });

    try {
      final supabase = ref.read(supabaseClientProvider);
      final files = await supabase.storage
          .from('task_attachments')
          .list(path: taskId);

      if (mounted) {
        setState(() {
          _attachments = files.map((f) => f.name).toList();
          _loadingAttachments = false;
        });
        debugPrint('Attachments loaded: ${_attachments?.length ?? 0} files');
      }
    } catch (e) {
      debugPrint('Error getting attachments list: $e');
      if (mounted) {
        setState(() {
          _attachments = [];
          _loadingAttachments = false;
        });
      }
    }
  }

  Future<void> _downloadTaskAttachment(String taskId, String fileName) async {
    try {
      if (mounted) {
        showInfoSnackBar(context, 'Downloading: $fileName');
      }

      final supabase = ref.read(supabaseClientProvider);

      // Download file data from storage
      final Uint8List bytes;
      try {
        bytes = await supabase.storage
            .from('task_attachments')
            .download('$taskId/$fileName');
        debugPrint('Downloaded ${bytes.length} bytes for $fileName');
      } catch (e) {
        debugPrint('Storage download error: $e');
        if (mounted) {
          showErrorSnackBar(context, 'Failed to download: $e');
        }
        return;
      }

      if (!mounted) return;

      // Use FilePicker to save file (works on all platforms)
      String? savePath = await FilePicker.platform.saveFile(
        dialogTitle: 'Save attachment',
        fileName: fileName,
        bytes: bytes,
      );

      if (mounted) {
        if (savePath != null && savePath.isNotEmpty) {
          showSuccessSnackBar(context, 'File saved to: $savePath');
        } else {
          showInfoSnackBar(context, 'Download cancelled');
        }
      }
    } catch (e) {
      debugPrint('Download error: $e');
      if (mounted) {
        showErrorSnackBar(context, 'Download error: $e');
      }
    }
  }

  Future<void> _deleteTaskAttachment(String taskId, String fileName) async {
    try {
      final confirmed = await showDialog<bool>(
        context: context,
        builder: (ctx) => AlertDialog(
          title: const Text('Delete Attachment?'),
          content: Text('Remove "$fileName"?'),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(ctx).pop(false),
              child: const Text('Cancel'),
            ),
            FilledButton(
              onPressed: () => Navigator.of(ctx).pop(true),
              child: const Text('Delete'),
            ),
          ],
        ),
      );

      if (confirmed == true) {
        final supabase = ref.read(supabaseClientProvider);
        await supabase.storage.from('task_attachments').remove([
          '$taskId/$fileName',
        ]);

        if (mounted) {
          showSuccessSnackBar(context, 'Attachment deleted');
          // Reload attachments list
          await _loadAttachments(taskId);
        }
      }
    } catch (e) {
      if (mounted) {
        showErrorSnackBar(context, 'Failed to delete: $e');
      }
    }
  }

  // PDF preview/building moved to `task_pdf.dart`.
}

class _MetaBadge extends StatelessWidget {
  const _MetaBadge({required this.label, required this.value, this.isMono});

  final String label;
  final String value;
  final bool? isMono;

  @override
  Widget build(BuildContext context) {
    final border = Theme.of(context).colorScheme.outlineVariant;
    final background = Theme.of(context).colorScheme.surfaceContainerLow;
    final textStyle = Theme.of(context).textTheme.labelSmall;
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
      decoration: BoxDecoration(
        color: background,
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: border),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(label, style: textStyle),
          const SizedBox(width: 6),
          if (isMono == true)
            MonoText(value, style: textStyle)
          else
            Text(value, style: textStyle),
        ],
      ),
    );
  }
}

extension _FirstOrNull<T> on Iterable<T> {
  T? get firstOrNull => isEmpty ? null : first;
}
