import 'package:flux/features/tasks/models/task_status.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; // Sostituisci con i percorsi corretti di FLUX import 'package:flux/features/tasks/models/task_model.dart'; class TaskRepository { final SupabaseClient _supabase; TaskRepository({SupabaseClient? supabase}) : _supabase = supabase ?? Supabase.instance.client; // --- RECUPERO DEI TASK FILTRATI --- Future> getTasks({ required String companyId, String? storeId, String? staffId, List? statuses, int? limit, }) async { try { // 1. FASE FILTRI (PostgrestFilterBuilder) var filterBuilder = _supabase .from('tasks') .select('*, assigned_to_staff:staff_members!task_assignments(*)') .eq('company_id', companyId); if (storeId != null) { filterBuilder = filterBuilder.or( 'store_id.eq.$storeId,store_id.is.null', ); } if (staffId != null) { filterBuilder = filterBuilder.or( 'staff_id.eq.$staffId,staff_id.is.null', ); } if (statuses != null && statuses.isNotEmpty) { final statusValues = statuses.map((s) => s.toValue).toList(); filterBuilder = filterBuilder.inFilter('status', statusValues); } // 2. FASE TRASFORMAZIONI (PostgrestTransformBuilder) // L'ordinamento lo facciamo sempre, quindi partiamo da qui var transformBuilder = filterBuilder .order('due_date', ascending: true, nullsFirst: false) .order('created_at', ascending: false, nullsFirst: false); // Aggiungiamo il limite se richiesto if (limit != null) { transformBuilder = transformBuilder.limit(limit); } // 3. ESECUZIONE DELLA QUERY final response = await transformBuilder; return (response as List).map((json) => TaskModel.fromMap(json)).toList(); } catch (e) { throw Exception('Errore nel recupero dei task: $e'); } } // --- 2. CREAZIONE DEL TASK --- Future createTask(TaskModel task) async { try { final taskData = task.toMap(); // Rimuoviamo l'array prima di inviare i dati alla tabella principale, // la "Strada C" impone che la verità assoluta derivi dalla tabella di giunzione! taskData.remove('assigned_to_ids'); // 1. Inseriamo il record base nella tabella tasks final response = await _supabase .from('tasks') .insert(taskData) .select() .single(); final newTask = TaskModel.fromMap(response); // 2. Se l'utente ha assegnato il task a qualcuno, popoliamo la giunzione if (task.assignedToIds.isNotEmpty && newTask.id != null) { await _syncAssignments(newTask.id!, task.assignedToIds); // 3. Ricarichiamo il task appena creato per ottenere l'array e il JOIN aggiornati dal trigger! return await getTaskById(newTask.id!); } return newTask; } catch (e) { throw Exception('Errore nella creazione del task: $e'); } } // --- 3. AGGIORNAMENTO DEL TASK --- Future updateTask(TaskModel task) async { if (task.id == null) throw Exception('ID Task mancante. Impossibile aggiornare.'); try { final taskData = task.toMap(); taskData.remove( 'assigned_to_ids', ); // Sempre via l'array dal body principale // 1. Aggiorniamo i dati base del task (titolo, stato, scadenza, ecc.) await _supabase.from('tasks').update(taskData).eq('id', task.id!); // 2. Sincronizziamo in modo distruttivo gli assegnatari nella tabella di giunzione await _syncAssignments(task.id!, task.assignedToIds); // 3. Ritorniamo il modello fresco di DB return await getTaskById(task.id!); } catch (e) { throw Exception('Errore nell\'aggiornamento del task: $e'); } } // --- 4. ELIMINAZIONE DEL TASK --- Future deleteTask(String taskId) async { try { // Eliminando il task, se la Foreign Key su Supabase ha "ON DELETE CASCADE", // le righe nella tabella di giunzione si distruggeranno da sole in automatico! await _supabase.from('tasks').delete().eq('id', taskId); } catch (e) { throw Exception('Errore nell\'eliminazione del task: $e'); } } // --- HELPER: RECUPERO SINGOLO TASK --- Future getTaskById(String taskId) async { try { final response = await _supabase .from('tasks') .select('*, assigned_to_staff:staff!task_assignments(*)') .eq('id', taskId) .single(); return TaskModel.fromMap(response); } catch (e) { throw Exception('Errore nel recupero del singolo task: $e'); } } // --- HELPER: SINCRONIZZAZIONE DELLA TABELLA DI GIUNZIONE --- Future _syncAssignments(String taskId, List staffIds) async { // TECNICA "WIPE & REPLACE": // Invece di capire chi è stato aggiunto e chi tolto, eliminiamo tutti i record // di questo task e li reinseriamo. È fulmineo ed esclude a priori bug di disallineamento. // 1. Facciamo piazza pulita await _supabase.from('task_assignments').delete().eq('task_id', taskId); // 2. Inseriamo le nuove assegnazioni (se ce ne sono) if (staffIds.isNotEmpty) { final List> assignments = staffIds .map((staffId) => {'task_id': taskId, 'staff_id': staffId}) .toList(); await _supabase.from('task_assignments').insert(assignments); } } }