+// whatsappImportHistory reads batch names and live cutoffs from both logs.
+// Imported chat-days belong only to the target log, which is first.
+func whatsappImportHistory(target, root []DatedMessage, names map[string]WhatsAppChat, cutoffs map[string]time.Time, location *time.Location) (map[string]bool, error) {
+ imported := make(map[string]bool)
+ for source, entries := range [][]DatedMessage{target, root} {
+ for _, entry := range entries {
+ if entry.Kind != "work" || !strings.HasPrefix(entry.Text, "[WhatsApp] ") {
+ continue
+ }
+
+ first, _, _ := strings.Cut(entry.Text, "\n")
+ marked := strings.HasSuffix(first, whatsappImportMark)
+ first = strings.TrimSuffix(first, whatsappImportMark)
+ match := whatsappImportHeader.FindStringSubmatch(first)
+ name, day := "", ""
+ if len(match) > 0 {
+ name, day = match[1], match[3]
+ whatsappImportName(names, WhatsAppChat{
+ ID: match[2],
+ Name: name,
+ Group: strings.Contains(first, ", group "+match[2]+","),
+ })
+ } else if marked {
+ match = whatsappImportUnknown.FindStringSubmatch(first)
+ if len(match) > 0 {
+ name, day = match[1], match[2]
+ }
+ }
+
+ if name == "" {
+ return nil, errors.New("invalid WhatsApp batch header")
+ }
+
+ if marked {
+ if source == 0 {
+ imported[name+"\n"+day] = true
+ }
+
+ continue
+ }
+
+ _, body, found := strings.Cut(entry.Text, "\n")
+ if !found || len(body) < len("15:04 ") {
+ return nil, errors.New("missing first WhatsApp message time")
+ }
+
+ date, err := time.ParseInLocation("2006-01-02 15:04", day+" "+body[:5], location)
+ if err != nil {
+ return nil, fmt.Errorf("parse first live message time: %w", err)
+ }
+
+ if cutoffs[name].IsZero() || date.Before(cutoffs[name]) {
+ cutoffs[name] = date
+ }
+ }
+ }
+
+ return imported, nil
+}
+