import 'package:equatable/equatable.dart'; import 'package:flux/core/utils/extensions.dart'; import 'package:flux/features/master_data/staff/models/staff_member_model.dart'; import 'package:flux/features/tasks/models/task_status.dart'; class TaskModel extends Equatable { final String? id; final String? companyId; final String title; final String? description; final List assignedToIds; final List assignedToStaff; // I dati completi dal JOIN final StaffMemberModel? createdBy; final DateTime? dueDate; final TaskStatus status; final DateTime? createdAt; final String? storeId; final StaffMemberModel? updatedBy; const TaskModel({ this.id, this.companyId, required this.title, this.description, this.assignedToIds = const [], this.assignedToStaff = const [], this.createdBy, this.dueDate, this.status = TaskStatus.open, this.createdAt, this.storeId, this.updatedBy, }); bool get isGlobal => storeId == null; // --- FACTORY: MODELLO VUOTO (Per le creazioni) --- factory TaskModel.empty({String? companyId, StaffMemberModel? createdBy}) { return TaskModel( companyId: companyId, title: '', description: '', assignedToIds: const [], assignedToStaff: const [], createdBy: createdBy, status: TaskStatus.open, createdAt: DateTime.now(), ); } // --- EQUATABLE: PROPRIETÀ DA COMPARARE --- @override List get props => [ id, companyId, title, description, assignedToIds, assignedToStaff, createdBy, dueDate, status, createdAt, storeId, updatedBy, ]; // --- COPY WITH --- TaskModel copyWith({ String? id, String? companyId, String? title, String? description, List? assignedToIds, List? assignedToStaff, StaffMemberModel? createdBy, DateTime? dueDate, bool clearDueDate = false, // Flag ninja per resettare la scadenza TaskStatus? status, DateTime? createdAt, String? storeId, bool clearStoreId = false, StaffMemberModel? updatedBy, String? updatedByDisplayName, }) { return TaskModel( id: id ?? this.id, companyId: companyId ?? this.companyId, title: title ?? this.title, description: description ?? this.description, assignedToIds: assignedToIds ?? this.assignedToIds, assignedToStaff: assignedToStaff ?? this.assignedToStaff, createdBy: createdBy ?? this.createdBy, dueDate: clearDueDate ? null : (dueDate ?? this.dueDate), status: status ?? this.status, createdAt: createdAt ?? this.createdAt, storeId: clearStoreId ? null : (storeId ?? this.storeId), updatedBy: updatedBy ?? this.updatedBy, ); } // --- SERIALIZZAZIONE DA SUPABASE --- factory TaskModel.fromMap(Map map) { // 1. Gestiamo l'array nullo di Supabase trasformandolo in lista vuota final List parsedAssignedToIds = map['assigned_to_ids'] != null ? List.from(map['assigned_to_ids']) : []; // 2. Mappiamo il JOIN dello staff, se presente List staffList = []; // Gestione del JSON proveniente dal Join nidificato (es. task_assignments -> staff_members) if (map['task_assignments'] != null) { staffList = (map['task_assignments'] as List) .map((a) => a['staff_members']) .where((s) => s != null) .map((s) => StaffMemberModel.fromMap(s)) .toList(); } // Gestione del JSON piatto (se mai lo userai in altre chiamate RPC o viste) else if (map['assigned_to_staff'] != null) { staffList = (map['assigned_to_staff'] as List) .map((s) => StaffMemberModel.fromMap(s)) .toList(); } return TaskModel( id: map['id'] as String?, companyId: map['company_id'] as String?, title: map['title'] as String? ?? '', description: map['description'] as String?, assignedToIds: parsedAssignedToIds, assignedToStaff: staffList, createdBy: map['created_by_id'] != null ? StaffMemberModel.fromMap(map['creator']) : null, dueDate: map['due_date'] != null ? DateTime.parse(map['due_date'] as String).toLocal() : null, status: TaskStatusExtension.fromString(map['status'] as String?), createdAt: map['created_at'] != null ? DateTime.parse(map['created_at'] as String).toLocal() : null, storeId: map['store_id'] as String?, updatedBy: map['updated_by_id'] != null ? StaffMemberModel.fromMap(map['updater']) : null, ); } // --- SERIALIZZAZIONE VERSO SUPABASE --- Map toMap() { return { if (id != null) 'id': id, if (companyId != null) 'company_id': companyId, 'title': title, if (description != null) 'description': description, // Passiamo l'array vuoto se non ci sono assegnazioni 'assigned_to_ids': assignedToIds.isEmpty ? null : assignedToIds, if (createdBy != null) 'created_by_id': createdBy!.id, 'due_date': dueDate?.toUtc().toIso8601String(), 'status': status.toValue, 'store_id': storeId, if (updatedBy != null) 'updated_by_id': updatedBy!.id, }; } }