import 'dart:async'; import 'package:pocketbase/pocketbase.dart'; import '../../../core/api/pocketbase_client.dart'; import '../../../core/services/job_history_service.dart'; import '../../../models/job.dart'; const _listExpand = 'clinic_tenant_id,lab_tenant_id'; const _detailExpand = 'clinic_tenant_id,lab_tenant_id,patient_id'; class LabJobsRepository { LabJobsRepository._(); static final instance = LabJobsRepository._(); PocketBase get _pb => PocketBaseClient.instance.pb; Future> listInbound( String labTenantId, { String? status, int page = 1, int limit = 30, }) async { final filterParts = ['lab_tenant_id = "$labTenantId"']; if (status != null) filterParts.add('status = "$status"'); final result = await _pb.collection('jobs').getList( page: page, perPage: limit, filter: filterParts.join(' && '), expand: _listExpand, ); return (result.items.map((r) => Job.fromJson(r.toJson())).toList() ..sort((a, b) => b.dateCreated.compareTo(a.dateCreated))); } Future> listInProgress(String labTenantId, {int limit = 50, String? location}) async { final filterParts = ['lab_tenant_id = "$labTenantId"', 'status = "in_progress"']; if (location != null) filterParts.add('location = "$location"'); final result = await _pb.collection('jobs').getList( perPage: limit, filter: filterParts.join(' && '), expand: _listExpand, ); return (result.items.map((r) => Job.fromJson(r.toJson())).toList() ..sort((a, b) { if (a.dueDate == null && b.dueDate == null) return b.dateCreated.compareTo(a.dateCreated); if (a.dueDate == null) return 1; if (b.dueDate == null) return -1; final cmp = a.dueDate!.compareTo(b.dueDate!); return cmp != 0 ? cmp : b.dateCreated.compareTo(a.dateCreated); })); } Future getJob(String jobId) async { final record = await _pb.collection('jobs').getOne(jobId, expand: _detailExpand); return Job.fromJson(record.toJson()); } Future acceptJob(Job pendingJob) async { final firstStep = pendingJob.stepTemplate.first; final record = await _pb.collection('jobs').update(pendingJob.id, body: { 'status': 'in_progress', 'current_step': firstStep.value, 'location': 'at_lab', }); final job = Job.fromJson(record.toJson()); unawaited(JobHistoryService.instance.append( jobId: pendingJob.id, clinicTenantId: job.clinicTenantId, labTenantId: job.labTenantId, action: JobHistoryAction.accepted, step: firstStep, )); return job; } Future handToClinic(String jobId, Job job, {String? note}) async { final isFinal = job.currentStep == JobStep.cilaBitim; final patch = isFinal ? {'status': 'sent', 'location': 'at_clinic'} : {'location': 'at_clinic'}; final record = await _pb.collection('jobs').update(jobId, body: patch); final updated = Job.fromJson(record.toJson()); unawaited(JobHistoryService.instance.append( jobId: jobId, clinicTenantId: job.clinicTenantId, labTenantId: job.labTenantId, action: JobHistoryAction.handedToClinic, step: job.currentStep, note: note, )); return updated; } Future cancelJob(String jobId, Job job) async { final record = await _pb.collection('jobs').update(jobId, body: { 'status': 'cancelled', }); unawaited(JobHistoryService.instance.append( jobId: jobId, clinicTenantId: job.clinicTenantId, labTenantId: job.labTenantId, action: JobHistoryAction.cancelled, step: job.currentStep, )); return Job.fromJson(record.toJson()); } Future bulkAcceptPending(String labTenantId) async { final pending = await listInbound(labTenantId, status: 'pending', limit: 200); await Future.wait(pending.map((j) => acceptJob(j))); } Future countByStatus(String labTenantId, String? status) async { final filter = status != null ? 'lab_tenant_id = "$labTenantId" && status = "$status"' : 'lab_tenant_id = "$labTenantId"'; final r = await _pb.collection('jobs').getList(perPage: 1, filter: filter); return r.totalItems; } Future countDelivered(String labTenantId, {DateTime? from, DateTime? to}) async { final parts = ['lab_tenant_id = "$labTenantId"', 'status = "delivered"']; if (from != null) parts.add('updated >= "${_date(from)}"'); if (to != null) parts.add('updated < "${_date(to)}"'); final r = await _pb.collection('jobs').getList(perPage: 1, filter: parts.join(' && ')); return r.totalItems; } static String _date(DateTime d) => d.toIso8601String().split('T').first; }