HydroNutrify_Ari_e41221567/lib/data/services/planting_cycles_service.dart

141 lines
4.7 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:mobile_monitoring/core/utils/cycle_phase_utils.dart';
/// Service untuk mengelola siklus tanam dengan fase pertumbuhan otomatis
class PlantingCyclesService {
static const String collectionName = 'planting_cycles';
CollectionReference<Map<String, dynamic>> get _collection =>
FirebaseFirestore.instance.collection(collectionName);
/// Stream siklus tanam yang sedang aktif (per user dengan fallback)
Stream<Map<String, dynamic>?> getActiveCycleStream({required String userId}) {
return _collection.snapshots().map((snapshot) {
if (snapshot.docs.isEmpty) return null;
if (userId.isNotEmpty) {
final matches = snapshot.docs.where((d) => d.id == userId).toList();
if (matches.isNotEmpty && matches.first.data().isNotEmpty) {
return {...matches.first.data(), 'doc_id': matches.first.id};
}
}
// Fallback ke dokumen siklus tanam pertama di database
final firstDoc = snapshot.docs.first;
return {...firstDoc.data(), 'doc_id': firstDoc.id};
}).handleError((error) {
debugPrint('[PlantingCyclesService] Stream error: $error');
return null;
});
}
/// Tambah siklus tanam baru (gunakan userId sebagai doc ID)
Future<String> addCycle({
required String userId,
required DateTime startDate,
}) async {
if (userId.isEmpty) throw Exception('User tidak terautentikasi');
await _collection.doc(userId).set({
'user_id': userId,
'start_date': Timestamp.fromDate(startDate),
'days_since_planting': 0,
'growth_phase': 'Semai',
'created_at': FieldValue.serverTimestamp(),
'updated_at': FieldValue.serverTimestamp(),
});
return userId;
}
/// Update hari dan fase tanam berdasarkan start_date
Future<void> updateCycleProgress({
required String userId,
required DateTime startDate,
}) async {
final now = DateTime.now();
final daysSincePlanting = now.difference(startDate).inDays;
final growthPhase = CyclePhaseUtils.calculateCyclePhase(daysSincePlanting);
await _collection.doc(userId).set({
'days_since_planting': daysSincePlanting,
'growth_phase': growthPhase,
'updated_at': FieldValue.serverTimestamp(),
}, SetOptions(merge: true));
}
/// Hitung hari total siklus untuk panen
Future<int> calculateCycleDaysBeforeDelete({required String userId}) async {
if (userId.isEmpty) throw Exception('User tidak terautentikasi');
final doc = await _collection.doc(userId).get();
if (!doc.exists || doc.data() == null) {
throw Exception('Siklus tanam aktif tidak ditemukan');
}
final data = doc.data()!;
final startValue = data['start_date'];
DateTime? startDate;
if (startValue is Timestamp) {
startDate = startValue.toDate();
} else if (startValue is DateTime) {
startDate = startValue;
}
final daysSincePlanting = startDate == null
? (data['days_since_planting'] as num?)?.toInt() ?? 0
: DateTime.now().difference(startDate).inDays;
return daysSincePlanting;
}
/// Hapus siklus tanam (gunakan userId)
Future<void> deleteCycle({required String userId}) async {
await _collection.doc(userId).delete();
}
/// Get detail siklus berdasarkan userId dengan update otomatis
Future<Map<String, dynamic>?> getCycleByUserId({
required String userId,
}) async {
final doc = await _collection.doc(userId).get();
if (!doc.exists || doc.data() == null) return null;
final data = doc.data()!;
final startDate = (data['start_date'] as Timestamp).toDate();
// Update progress sebelum return
await updateCycleProgress(userId: userId, startDate: startDate);
// Get data terbaru
final updatedDoc = await _collection.doc(userId).get();
if (!updatedDoc.exists) return null;
return {...updatedDoc.data()!, 'doc_id': updatedDoc.id};
}
/// Get siklus aktif dengan info fase terkini
Future<Map<String, dynamic>?> getActiveCycle({required String userId}) async {
if (userId.isEmpty) throw Exception('User tidak terautentikasi');
final doc = await _collection.doc(userId).get();
if (!doc.exists || doc.data() == null) return null;
final data = doc.data()!;
final startDate = (data['start_date'] as Timestamp).toDate();
// Hitung days_since_planting dan growth_phase terkini
final now = DateTime.now();
final daysSincePlanting = now.difference(startDate).inDays;
final growthPhase = CyclePhaseUtils.calculateCyclePhase(daysSincePlanting);
return {
...data,
'doc_id': doc.id,
'days_since_planting': daysSincePlanting,
'growth_phase': growthPhase,
};
}
}