package bot import ( "sort" "worktimeBot/internal/db" ) type State int const ( StateIdle State = iota StateWorking StateOnBreak ) // DailyTotals holds aggregated times for a single day. type DailyTotals struct { TotalSeconds int64 BreakSeconds int64 PairCount int } // ComputeDailyTotals pairs events with break inference. // Multi‑out sequences: first out ends work, second out starts break, // next in ends break, next out ends work, etc. func ComputeDailyTotals(events []db.Event) DailyTotals { if len(events) == 0 { return DailyTotals{} } sorted := make([]db.Event, len(events)) copy(sorted, events) sort.Slice(sorted, func(i, j int) bool { return sorted[i].OccurredAt < sorted[j].OccurredAt }) var workTotal, breakTotal int64 var workStart, breakStart int64 pairs := 0 state := StateIdle for _, e := range sorted { switch { case e.EventType == "in": switch state { case StateIdle, StateOnBreak: if state == StateOnBreak { breakTotal += e.OccurredAt - breakStart breakStart = 0 } workStart = e.OccurredAt state = StateWorking // Working → ignore duplicate in (shouldn't happen) case StateWorking: // already working, ignore } case e.EventType == "out": switch state { case StateWorking: // End of work period workTotal += e.OccurredAt - workStart workStart = 0 pairs++ state = StateIdle case StateIdle: // Second consecutive out → break start breakStart = e.OccurredAt state = StateOnBreak case StateOnBreak: // Duplicate break start – ignore } } } return DailyTotals{ TotalSeconds: workTotal, BreakSeconds: breakTotal, PairCount: pairs, } }