import 'dart:typed_data'; import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/features/attachments/blocs/attachments_bloc.dart'; import 'package:flux/features/attachments/data/attachments_repository.dart'; import 'package:flux/features/tickets/models/shipping_document_model.dart'; import 'package:flux/features/master_data/providers/models/provider_model.dart'; import 'package:flux/features/master_data/providers/models/provider_role.dart'; import 'package:get_it/get_it.dart'; import 'package:supabase_flutter/supabase_flutter.dart' hide Bucket; class TicketsShippingRepository { final _supabase = GetIt.I.get(); final _companyId = GetIt.I.get().state.company!.id!; Future> fetchRepairCenters() async { try { final response = await _supabase .from('provider') .select('*, provider_locations (*)') .eq('is_active', true) .order('name'); final allProviders = (response as List) .map((row) => ProviderModel.fromMap(row as Map)) .toList(); // Filtriamo lato client per prendere SOLO i repairCenter return allProviders .where((p) => p.roles.contains(ProviderRole.repairCenter)) .toList(); } catch (e) { throw ('Errore caricamento laboratori: $e'); } } Future> fetchShipmentDocumentsForTicket( String ticketId, ) async { try { final response = await _supabase .from('shipping_documents') .select('*, attachments (*)') .contains('ticket_ids', [ticketId]); return (response as List) .map( (row) => ShippingDocumentModel.fromMap(row as Map), ) .toList(); } catch (e) { throw ('Errore caricamento documenti di trasporto: $e'); } } Future> fetchCompanyShipmentDocuments() async { try { final response = await _supabase .from('shipping_documents') .select('*, attachments (*)') .eq('company_id', _companyId); return (response as List) .map( (row) => ShippingDocumentModel.fromMap(row as Map), ) .toList(); } catch (e) { throw ('Errore caricamento documenti di trasporto aziendali: $e'); } } Future fetchShipmentDocumentById( String documentId, ) async { try { final response = await _supabase .from('shipping_documents') .select('*, attachments (*)') .eq('id', documentId) .single(); return ShippingDocumentModel.fromMap(response); } catch (e) { throw ('Errore caricamento documento di trasporto: $e'); } } /// Salva il DDT nel DB, carica il PDF nello Storage e lo registra come Attachment ufficiale Future createShipmentWithPdf({ required ShippingDocumentModel document, required Uint8List pdfBytes, required String newTicketStatus, }) async { try { final attachmentsRepo = GetIt.I.get(); // 1. Inseriamo prima il Documento di Trasporto (DDT) su Postgres // Il modello iniziale non ha ancora gli allegati popolati, quindi passiamo il toMap standard final savedDocument = await _supabase .from('shipping_documents') .insert(document.toMap()) .select('id') .single(); final documentId = savedDocument['id'] as String; // 2. Prepariamo il nome del file PDF (es: DDT_123_2026.pdf) final fileName = 'DDT_${document.docNumber.replaceAll('/', '_').replaceAll(' ', '_')}.pdf'; // 3. IL TOCCO MASTER: Delegiamo l'upload e la registrazione nel DB all'AttachmentsRepository // Questo creerà la riga nella tabella degli allegati agganciando lo 'shipping_document_id' await attachmentsRepo.uploadAndRegisterFile( parentId: documentId, parentType: AttachmentParentType.shippingDocument, // Il tuo nuovo enum! companyId: document.companyId, bucket: Bucket.companyDocuments, rawBytes: pdfBytes, rawFileName: fileName, ); // 4. Aggiorniamo lo stato di TUTTI i ticket inclusi nel DDT e li colleghiamo all'ID del DDT await _supabase .from('ticket') .update({ 'ticket_status': newTicketStatus, 'shipment_document_id': documentId, }) .inFilter('id', document.ticketIds); } catch (e) { throw ('Errore durante il salvataggio e upload della spedizione con allegato: $e'); } } }