import 'dart:convert';

import '../utils/app_time.dart';

class Task {
  Task({
    required this.id,
    required this.ticketId,
    required this.taskNumber,
    required this.title,
    required this.description,
    required this.officeId,
    required this.status,
    required this.priority,
    required this.queueOrder,
    required this.createdAt,
    required this.creatorId,
    required this.startedAt,
    required this.completedAt,
    // new optional metadata fields
    this.requestedBy,
    this.notedBy,
    this.receivedBy,
    this.requestType,
    this.requestTypeOther,
    this.requestCategory,
    this.actionTaken,
    this.cancellationReason,
    this.cancelledAt,
  });

  final String id;
  final String? ticketId;
  final String? taskNumber;
  final String title;
  final String description;
  final String? officeId;
  final String status;
  final int priority;
  final int? queueOrder;
  final DateTime createdAt;
  final String? creatorId;
  final DateTime? startedAt;
  final DateTime? completedAt;

  // Optional client/user metadata
  final String? requestedBy;
  final String? notedBy;
  final String? receivedBy;

  /// Optional request metadata added later in lifecycle.
  final String? requestType;
  final String? requestTypeOther;
  final String? requestCategory;
  // JSON serialized rich text for action taken (Quill Delta JSON encoded)
  final String? actionTaken;

  /// Cancellation details when a task was cancelled.
  final String? cancellationReason;
  final DateTime? cancelledAt;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Task &&
          runtimeType == other.runtimeType &&
          id == other.id &&
          ticketId == other.ticketId &&
          taskNumber == other.taskNumber &&
          title == other.title &&
          description == other.description &&
          officeId == other.officeId &&
          status == other.status &&
          priority == other.priority &&
          queueOrder == other.queueOrder &&
          createdAt == other.createdAt &&
          creatorId == other.creatorId &&
          startedAt == other.startedAt &&
          completedAt == other.completedAt &&
          requestedBy == other.requestedBy &&
          notedBy == other.notedBy &&
          receivedBy == other.receivedBy &&
          requestType == other.requestType &&
          requestTypeOther == other.requestTypeOther &&
          requestCategory == other.requestCategory &&
          actionTaken == other.actionTaken &&
          cancellationReason == other.cancellationReason &&
          cancelledAt == other.cancelledAt;

  @override
  int get hashCode => Object.hash(
    id,
    ticketId,
    taskNumber,
    title,
    description,
    officeId,
    status,
    priority,
    queueOrder,
    createdAt,
    creatorId,
    startedAt,
    completedAt,
    requestedBy,
    notedBy,
    receivedBy,
    requestType,
    requestTypeOther,
    requestCategory,
    // Object.hash supports max 20 positional args; combine remainder.
    Object.hash(actionTaken, cancellationReason, cancelledAt),
  );

  /// Helper that indicates whether a completed task still has missing
  /// metadata such as signatories or action details.  The parameter is used
  /// by UI to surface a warning icon/banner when a task has been closed but
  /// the user skipped filling out all fields.
  bool get hasIncompleteDetails {
    if (status != 'completed') return false;
    bool empty(String? v) => v == null || v.trim().isEmpty;
    return empty(requestedBy) ||
        empty(notedBy) ||
        empty(receivedBy) ||
        empty(actionTaken);
  }

  factory Task.fromMap(Map<String, dynamic> map) {
    return Task(
      id: map['id'] as String,
      ticketId: map['ticket_id'] as String?,
      taskNumber: map['task_number'] as String?,
      title: map['title'] as String? ?? 'Task',
      description: map['description'] as String? ?? '',
      officeId: map['office_id'] as String?,
      status: map['status'] as String? ?? 'queued',
      priority: map['priority'] as int? ?? 1,
      queueOrder: map['queue_order'] as int?,
      createdAt: AppTime.parse(map['created_at'] as String),
      creatorId: map['creator_id'] as String?,
      startedAt: map['started_at'] == null
          ? null
          : AppTime.parse(map['started_at'] as String),
      completedAt: map['completed_at'] == null
          ? null
          : AppTime.parse(map['completed_at'] as String),
      requestType: map['request_type'] as String?,
      requestTypeOther: map['request_type_other'] as String?,
      requestCategory: map['request_category'] as String?,
      requestedBy: map['requested_by'] as String?,
      notedBy: map['noted_by'] as String?,
      receivedBy: map['received_by'] as String?,
      cancellationReason: map['cancellation_reason'] as String?,
      cancelledAt: map['cancelled_at'] == null
          ? null
          : AppTime.parse(map['cancelled_at'] as String),
      actionTaken: (() {
        final at = map['action_taken'];
        if (at == null) return null;
        if (at is String) return at;
        try {
          return jsonEncode(at);
        } catch (_) {
          return at.toString();
        }
      })(),
    );
  }
}
