const { query, toISODate, parseISODate } = require('../database/db'); class Cycle { static async getAll() { try { const result = await query('SELECT * FROM cycles ORDER BY start_date DESC', []); return result.rows.map(this.formatCycle); } catch (error) { console.error('Error getting all cycles:', error); throw error; } } static async getById(id) { try { const result = await query('SELECT * FROM cycles WHERE id = $1', [id]); if (result.rows.length === 0) return null; return this.formatCycle(result.rows[0]); } catch (error) { console.error('Error getting cycle by ID:', error); throw error; } } static async create(cycleData) { try { const { id, totalDays, currentDay, startDate, endDate, chickInWeight, docInCount, status } = cycleData; await query('INSERT INTO cycles (id, total_days, current_day, start_date, end_date, chick_in_weight, doc_in_count, status) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)', [id, totalDays, currentDay, toISODate(startDate), toISODate(endDate), chickInWeight || null, docInCount || null, status]); return this.getById(id); } catch (error) { console.error('Error creating cycle:', error); throw error; } } static async update(id, cycleData) { try { const { totalDays, currentDay, startDate, endDate, chickInWeight, docInCount, status } = cycleData; const result = await query('UPDATE cycles SET total_days = $1, current_day = $2, start_date = $3, end_date = $4, chick_in_weight = $5, doc_in_count = $6, status = $7, updated_at = CURRENT_TIMESTAMP WHERE id = $8', [totalDays, currentDay, toISODate(startDate), toISODate(endDate), chickInWeight || null, docInCount || null, status, id]); if (result.rowCount === 0) return null; return this.getById(id); } catch (error) { console.error('Error updating cycle:', error); throw error; } } static async delete(id) { try { const result = await query('DELETE FROM cycles WHERE id = $1', [id]); return result.rowCount > 0; } catch (error) { console.error('Error deleting cycle:', error); throw error; } } static async getActive() { try { const result = await query("SELECT * FROM cycles WHERE status = 'Active' LIMIT 1", []); if (result.rows.length === 0) return null; return this.formatCycle(result.rows[0]); } catch (error) { console.error('Error getting active cycle:', error); throw error; } } static async markAllActiveAsCompleted() { try { const result = await query( "UPDATE cycles SET status = 'Completed', updated_at = CURRENT_TIMESTAMP WHERE status = 'Active'", [] ); return result; } catch (error) { console.error('Error marking active cycles as completed:', error); throw error; } } static formatCycle(cycle) { // Calculate current day dynamically based on start_date let calculatedCurrentDay = cycle.current_day; if (cycle.status === 'Active' && cycle.start_date) { const startDate = new Date(cycle.start_date); const today = new Date(); // Reset time to midnight for accurate day calculation startDate.setHours(0, 0, 0, 0); today.setHours(0, 0, 0, 0); // Calculate days difference const diffMs = today - startDate; const daysDiff = Math.floor(diffMs / (1000 * 60 * 60 * 24)); // 0-based day index: day 0 = startDate, last day = startDate + (totalDays - 1) // Cap at totalDays - 1 so currentDay never maps past Estimasi Panen / end_date const lastDayIndex = Math.max(0, cycle.total_days - 1); calculatedCurrentDay = Math.min(daysDiff, lastDayIndex); } return { id: cycle.id, totalDays: cycle.total_days, currentDay: calculatedCurrentDay, // Use dynamically calculated day for active cycles startDate: cycle.start_date, endDate: cycle.end_date, chickInWeight: cycle.chick_in_weight, docInCount: cycle.doc_in_count, status: cycle.status, createdAt: cycle.created_at, updatedAt: cycle.updated_at }; } } module.exports = Cycle;