const worklogRepository = require('../repositories/WorklogRepository');
const userRepository = require('../repositories/UserRepository');
const database = require('../config/database');

/**
 * Service-Klasse für Zeiteinträge
 * Enthält die gesamte Business-Logik
 * Verwendet das Repository-Pattern für Datenbankzugriff
 */
class TimeEntryService {
  constructor() {
    // Default-Benutzer-ID (kann später durch Auth ersetzt werden)
    this.defaultUserId = 1;
  }

  /**
   * Benutzer-ID setzen (für zukünftige Auth-Integration)
   * @param {number} userId - ID des aktuellen Benutzers
   */
  setCurrentUser(userId) {
    this.defaultUserId = userId;
  }

  /**
   * Alle Zeiteinträge abrufen
   * @param {number} userId - Benutzer-ID (optional)
   * @returns {Promise<Array>} Liste der Zeiteinträge
   */
  async getAllEntries(userId = null) {
    const uid = userId || this.defaultUserId;
    const pairs = await worklogRepository.findPairsByUser(uid);
    const safePairs = Array.isArray(pairs) ? pairs : [];
    
    return safePairs.map(pair => this._mapWorklogPairToTimeEntry(pair));
  }

  /**
   * Einzelnen Zeiteintrag anhand der ID abrufen
   * @param {number} id - Die ID des Zeiteintrags (start_id)
   * @returns {Promise<Object|null>} Der gefundene Zeiteintrag oder null
   */
  async getEntryById(id) {
    const worklog = await worklogRepository.findById(id);
    if (!worklog) return null;

    // Wenn es ein Start-Eintrag ist, zugehörigen End-Eintrag suchen
    if (worklog.relatedTo_id === null) {
      const pairs = await worklogRepository.findPairsByUser(worklog.user_id);
      const safePairs = Array.isArray(pairs) ? pairs : [];
      const pair = safePairs.find(p => p.start_id === parseInt(id));
      
      if (pair) {
        return this._mapWorklogPairToTimeEntry(pair);
      }
    }

    return null;
  }

  /**
   * Neuen Zeiteintrag erstellen (Timer starten)
   * @param {Object} entryData - Daten für den neuen Eintrag
   * @param {string} entryData.description - Beschreibung der Tätigkeit
   * @param {string} entryData.project - Projektname
   * @param {number} entryData.userId - Benutzer-ID (optional)
   * @returns {Promise<Object>} Der erstellte Zeiteintrag
   * @throws {Error} Bei ungültigen Eingabedaten
   */
  async createEntry(entryData) {
    const userId = entryData.userId || this.defaultUserId;
    const { description = '', project = 'Allgemein' } = entryData;

    // Validierung: Prüfen ob bereits ein Timer läuft
    const runningEntry = await worklogRepository.findRunningByUser(userId);
    if (runningEntry) {
      throw new Error('Es läuft bereits ein Timer. Bitte stoppen Sie diesen zuerst.');
    }

    // State-String mit zusätzlichen Informationen
    const state = JSON.stringify({
      action: 'Clock In',
      project,
      description
    });

    // Worklog-Eintrag erstellen
    const worklog = await worklogRepository.create({
      user_id: userId,
      state,
      tstamp: new Date(),
      relatedTo_id: null
    });

    // Als TimeEntry-Format zurückgeben
    return {
      id: worklog.id,
      startTime: worklog.tstamp,
      endTime: null,
      description,
      project,
      duration: null,
      isRunning: true,
      userId: worklog.user_id
    };
  }

  /**
   * Zeiteintrag aktualisieren (Timer stoppen oder Daten ändern)
   * @param {number} id - Die ID des zu aktualisierenden Eintrags
   * @param {Object} updateData - Zu aktualisierende Daten
   * @param {string} updateData.endTime - Endzeit (ISO 8601)
   * @param {string} updateData.description - Neue Beschreibung
   * @param {string} updateData.project - Neuer Projektname
   * @returns {Promise<Object>} Der aktualisierte Zeiteintrag
   * @throws {Error} Wenn der Eintrag nicht gefunden wurde
   */
  async updateEntry(id, updateData) {
    const startWorklog = await worklogRepository.findById(id);
    
    if (!startWorklog) {
      throw new Error(`Eintrag mit ID ${id} nicht gefunden`);
    }

    // State-Daten extrahieren
    let stateData;
    try {
      stateData = JSON.parse(startWorklog.state);
    } catch {
      stateData = { action: 'Clock In', project: 'Allgemein', description: '' };
    }

    const { endTime, description, project } = updateData;

    // Timer stoppen
    if (endTime) {
      const endTimestamp = new Date(endTime);
      const startTimestamp = new Date(startWorklog.tstamp);

      // Validierung: Endzeit muss nach Startzeit liegen
      if (endTimestamp <= startTimestamp) {
        throw new Error('Endzeit muss nach Startzeit liegen');
      }

      // End-State erstellen
      const endState = JSON.stringify({
        action: 'Clock Out',
        project: project || stateData.project,
        description: description !== undefined ? description : stateData.description
      });

      // Clock-Out Worklog erstellen
      await worklogRepository.create({
        user_id: startWorklog.user_id,
        state: endState,
        tstamp: endTimestamp,
        relatedTo_id: id
      });

      // Aktualisiertes Paar abrufen
      const pairs = await worklogRepository.findPairsByUser(startWorklog.user_id);
      const safePairs = Array.isArray(pairs) ? pairs : [];
      const pair = safePairs.find(p => p.start_id === parseInt(id));
      
      return this._mapWorklogPairToTimeEntry(pair);
    }

    // Nur Beschreibung/Projekt aktualisieren (ohne Timer zu stoppen)
    if (description !== undefined || project !== undefined) {
      const updatedState = JSON.stringify({
        ...stateData,
        project: project !== undefined ? project : stateData.project,
        description: description !== undefined ? description : stateData.description
      });

      await worklogRepository.update(id, { state: updatedState });
      return await this.getEntryById(id);
    }

    return await this.getEntryById(id);
  }

  /**
   * Zeiteintrag löschen
   * @param {number} id - Die ID des zu löschenden Eintrags
   * @returns {Promise<boolean>} true wenn erfolgreich gelöscht
   * @throws {Error} Wenn der Eintrag nicht gefunden wurde
   */
  async deleteEntry(id) {
    const startWorklog = await worklogRepository.findById(id);
    
    if (!startWorklog) {
      throw new Error(`Eintrag mit ID ${id} nicht gefunden`);
    }

    // Zugehörigen End-Eintrag finden und löschen
    const pairs = await worklogRepository.findPairsByUser(startWorklog.user_id);
    const pair = pairs.find(p => p.start_id === parseInt(id));
    
    if (pair && pair.end_id) {
      await worklogRepository.delete(pair.end_id);
    }

    // Start-Eintrag löschen
    return await worklogRepository.delete(id);
  }

  /**
   * Statistiken über alle Zeiteinträge abrufen
   * @param {number} userId - Benutzer-ID (optional)
   * @returns {Promise<Object>} Statistik-Objekt mit verschiedenen Metriken
   */
  async getStatistics(userId = null) {
    const uid = userId || this.defaultUserId;
    
    // Hole User-Daten (für daily_hours Fallback)
    const { User } = database.getModels();
    const user = await User.findByPk(uid, { attributes: ['daily_hours'], raw: true });
    const userDailyHours = user?.daily_hours || 8;
    
    let currentlyWorked = null;
    let allEntries = [];
    
    // Hole laufenden Eintrag
    const runningEntry = await this.getRunningEntry(uid);
    
    const now = new Date();
    const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
    const todayEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
    
    if (runningEntry) {
      // Berechne ALLE Arbeitszeiten des heutigen Tages
      // Hole alle Einträge von heute (wird auch für Pausen verwendet)
      allEntries = await worklogRepository.findByDateRange(uid, todayStart, todayEnd);
      
      // Hole Timefixes für alle Einträge von heute
      const allEntryIds = allEntries.map(e => e.id);
      const timefixMap = await worklogRepository.getTimefixesByWorklogIds(allEntryIds);
      
      // Finde alle Start-Work-Paare von heute
      const workBlocks = [];
      const startWorks = {};
      
      allEntries.forEach(entry => {
        let state = entry.state;
        if (typeof state === 'string') {
          try {
            state = JSON.parse(state);
          } catch (e) {
            // ignore
          }
        }
        
        const action = state?.action || state;
        
        if (action === 'start work') {
          // Prüfe auf Timefix-Korrektur
          const startFix = timefixMap.get(entry.id)?.find(f => f.fix_type === 'start work');
          const startTime = startFix?.fix_date_time || entry.tstamp;
          
          startWorks[entry.id] = {
            id: entry.id,
            startTime: startTime,
            endTime: null,
            pauses: []
          };
        } else if (action === 'stop work' && entry.relatedTo_id && startWorks[entry.relatedTo_id]) {
          // Prüfe auf Timefix-Korrektur
          const endFix = timefixMap.get(entry.id)?.find(f => f.fix_type === 'stop work');
          const endTime = endFix?.fix_date_time || entry.tstamp;
          
          startWorks[entry.relatedTo_id].endTime = endTime;
        }
      });
      
      // Sammle Pausen für jeden Block
      allEntries.forEach(entry => {
        let state = entry.state;
        if (typeof state === 'string') {
          try {
            state = JSON.parse(state);
          } catch (e) {
            // ignore
          }
        }
        
        const action = state?.action || state;
        
        if (action === 'start pause' && entry.relatedTo_id && startWorks[entry.relatedTo_id]) {
          // Prüfe auf Timefix-Korrektur
          const pauseStartFix = timefixMap.get(entry.id)?.find(f => f.fix_type === 'start pause');
          const pauseStartTime = pauseStartFix?.fix_date_time || entry.tstamp;
          
          startWorks[entry.relatedTo_id].pauses.push({
            id: entry.id,
            startTime: pauseStartTime,
            endTime: null
          });
        } else if (action === 'stop pause' && entry.relatedTo_id) {
          // Finde das zugehörige start pause
          Object.values(startWorks).forEach(block => {
            const pause = block.pauses.find(p => p.id === entry.relatedTo_id);
            if (pause) {
              // Prüfe auf Timefix-Korrektur
              const pauseEndFix = timefixMap.get(entry.id)?.find(f => f.fix_type === 'stop pause');
              pause.endTime = pauseEndFix?.fix_date_time || entry.tstamp;
            }
          });
        }
      });
      
      // Berechne Gesamtarbeitszeit aller Blöcke
      let totalWorkedMs = 0;
      
      Object.values(startWorks).forEach(block => {
        const blockStart = new Date(block.startTime).getTime();
        const blockEnd = block.endTime ? new Date(block.endTime).getTime() : now.getTime();
        
        let blockWorkedMs = blockEnd - blockStart;
        
        // Ziehe abgeschlossene Pausen ab
        block.pauses.forEach(pause => {
          if (pause.endTime) {
            const pauseDuration = new Date(pause.endTime).getTime() - new Date(pause.startTime).getTime();
            blockWorkedMs -= pauseDuration;
          } else {
            // Laufende Pause
            const pauseDuration = now.getTime() - new Date(pause.startTime).getTime();
            blockWorkedMs -= pauseDuration;
          }
        });
        
        totalWorkedMs += blockWorkedMs;
      });
      
      // Formatiere als HH:MM:SS
      const totalSeconds = Math.floor(totalWorkedMs / 1000);
      const hours = Math.floor(totalSeconds / 3600);
      const minutes = Math.floor((totalSeconds % 3600) / 60);
      const seconds = totalSeconds % 60;
      
      currentlyWorked = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    }
    
    // Berechne "Offen" basierend auf timewish (oder Standard: 8 Stunden)
    // WICHTIG: Diese Zeit wird OHNE fehlende Pausen berechnet
    // Das Frontend addiert die fehlenden Pausen dann zur "Normales Arbeitsende" Berechnung
    let open = null;
    const { Timewish } = database.getModels();
    
    // now wurde bereits oben deklariert (Zeile 221)
    const currentDayOfWeek = now.getDay(); // 0=Sonntag, 1=Montag, ..., 6=Samstag
    // Konvertiere: 0->7 (Sonntag), 1->1 (Montag), ..., 6->6 (Samstag)
    const timewishDay = currentDayOfWeek === 0 ? 7 : currentDayOfWeek;
    
    const timewish = await Timewish.findOne({
      where: {
        user_id: uid,
        day: timewishDay
      },
      raw: true
    });
    
    // Berechne "Offen" nur wenn aktuell gearbeitet wird
    if (currentlyWorked) {
      if (timewish) {
        // Timewish vorhanden - verwende Wunschzeit
        if (timewish.wishtype === 1) {
          // Ende nach Uhrzeit
          if (timewish.end_time) {
            // Parse end_time (HH:MM:SS)
            const [endHour, endMinute] = timewish.end_time.split(':').map(Number);
            const endTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), endHour, endMinute, 0);
            
            const remainingMs = endTime.getTime() - now.getTime();
            
            if (remainingMs > 0) {
              const remainingSeconds = Math.floor(remainingMs / 1000);
              const h = Math.floor(remainingSeconds / 3600);
              const m = Math.floor((remainingSeconds % 3600) / 60);
              const s = remainingSeconds % 60;
              open = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
            } else {
              open = '00:00:00'; // Bereits überschritten
            }
          }
        } else if (timewish.wishtype === 2) {
          // Ende nach Stunden
          if (timewish.hours) {
            // Parse currentlyWorked
            const [workedH, workedM, workedS] = currentlyWorked.split(':').map(Number);
            const workedSeconds = workedH * 3600 + workedM * 60 + workedS;
            const wishSeconds = Math.floor(timewish.hours * 3600);
            
            const remainingSeconds = wishSeconds - workedSeconds;
            
            if (remainingSeconds > 0) {
              const h = Math.floor(remainingSeconds / 3600);
              const m = Math.floor((remainingSeconds % 3600) / 60);
              const s = remainingSeconds % 60;
              open = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
            } else {
              open = '00:00:00'; // Bereits erreicht
            }
          }
        }
      } else {
        // Kein Timewish - Standard: 8 Stunden
        const [workedH, workedM, workedS] = currentlyWorked.split(':').map(Number);
        const workedSeconds = workedH * 3600 + workedM * 60 + workedS;
        const standardSeconds = 8 * 3600; // 8 Stunden
        
        const remainingSeconds = standardSeconds - workedSeconds;
        
        if (remainingSeconds > 0) {
          const h = Math.floor(remainingSeconds / 3600);
          const m = Math.floor((remainingSeconds % 3600) / 60);
          const s = remainingSeconds % 60;
          open = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
        } else {
          open = '00:00:00'; // Bereits erreicht
        }
      }
    }
    
    // Berechne gesetzlich erforderliche Pausen
    let requiredBreakMinutes = 0;
    let alreadyTakenBreakMinutes = 0;
    
    if (currentlyWorked) {
      // Geplante Arbeitszeit
      let plannedWorkHours = 8; // Standard
      
      if (timewish && timewish.wishtype === 2 && timewish.hours) {
        plannedWorkHours = timewish.hours;
      }
      
      // Gesetzliche Pausen: ab 6h -> 30min, ab 9h -> 45min
      if (plannedWorkHours >= 9) {
        requiredBreakMinutes = 45;
      } else if (plannedWorkHours >= 6) {
        requiredBreakMinutes = 30;
      }
      
      // Berechne ALLE genommenen Pausen von heute (verwende bereits geladene Einträge)
      if (allEntries.length > 0) {
        // Sammle alle abgeschlossenen Pausen
        const pauseStarts = {};
        let totalPauseMs = 0;
        
        allEntries.forEach(entry => {
          let state = entry.state;
          if (typeof state === 'string') {
            try {
              state = JSON.parse(state);
            } catch (e) {
              // ignore
            }
          }
          
          const action = state?.action || state;
          
          if (action === 'start pause') {
            pauseStarts[entry.id] = entry;
          } else if (action === 'stop pause' && entry.relatedTo_id) {
            const startPause = pauseStarts[entry.relatedTo_id];
            if (startPause) {
              const pauseDuration = new Date(entry.tstamp).getTime() - new Date(startPause.tstamp).getTime();
              totalPauseMs += pauseDuration;
              delete pauseStarts[entry.relatedTo_id];
            }
          }
        });
        
        alreadyTakenBreakMinutes = Math.floor(totalPauseMs / (1000 * 60));
      }
    }
    
    // Fehlende Pausenzeit
    const missingBreakMinutes = Math.max(0, requiredBreakMinutes - alreadyTakenBreakMinutes);
    
    // Addiere fehlende Pausen zur "Offen" Zeit
    if (open && open !== '—' && open !== 'Arbeitsende erreicht') {
      const openParts = open.split(':');
      const openH = parseInt(openParts[0]);
      const openM = parseInt(openParts[1]);
      const openS = parseInt(openParts[2] || 0);
      const openMinutes = openH * 60 + openM + missingBreakMinutes;
      
      const newOpenH = Math.floor(openMinutes / 60);
      const newOpenM = openMinutes % 60;
      const newOpenS = openS;
      
      open = `${newOpenH.toString().padStart(2, '0')}:${newOpenM.toString().padStart(2, '0')}:${newOpenS.toString().padStart(2, '0')}`;
    }
    
    // Berechne Überstunden über den gesamten Zeitraum (alle Wochen)
    // Neue Berechnung: Timewish-basiert
    const totalOvertimeResult = await this._calculateTotalOvertime(uid, runningEntry);
    
    // Berechne Überstunden für die aktuelle Woche
    const weekData = await this.getWeekOverview(uid, 0);
    
    console.log(`🔍 Wochenüberstunden-Berechnung START: userDailyHours=${userDailyHours}`);
    
    let weekSollMinutes = 0; // Soll-Arbeitszeit für die Woche
    let weekIstMinutes = 0; // Ist-Arbeitszeit für die Woche
    
    // Hole alle Timewishes für Mo-Fr
    const allTimewishes = await Timewish.findAll({
      where: {
        user_id: uid,
        day: {
          [require('sequelize').Op.in]: [1, 2, 3, 4, 5] // Mo-Fr
        }
      },
      raw: true
    });
    
    // Erstelle Map: Tag -> Array von Timewishes
    const timewishMap = new Map();
    allTimewishes.forEach(tw => {
      if (!timewishMap.has(tw.day)) {
        timewishMap.set(tw.day, []);
      }
      timewishMap.get(tw.day).push(tw);
    });
    
    // Nur abgeschlossene Tage berücksichtigen (nicht heute, wenn noch gearbeitet wird)
    const todayDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const includeTodayInOvertime = !runningEntry; // Nur wenn heute schon abgeschlossen ist
    
    weekData.days.forEach(day => {
      // Parse day.date (YYYY-MM-DD) - mit expliziter Zeit um Midnight
      const dayDate = new Date(day.date + 'T00:00:00');
      const dayDateOnly = new Date(dayDate.getFullYear(), dayDate.getMonth(), dayDate.getDate());
      
      const isToday = dayDateOnly.getTime() === todayDate.getTime();
      
      // Zukünftige Tage überspringen
      if (dayDateOnly > todayDate) {
        return;
      }
      
      // Heute überspringen, wenn noch gearbeitet wird
      if (isToday && !includeTodayInOvertime) {
        return;
      }
      
      const dayOfWeek = dayDate.getDay(); // 0=So, 1=Mo, ..., 6=Sa
      
      // Nur Mo-Fr berücksichtigen
      if (dayOfWeek === 0 || dayOfWeek === 6) {
        return; // Wochenende überspringen
      }
      
      // Prüfe auf Feiertag, Urlaub, Krankheit
      if (day.sick) {
        // Krankheitstag: Soll = 0, Ist wird ignoriert
        return;
      }
      
      if (day.holiday) {
        // Feiertag: Soll = 0
        return;
      }
      
      if (day.vacation && !day.workBlocks?.length) {
        // Voller Urlaubstag ohne Arbeit: Soll = 0
        return;
      }
      
      // Berechne Soll-Zeit für diesen Tag
      const timewishDay = dayOfWeek === 0 ? 7 : dayOfWeek;
      const dayTimewishes = timewishMap.get(timewishDay) || [];
      
      // Finde den passenden Timewish für dieses Datum
      const applicableTimewish = dayTimewishes.find(tw => {
        const startDate = new Date(tw.start_date);
        const endDate = tw.end_date ? new Date(tw.end_date) : null;
        
        // Prüfe ob dayDate im Gültigkeitsbereich liegt
        if (dayDate < startDate) return false;
        if (endDate && dayDate > endDate) return false;
        
        return true;
      });
      
      let daySollHours = userDailyHours; // Fallback: User's daily_hours
      console.log(`  Tag ${day.date}: userDailyHours=${userDailyHours}, applicableTimewish=${applicableTimewish ? applicableTimewish.hours + 'h' : 'keine'}`);
      
      if (applicableTimewish && applicableTimewish.wishtype === 2 && applicableTimewish.hours) {
        daySollHours = applicableTimewish.hours;
        console.log(`  → Verwende Timewish: ${daySollHours}h`);
      }
      
      // Bei halbem Urlaubstag: Soll halbiert
      if (day.vacation && day.vacation.halfDay) {
        daySollHours = daySollHours / 2;
        console.log(`  → Halber Urlaubstag: ${daySollHours}h`);
      }
      
      weekSollMinutes += daySollHours * 60;
      
      // Berechne Ist-Zeit für diesen Tag
      if (day.netWorkTime) {
        const [h, m] = day.netWorkTime.split(':').map(Number);
        weekIstMinutes += h * 60 + m;
        console.log(`  Tag ${day.date}: netWorkTime=${day.netWorkTime}, Soll=${daySollHours}h, Ist=${h}:${m}`);
      }
    });
    
    // Überstunden = Ist - Soll
    const overtimeMinutes = weekIstMinutes - weekSollMinutes;
    
    console.log(`🔍 Wochenüberstunden: weekIst=${weekIstMinutes}min (${Math.floor(weekIstMinutes/60)}:${weekIstMinutes%60}), weekSoll=${weekSollMinutes}min (${Math.floor(weekSollMinutes/60)}:${weekSollMinutes%60}), overtime=${overtimeMinutes}min`);
    
    const overtimeHours = Math.floor(Math.abs(overtimeMinutes) / 60);
    const overtimeMins = Math.abs(overtimeMinutes) % 60;
    const overtimeSign = overtimeMinutes >= 0 ? '+' : '-';
    const overtime = `${overtimeSign}${overtimeHours}:${overtimeMins.toString().padStart(2, '0')}`;
    
    // Wochenarbeitszeit
    const weekWorktimeHours = Math.floor(weekIstMinutes / 60);
    const weekWorktimeMins = weekIstMinutes % 60;
    const weekWorktime = `${weekWorktimeHours}:${weekWorktimeMins.toString().padStart(2, '0')}`;
    
    // Berechne "Offen für Woche"
    // Dies ist: Wie lange muss ich HEUTE noch arbeiten, um das Wochenziel zu erreichen?
    // = Wochensoll (gesamt) - Wochenist (abgeschlossene Tage + heute bisher)
    let openForWeekFormatted = '—';
    
    if (runningEntry) {
      // Berechne Wochensoll und -ist
      let weekSollMinutesTotal = 0;
      let weekIstMinutesTotal = 0;
      
      weekData.days.forEach(day => {
        // Parse day.date als YYYY-MM-DD und vergleiche nur das Datum (ohne Zeit)
        const dayDate = new Date(day.date + 'T00:00:00');
        const dayDateOnly = new Date(dayDate.getFullYear(), dayDate.getMonth(), dayDate.getDate());
        
        // isToday basierend auf Datumsvergleich (ohne Uhrzeit)
        const isToday = dayDateOnly.getTime() === todayDate.getTime();
        
        // Zukünftige Tage überspringen
        if (dayDateOnly > todayDate) {
          return;
        }
        
        const dayOfWeek = dayDate.getDay();
        
        // Nur Mo-Fr berücksichtigen
        if (dayOfWeek === 0 || dayOfWeek === 6) {
          return;
        }
        
        // Prüfe auf Feiertag, Urlaub, Krankheit
        if (day.sick || day.holiday) {
          return;
        }
        
        if (day.vacation && !day.workBlocks?.length) {
          return;
        }
        
        // Berechne Soll-Zeit für diesen Tag
        const timewishDay = dayOfWeek === 0 ? 7 : dayOfWeek;
        const dayTimewishes = timewishMap.get(timewishDay) || [];
        
        const applicableTimewish = dayTimewishes.find(tw => {
          const startDate = new Date(tw.start_date);
          const endDate = tw.end_date ? new Date(tw.end_date) : null;
          if (dayDate < startDate) return false;
          if (endDate && dayDate > endDate) return false;
          return true;
        });
        
        let daySollHours = userDailyHours; // Fallback: User's daily_hours
        if (applicableTimewish && applicableTimewish.wishtype === 2 && applicableTimewish.hours) {
          daySollHours = applicableTimewish.hours;
        }
        
        if (day.vacation && day.vacation.halfDay) {
          daySollHours = daySollHours / 2;
        }
        
        weekSollMinutesTotal += daySollHours * 60;
        
        // Berechne Ist-Zeit für diesen Tag
        let dayIstMinutes = 0;
        
        if (isToday && currentlyWorked) {
          // Für heute: Verwende die aktuell gearbeitete Zeit aus currentlyWorked
          // NICHT day.netWorkTime verwenden, um Doppelzählung zu vermeiden!
          const [h, m, s] = currentlyWorked.split(':').map(Number);
          dayIstMinutes = h * 60 + m;
          weekIstMinutesTotal += dayIstMinutes;
          console.log(`  HEUTE ${day.date}: currentlyWorked=${currentlyWorked}, Soll=${daySollHours}h, Ist=${h}:${m}`);
        } else if (!isToday && day.netWorkTime) {
          // Für vergangene Tage: Verwende netWorkTime
          const [h, m] = day.netWorkTime.split(':').map(Number);
          dayIstMinutes = h * 60 + m;
          weekIstMinutesTotal += dayIstMinutes;
          console.log(`  Vergangener Tag ${day.date}: netWorkTime=${day.netWorkTime}, Soll=${daySollHours}h, Ist=${h}:${m}`);
        }
      });
      
      console.log(`🔍 Offen für Woche: weekIstTotal=${weekIstMinutesTotal}min, weekSollTotal=${weekSollMinutesTotal}min`);
      
      // Offen für Woche = Wochensoll - Wochenist (bisher)
      const openForWeekMinutes = weekSollMinutesTotal - weekIstMinutesTotal;
      
      if (openForWeekMinutes > 0) {
        // Es muss noch gearbeitet werden, um das Wochenziel zu erreichen
        const openWeekHours = Math.floor(openForWeekMinutes / 60);
        const openWeekMins = openForWeekMinutes % 60;
        openForWeekFormatted = `${openWeekHours}:${openWeekMins.toString().padStart(2, '0')}`;
      } else if (openForWeekMinutes === 0) {
        // Exakt das Wochenziel erreicht
        openForWeekFormatted = 'Wochenziel erreicht';
      } else {
        // Negativ = Wochenziel bereits übertroffen
        openForWeekFormatted = '—';
      }
    }
    
    // Berechne "Bereinigtes Arbeitsende"
    // Nur berechnen, wenn derzeit gearbeitet wird (NICHT in Pause!)
    let adjustedEndTodayGeneral = '—';
    let adjustedEndTodayWeek = '—';
    
    // Hole den aktuellen Status
    const currentState = await this.getCurrentState(uid);
    
    // Arbeitsende berechnen, wenn derzeit gearbeitet wird
    // Das ist der Fall bei: 'start work' (direkt nach Arbeitsbeginn) oder 'stop pause' (nach Pausenende)
    const isCurrentlyWorking = runningEntry && (currentState === 'start work' || currentState === 'stop pause');
    
    if (isCurrentlyWorking && open && open !== '—' && open !== 'Arbeitsende erreicht') {
      // Parse "Offen" Zeit (Format: HH:MM:SS)
      const openParts = open.split(':');
      const openH = parseInt(openParts[0]);
      const openM = parseInt(openParts[1]);
      const openS = parseInt(openParts[2] || 0);
      const openMinutes = openH * 60 + openM;
      
      // Aktuelle Zeit
      const currentTime = new Date();
      
      // ===== GENERELL =====
      // Verbleibende Zeit = Offen - Gesamt-Überstunden
      // WICHTIG: "open" enthält bereits die fehlenden Pausen!
      const generalOvertimeMinutes = totalOvertimeResult.minutes || 0;
      const generalRemainingMinutes = openMinutes - generalOvertimeMinutes;
      
      if (generalRemainingMinutes <= 0) {
        adjustedEndTodayGeneral = 'Arbeitsende erreicht';
      } else {
        // Berechne Uhrzeit: jetzt + verbleibende Minuten
        const endTime = new Date(currentTime.getTime() + generalRemainingMinutes * 60 * 1000);
        const endH = endTime.getHours();
        const endM = endTime.getMinutes();
        adjustedEndTodayGeneral = `${endH.toString().padStart(2, '0')}:${endM.toString().padStart(2, '0')}`;
      }
      
      // ===== WOCHE =====
      // Verbleibende Zeit = Offen - Wochen-Über/Unterstunden
      // WICHTIG: "open" enthält bereits die fehlenden Pausen!
      const weekOvertimeMinutes = overtimeMinutes; // Bereits berechnet
      const weekRemainingMinutes = openMinutes - weekOvertimeMinutes;
      
      if (weekRemainingMinutes <= 0) {
        adjustedEndTodayWeek = 'Arbeitsende erreicht';
      } else {
        // Berechne Uhrzeit: jetzt + verbleibende Minuten
        const endTime = new Date(currentTime.getTime() + weekRemainingMinutes * 60 * 1000);
        const endH = endTime.getHours();
        const endM = endTime.getMinutes();
        adjustedEndTodayWeek = `${endH.toString().padStart(2, '0')}:${endM.toString().padStart(2, '0')}`;
      }
    }
    
    // Berechne Arbeitsfreie Stunden (Urlaub + Krankheit + Feiertage) bis heute
    let nonWorkingMinutes = 0;
    
    weekData.days.forEach(day => {
      const dayDate = new Date(day.date);
      
      // Nur Tage bis heute berücksichtigen
      if (dayDate > todayDate) {
        return;
      }
      
      // Bei laufendem Tag: überspringen
      if (dayDate.getTime() === todayDate.getTime() && !includeTodayInOvertime) {
        return;
      }
      
      const dayOfWeek = dayDate.getDay();
      
      // Nur Mo-Fr berücksichtigen
      if (dayOfWeek === 0 || dayOfWeek === 6) {
        return;
      }
      
      // Sammle arbeitsfreie Stunden
      if (day.sick) {
        nonWorkingMinutes += day.sick.hours * 60;
      } else if (day.holiday) {
        nonWorkingMinutes += day.holiday.hours * 60;
      } else if (day.vacation) {
        nonWorkingMinutes += day.vacation.hours * 60;
      }
    });
    
    const nonWorkingHours = Math.floor(nonWorkingMinutes / 60);
    const nonWorkingMins = nonWorkingMinutes % 60;
    const nonWorkingHoursFormatted = nonWorkingMinutes > 0 
      ? `${nonWorkingHours}:${nonWorkingMins.toString().padStart(2, '0')}`
      : null;
    
    // TODO: Echte Berechnungen für die anderen Felder implementieren
    
    return {
      timestamp: new Date().toISOString(), // Zeitpunkt der Berechnung
      currentlyWorked: currentlyWorked,
      open: open,
      requiredBreakMinutes: requiredBreakMinutes, // Gesetzlich erforderlich
      alreadyTakenBreakMinutes: alreadyTakenBreakMinutes, // Bereits genommen
      missingBreakMinutes: missingBreakMinutes, // Noch fehlend
      regularEnd: null,
      overtime: overtime, // Überstunden für die aktuelle Woche
      totalOvertime: totalOvertimeResult.formatted, // Überstunden über den gesamten Zeitraum (timewish-basiert)
      weekWorktime: weekWorktime,
      nonWorkingHours: nonWorkingHoursFormatted,
      openForWeek: openForWeekFormatted,
      adjustedEndToday: 'Bereinigtes Arbeitsende (heute)', // Überschrift ohne Zeitwert
      adjustedEndTodayGeneral: adjustedEndTodayGeneral,
      adjustedEndTodayWeek: adjustedEndTodayWeek
    };
  }

  /**
   * Berechnet die Gesamt-Überstunden über alle Wochen
   * @param {number} userId - Benutzer-ID
   * @param {Object|null} runningEntry - Laufender Eintrag (falls vorhanden)
   * @returns {Promise<Object>} { minutes, formatted }
   * @private
   */
  /**
   * Berechne Überstunden im alten Style (weekly_worktime)
   * @private
   */
  async _calculateTotalOvertimeOldStyle(userId, runningEntry) {
    const { WeeklyWorktime } = database.getModels();
    
    // Finde den ersten Worklog-Eintrag des Users
    const firstEntry = await worklogRepository.findByUser(userId);
    if (!firstEntry || firstEntry.length === 0) {
      return { minutes: 0, formatted: '+0:00' };
    }
    
    // Hole alle WeeklyWorktime-Einträge für diesen User
    const weeklyWorktimes = await WeeklyWorktime.findAll({
      where: { user_id: userId },
      order: [['starting_from', 'ASC']],
      raw: true
    });
    
    if (weeklyWorktimes.length === 0) {
      weeklyWorktimes.push({
        weekly_work_time: 40,
        starting_from: null,
        ends_at: null
      });
    }
    
    // Berechne Soll-Stunden für ein Datum basierend auf weekly_worktime
    const getDailySollHours = (date) => {
      const dateObj = new Date(date);
      const dateString = dateObj.toISOString().split('T')[0];
      
      // Finde passenden weekly_worktime Eintrag
      let applicable = null;
      for (const wt of weeklyWorktimes) {
        const startFrom = wt.starting_from || '1900-01-01';
        const endsAt = wt.ends_at || '9999-12-31';
        
        if (dateString >= startFrom && dateString <= endsAt) {
          applicable = wt;
          break;
        }
      }
      
      if (!applicable) {
        applicable = weeklyWorktimes[weeklyWorktimes.length - 1];
      }
      
      // Wochenstunden / 5 = Tagesstunden (Mo-Fr)
      return applicable.weekly_work_time / 5;
    };
    
    const firstDate = new Date(firstEntry[0].tstamp + 'Z');
    const firstMonday = new Date(firstDate);
    const dayOfWeek = firstDate.getUTCDay();
    const daysToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
    firstMonday.setUTCDate(firstDate.getUTCDate() + daysToMonday);
    firstMonday.setUTCHours(0, 0, 0, 0);
    
    const now = new Date();
    const todayMonday = new Date(now);
    const todayDayOfWeek = now.getDay();
    const todayDaysToMonday = todayDayOfWeek === 0 ? -6 : 1 - todayDayOfWeek;
    todayMonday.setDate(now.getDate() + todayDaysToMonday);
    todayMonday.setHours(0, 0, 0, 0);
    
    const weeksDiff = Math.floor((todayMonday - firstMonday) / (7 * 24 * 60 * 60 * 1000));
    
    let totalSollMinutes = 0;
    let totalIstMinutes = 0;
    
    const todayDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const yesterdayDate = new Date(todayDate);
    yesterdayDate.setDate(yesterdayDate.getDate() - 1);
    const endDate = yesterdayDate;
    
    // Iteriere über alle Wochen
    for (let weekOffset = -weeksDiff; weekOffset <= 0; weekOffset++) {
      const weekData = await this.getWeekOverview(userId, weekOffset);
      
      weekData.days.forEach(day => {
        const dayDate = new Date(day.date);
        
        if (dayDate > endDate) {
          return;
        }
        
        const dayOfWeek = dayDate.getDay();
        
        if (dayOfWeek === 0 || dayOfWeek === 6) {
          return;
        }
        
        const daySollHours = getDailySollHours(day.date);
        
        if (day.holiday || day.sick) {
          return;
        }
        
        if (day.vacation) {
          const vacationHours = day.vacationHours || 0;
          
          if (vacationHours === 4) {
            // Halber Urlaubstag: Soll = Tagesstunden * 0.5
            totalSollMinutes += (daySollHours * 0.5) * 60;
            
            if (day.netWorkTime) {
              const [h, m] = day.netWorkTime.split(':').map(Number);
              totalIstMinutes += h * 60 + m;
            }
          } else {
            // Ganzer Urlaubstag: überspringen
            return;
          }
        } else {
          // Normaler Arbeitstag
          // WICHTIG für Alt-Style: Nur Tage zählen, an denen tatsächlich gearbeitet wurde!
          if (day.netWorkTime) {
            const [h, m] = day.netWorkTime.split(':').map(Number);
            const istMinutes = h * 60 + m;
            
            totalSollMinutes += daySollHours * 60;
            totalIstMinutes += istMinutes;
          }
          // Tage OHNE Arbeit werden NICHT gezählt (kein Soll, kein Ist)
        }
      });
    }
    
    const overtimeMinutes = totalIstMinutes - totalSollMinutes;
    const overtimeHours = Math.floor(Math.abs(overtimeMinutes) / 60);
    const overtimeMins = Math.abs(overtimeMinutes) % 60;
    const overtimeSign = overtimeMinutes >= 0 ? '+' : '-';
    const formatted = `${overtimeSign}${overtimeHours}:${overtimeMins.toString().padStart(2, '0')}`;
    
    return { minutes: overtimeMinutes, formatted };
  }

  async _calculateTotalOvertime(userId, runningEntry) {
    const { Timewish, Holiday, Vacation, Sick, Worklog, User } = database.getModels();
    const sequelize = database.sequelize;
    
    // Hole den Überstunden-Offset und daily_hours für diesen User
    const user = await User.findByPk(userId, { attributes: ['overtime_offset_minutes', 'daily_hours'], raw: true });
    const overtimeOffsetMinutes = user?.overtime_offset_minutes || 0;
    const userDailyHours = user?.daily_hours || 8;
    
    // Hole alle Timewishes für Mo-Fr
    const allTimewishes = await Timewish.findAll({
      where: {
        user_id: userId,
        day: {
          [require('sequelize').Op.in]: [1, 2, 3, 4, 5] // Mo-Fr
        }
      },
      raw: true,
      order: [['day', 'ASC'], ['start_date', 'ASC']]
    });
    
    // Erstelle Map: Tag -> Array von Timewishes
    const timewishMap = new Map();
    allTimewishes.forEach(tw => {
      if (!timewishMap.has(tw.day)) {
        timewishMap.set(tw.day, []);
      }
      timewishMap.get(tw.day).push(tw);
    });
    
    // Berechne Soll-Stunden für ein Datum basierend auf timewish
    const getDailySollHours = (dateString, dayOfWeek) => {
      // Konvertiere JS dayOfWeek (0=So, 1=Mo) zu DB dayOfWeek (1=Mo, 7=So)
      const timewishDay = dayOfWeek === 0 ? 7 : dayOfWeek;
      
      const dayTimewishes = timewishMap.get(timewishDay) || [];
      
      // Finde den passenden Timewish für dieses Datum
      const applicableTimewish = dayTimewishes.find(tw => {
        const startDate = tw.start_date;
        const endDate = tw.end_date || '9999-12-31';
        
        return dateString >= startDate && dateString <= endDate;
      });
      
      if (applicableTimewish && applicableTimewish.wishtype === 2 && applicableTimewish.hours) {
        return parseFloat(applicableTimewish.hours);
      }
      
      // Fallback: User's daily_hours
      return parseFloat(userDailyHours);
    };
    
    // Berechne Endedatum: gestern (wie alte MySQL-Funktion)
    const now = new Date();
    const yesterdayDate = new Date(now);
    yesterdayDate.setDate(yesterdayDate.getDate() - 1);
    const endDateStr = yesterdayDate.toISOString().split('T')[0];
    
    // Hole alle Arbeitstage mit Netto-Arbeitszeit aus der DB
    // WICHTIG: Berücksichtigt timefix-Korrekturen!
    // Dies ist VIEL schneller als 253x getWeekOverview aufzurufen!
    const query = `
      SELECT 
        DATE(COALESCE(w1_fix.fix_date_time, w1.tstamp)) as work_date,
        DAYOFWEEK(DATE(COALESCE(w1_fix.fix_date_time, w1.tstamp))) as day_of_week,
        SUM(
          TIMESTAMPDIFF(SECOND, 
            COALESCE(w1_fix.fix_date_time, w1.tstamp), 
            COALESCE(w2_fix.fix_date_time, w2.tstamp)
          ) - IFNULL(pauses.pause_seconds, 0)
        ) / 3600 as net_hours
      FROM worklog w1
      LEFT JOIN timefix w1_fix ON w1_fix.worklog_id = w1.id
      JOIN worklog w2 ON w2.relatedTo_id = w1.id AND w2.state = 'stop work'
      LEFT JOIN timefix w2_fix ON w2_fix.worklog_id = w2.id
      LEFT JOIN (
        SELECT 
          p1.relatedTo_id as work_id,
          SUM(
            TIMESTAMPDIFF(SECOND, 
              COALESCE(p1_fix.fix_date_time, p1.tstamp), 
              COALESCE(p2_fix.fix_date_time, p2.tstamp)
            )
          ) as pause_seconds
        FROM worklog p1
        LEFT JOIN timefix p1_fix ON p1_fix.worklog_id = p1.id
        JOIN worklog p2 ON p2.relatedTo_id = p1.id AND p2.state = 'stop pause'
        LEFT JOIN timefix p2_fix ON p2_fix.worklog_id = p2.id
        WHERE p1.state = 'start pause'
        GROUP BY p1.relatedTo_id
      ) pauses ON pauses.work_id = w1.id
      WHERE w1.state = 'start work'
        AND w1.user_id = ?
        AND DATE(COALESCE(w1_fix.fix_date_time, w1.tstamp)) <= ?
        AND DAYOFWEEK(DATE(COALESCE(w1_fix.fix_date_time, w1.tstamp))) BETWEEN 2 AND 6
      GROUP BY DATE(COALESCE(w1_fix.fix_date_time, w1.tstamp)), DAYOFWEEK(DATE(COALESCE(w1_fix.fix_date_time, w1.tstamp)))
      ORDER BY DATE(COALESCE(w1_fix.fix_date_time, w1.tstamp))
    `;
    
    const workDays = await sequelize.query(query, {
      replacements: [userId, endDateStr],
      type: sequelize.QueryTypes.SELECT
    });
    
    // Hole User-Bundesland
    const { State: StateModel } = database.getModels();
    const userForState = await User.findByPk(userId, { 
      attributes: ['state_id'],
      raw: true 
    });
    const userStateId = userForState?.state_id;
    
    // Hole Feiertage mit States
    const holidays = await Holiday.findAll({
      where: {
        date: {
          [require('sequelize').Op.lte]: endDateStr
        }
      },
      include: [
        {
          model: StateModel,
          as: 'states',
          attributes: ['id'],
          through: { attributes: [] },
          required: false
        }
      ]
    });
    
    // Filtere nur Feiertage die für den User gelten
    const holidaySet = new Set();
    holidays.forEach(h => {
      const holidayStates = h.states || [];
      const isFederal = holidayStates.length === 0;
      const appliesToUser = isFederal || holidayStates.some(s => s.id === userStateId);
      
      if (appliesToUser) {
        holidaySet.add(h.date);
      }
    });
    
    // Hole Krankheitstage (expandiert)
    const sickDaysRaw = await Sick.findAll({
      where: {
        user_id: userId,
        first_day: {
          [require('sequelize').Op.lte]: endDateStr
        }
      },
      raw: true
    });
    
    const sickSet = new Set();
    sickDaysRaw.forEach(sick => {
      const start = new Date(sick.first_day);
      const end = new Date(sick.last_day);
      
      for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
        const dow = d.getDay();
        if (dow >= 1 && dow <= 5) { // Mo-Fr
          sickSet.add(d.toISOString().split('T')[0]);
        }
      }
    });
    
    // Hole Urlaubstage (expandiert)
    const vacationDaysRaw = await Vacation.findAll({
      where: {
        user_id: userId,
        first_day: {
          [require('sequelize').Op.lte]: endDateStr
        }
      },
      raw: true
    });
    
    const vacationMap = new Map(); // date -> hours (4 oder 8)
    vacationDaysRaw.forEach(vac => {
      const start = new Date(vac.first_day);
      const end = new Date(vac.last_day);
      const hours = vac.vacation_type === 1 ? 4 : 8;
      
      for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
        const dow = d.getDay();
        if (dow >= 1 && dow <= 5) { // Mo-Fr
          vacationMap.set(d.toISOString().split('T')[0], hours);
        }
      }
    });
    
    // Erstelle Map: work_date -> net_hours
    const workDaysMap = new Map();
    let totalIstHoursFromDB = 0;
    workDays.forEach(wd => {
      const netHours = parseFloat(wd.net_hours);
      workDaysMap.set(wd.work_date, netHours);
      totalIstHoursFromDB += netHours;
    });
    
    // Berechne Soll-Stunden für alle Arbeitstage
    let totalSollMinutes = 0;
    let processedDays = 0;
    let sickDaysCount = 0;
    let holidayDaysCount = 0;
    let vacationFullDays = 0;
    let vacationHalfDays = 0;
    let workedDays = 0;
    let notWorkedDays = 0;
    
    // Berechne Soll-Zeit für jeden Tag in workDaysMap (= Tage mit tatsächlicher Arbeit)
    workDaysMap.forEach((istHours, dateStr) => {
      const d = new Date(dateStr);
      const dow = d.getDay();
      
      // Prüfe auf Feiertag, Krankheit, Urlaub
      if (holidaySet.has(dateStr)) {
        holidayDaysCount++;
        return;
      }
      
      if (sickSet.has(dateStr)) {
        sickDaysCount++;
        return;
      }
      
      const vacationHours = vacationMap.get(dateStr);
      if (vacationHours) {
        if (vacationHours === 4) {
          // Halber Urlaubstag
          vacationHalfDays++;
          const sollHours = getDailySollHours(dateStr, dow);
          totalSollMinutes += (sollHours - 4) * 60;
          workedDays++;
        } else {
          // Ganzer Urlaubstag
          vacationFullDays++;
        }
      } else {
        // Normaler Arbeitstag
        const sollHours = getDailySollHours(dateStr, dow);
        totalSollMinutes += sollHours * 60;
        workedDays++;
        processedDays++;
      }
    });
    
    // Verwende die Ist-Stunden direkt aus der DB-Query (korrekt!)
    const totalIstMinutes = totalIstHoursFromDB * 60;
    
    // Berechne Überstunden ohne Offset
    const overtimeMinutesRaw = Math.round(totalIstMinutes - totalSollMinutes);
    
    // Addiere den Offset
    const overtimeMinutes = overtimeMinutesRaw + overtimeOffsetMinutes;
    
    const overtimeHours = Math.floor(Math.abs(overtimeMinutes) / 60);
    const overtimeMins = Math.abs(overtimeMinutes) % 60;
    const overtimeSign = overtimeMinutes >= 0 ? '+' : '-';
    const formatted = `${overtimeSign}${overtimeHours}:${overtimeMins.toString().padStart(2, '0')}`;
    
    return { minutes: overtimeMinutes, formatted };
  }

  /**
   * Wochenübersicht für einen Benutzer abrufen
   * @param {number} userId - Benutzer-ID
   * @param {number} weekOffset - Wochen-Offset (0 = aktuelle Woche, -1 = letzte Woche, etc.)
   * @returns {Promise<Object>} Wochenübersicht mit Tagesdaten
   */
  async getWeekOverview(userId, weekOffset = 0) {
    const uid = userId || this.defaultUserId;
    
    // Berechne Start und Ende der gewünschten Woche (Montag bis Sonntag)
    // Verwende lokales Datum, nicht UTC
    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth();
    const day = now.getDate();
    const currentDay = now.getDay(); // 0 = Sonntag, 1 = Montag, ..., 6 = Samstag
    
    // Offset zu Montag berechnen
    // Montag ist Tag 1, wir wollen zum Montag der aktuellen Woche
    // Wenn Sonntag (0), dann ist das Ende der Woche, also -6 Tage zum Montag
    // Wenn Montag (1), dann 0 Tage
    // Wenn Dienstag (2), dann -1 Tag, etc.
    const daysToMonday = currentDay === 0 ? -6 : 1 - currentDay;
    
    // Berechne Montag der Woche
    const weekStart = new Date(year, month, day + daysToMonday + (weekOffset * 7));
    weekStart.setHours(0, 0, 0, 0);
    
    // Berechne Sonntag der Woche
    const weekEnd = new Date(year, month, day + daysToMonday + (weekOffset * 7) + 6);
    weekEnd.setHours(23, 59, 59, 999);

    // Hole alle Worklog-Einträge für diese Woche
    const pairs = await worklogRepository.findPairsByUserInDateRange(uid, weekStart, weekEnd);
    
    // Hole auch alle einzelnen Einträge für Pausen
    const allEntries = await worklogRepository.findByDateRange(uid, weekStart, weekEnd);
    
    // Hole Timefix-Einträge für alle Worklog-IDs
    const allWorklogIds = [...new Set([
      ...pairs.map(p => p.id),
      ...allEntries.map(e => e.id)
    ])];
    const timefixMap = await worklogRepository.getTimefixesByWorklogIds(allWorklogIds);
    
    // Hole Vacation-Einträge für diese Woche
    const vacations = await worklogRepository.getVacationsByUserInDateRange(uid, weekStart, weekEnd);
    
    // Erstelle Map von Datum zu Vacation
    const vacationMap = new Map();
    vacations.forEach(vac => {
      const vacDate = new Date(vac.date);
      const vacKey = `${vacDate.getUTCFullYear()}-${(vacDate.getUTCMonth()+1).toString().padStart(2,'0')}-${vacDate.getUTCDate().toString().padStart(2,'0')}`;
      vacationMap.set(vacKey, vac);
    });
    
    // Hole Sick-Einträge für diese Woche
    const sickDays = await worklogRepository.getSickByUserInDateRange(uid, weekStart, weekEnd);
    
    // Erstelle Map von Datum zu Sick
    const sickMap = new Map();
    sickDays.forEach(sick => {
      const sickDate = new Date(sick.date);
      const sickKey = `${sickDate.getUTCFullYear()}-${(sickDate.getUTCMonth()+1).toString().padStart(2,'0')}-${sickDate.getUTCDate().toString().padStart(2,'0')}`;
      sickMap.set(sickKey, sick);
    });
    
    // Hole Feiertage für diese Woche (nur die für das User-Bundesland gelten)
    const holidays = await worklogRepository.getHolidaysInDateRange(weekStart, weekEnd, uid);
    
    // Erstelle Map von Datum zu Holiday
    const holidayMap = new Map();
    holidays.forEach(holiday => {
      const holidayDate = new Date(holiday.date);
      const holidayKey = `${holidayDate.getUTCFullYear()}-${(holidayDate.getUTCMonth()+1).toString().padStart(2,'0')}-${holidayDate.getUTCDate().toString().padStart(2,'0')}`;
      holidayMap.set(holidayKey, {
        hours: holiday.hours || 8,
        description: holiday.description
      });
    });
    
    // Gruppiere Einträge nach Tagen
    const dayData = {};
    
    // Initialisiere alle Wochentage
    const todayKey = `${year}-${(month+1).toString().padStart(2,'0')}-${day.toString().padStart(2,'0')}`;
    
    for (let i = 0; i < 7; i++) {
      const currentDay = new Date(weekStart.getFullYear(), weekStart.getMonth(), weekStart.getDate() + i);
      const dayKey = `${currentDay.getFullYear()}-${(currentDay.getMonth()+1).toString().padStart(2,'0')}-${currentDay.getDate().toString().padStart(2,'0')}`;
      
      dayData[dayKey] = {
        date: dayKey,
        name: this._getDayName(currentDay.getDay()),
        workBlocks: [], // Array für mehrere Arbeitszeitblöcke
        workTime: null, // Für Kompatibilität
        pauses: [],
        totalWorkTime: null,
        pauseTimes: [],
        netWorkTime: null,
        status: '',
        statusText: '',
        isToday: dayKey === todayKey
      };
    }

    // Verarbeite gefundene Einträge - SAMMLE alle Arbeitsblöcke
    (Array.isArray(pairs) ? pairs : []).forEach(pair => {
      if (!pair.start_time) return;
      
      const startDate = new Date(pair.start_time);
      const dayKey = `${startDate.getFullYear()}-${(startDate.getMonth()+1).toString().padStart(2,'0')}-${startDate.getDate().toString().padStart(2,'0')}`;
      
      if (!dayData[dayKey]) return;
      
      const day = dayData[dayKey];
      
      // Erstelle einen Arbeitsblock für diesen Pair
      const workBlock = {};
      
      if (pair.end_time) {
        // Abgeschlossener Arbeitstag
        // WICHTIG: DB speichert lokale Zeit als UTC
        // Wir müssen die UTC-Komponenten direkt als lokale Zeit interpretieren
        let workStartUTC = new Date(pair.start_time);
        let workEndUTC = new Date(pair.end_time);
        
        // Prüfe auf Timefix-Korrekturen
        const startFix = timefixMap.get(pair.id)?.find(f => f.fix_type === 'start work');
        const endFixEntry = allEntries.find(e => {
          const action = (typeof e.state === 'string' ? JSON.parse(e.state) : e.state)?.action || e.state;
          return action === 'stop work' && e.relatedTo_id === pair.id;
        }); 
        const endFix = endFixEntry ? timefixMap.get(endFixEntry.id)?.find(f => f.fix_type === 'stop work') : null;
        
        // Verwende korrigierte Zeiten falls vorhanden
        const originalStartTime = workStartUTC;
        const originalEndTime = workEndUTC;
        
        if (startFix) {
          // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation
          const fixTime = typeof startFix.fix_date_time === 'string' 
            ? startFix.fix_date_time.replace(' ', 'T') + 'Z'
            : startFix.fix_date_time;
          workStartUTC = new Date(fixTime);
        }
        if (endFix) {
          // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation
          const fixTime = typeof endFix.fix_date_time === 'string'
            ? endFix.fix_date_time.replace(' ', 'T') + 'Z'
            : endFix.fix_date_time;
          workEndUTC = new Date(fixTime);
        }
        
        // Parse Zeit-String (YYYY-MM-DD HH:MM:SS) direkt
        // tstamp ist jetzt ein String durch typeCast
        const parseTimeString = (timeStr) => {
          if (typeof timeStr === 'string') {
            const parts = timeStr.split(' ')[1]; // "HH:MM:SS"
            const [h, m] = parts.split(':').map(Number);
            return { hours: h, minutes: m };
          }
          // Fallback für Date-Objekte (sollte nicht mehr vorkommen)
          return { hours: timeStr.getHours(), minutes: timeStr.getMinutes() };
        };
        
        // Verwende korrigierte Zeiten für die Anzeige
        const start = parseTimeString(startFix ? workStartUTC : pair.start_time);
        const end = parseTimeString(endFix ? workEndUTC : pair.end_time);
        const startHours = start.hours;
        const startMinutes = start.minutes;
        const endHours = end.hours;
        const endMinutes = end.minutes;
        
        // Original-Zeiten für Tooltip
        const origStart = parseTimeString(originalStartTime);
        const origEnd = parseTimeString(originalEndTime);
        const originalStartHours = origStart.hours;
        const originalStartMinutes = origStart.minutes;
        const originalEndHours = origEnd.hours;
        const originalEndMinutes = origEnd.minutes;
        
        // Berechne Arbeitszeit (Dauer bleibt gleich, da beide gleich verschoben sind)
        const workStartMs = typeof pair.start_time === 'string' ? new Date(pair.start_time).getTime() : workStartUTC.getTime();
        const workEndMs = typeof pair.end_time === 'string' ? new Date(pair.end_time).getTime() : workEndUTC.getTime();
        const workDuration = workEndMs - workStartMs;
        const workHours = Math.floor(workDuration / (1000 * 60 * 60));
        const workMinutes = Math.floor((workDuration % (1000 * 60 * 60)) / (1000 * 60));
        
        workBlock.workTime = `${startHours.toString().padStart(2,'0')}:${startMinutes.toString().padStart(2,'0')} - ${endHours.toString().padStart(2,'0')}:${endMinutes.toString().padStart(2,'0')}`;
        workBlock.totalWorkTime = `${workHours}:${workMinutes.toString().padStart(2, '0')}`;
        workBlock.workTimeFixed = !!(startFix || endFix);
        
        if (startFix || endFix) {
          workBlock.workTimeOriginal = `${originalStartHours.toString().padStart(2,'0')}:${originalStartMinutes.toString().padStart(2,'0')} - ${originalEndHours.toString().padStart(2,'0')}:${originalEndMinutes.toString().padStart(2,'0')}`;
        }
        
        // Berechne Pausen NUR für diesen spezifischen Arbeitsblock
        // Finde alle Einträge, die zu diesem pair.id gehören (über relatedTo_id)
        const blockEntries = allEntries.filter(e => {
          // Parse state if it's a JSON string
          let state = e.state;
          if (typeof state === 'string') {
            try {
              state = JSON.parse(state);
            } catch (err) {
              // state bleibt als String
            }
          }
          
          const action = state?.action || state;
          
          // Einträge gehören zum Block wenn:
          // 1. Sie start/stop pause sind UND ihr relatedTo_id auf pair.id zeigt (direkt oder indirekt)
          // 2. Oder sie stop work sind mit relatedTo_id = pair.id
          
          if (action === 'start pause' && e.relatedTo_id === pair.id) {
            return true; // Pause gehört zu diesem Arbeitsblock
          }
          
          if (action === 'stop pause') {
            // Finde das zugehörige start pause
            const startPause = allEntries.find(sp => {
              const spState = typeof sp.state === 'string' ? JSON.parse(sp.state) : sp.state;
              const spAction = spState?.action || spState;
              return spAction === 'start pause' && sp.id === e.relatedTo_id;
            });
            
            if (startPause && startPause.relatedTo_id === pair.id) {
              return true; // Stop pause gehört zu einem start pause, das zu diesem Block gehört
            }
          }
          
          return false;
        });
        
        // Finde Pausen-Paare NUR für diesen Block
        const pausePairs = [];
        const pauseStarts = {};
        
        blockEntries.forEach(entry => {
          // Parse state if it's a JSON string
          let state = entry.state;
          if (typeof state === 'string') {
            try {
              state = JSON.parse(state);
            } catch (e) {
              // state bleibt als String
            }
          }
          
          const action = state?.action || state;
          
          if (action === 'start pause') {
            pauseStarts[entry.id] = entry;
          } else if (action === 'stop pause' && entry.relatedTo_id) {
            const startPause = pauseStarts[entry.relatedTo_id];
            if (startPause) {
              // Verwende die tatsächlichen Zeitwerte
              let pStartTime = startPause.tstamp;
              let pEndTime = entry.tstamp;
              
              // Prüfe auf Timefix-Korrekturen
              const pauseStartFix = timefixMap.get(startPause.id)?.find(f => f.fix_type === 'start pause');
              const pauseEndFix = timefixMap.get(entry.id)?.find(f => f.fix_type === 'stop pause');
              
              const originalPStartTime = pStartTime;
              const originalPEndTime = pEndTime;
              
              if (pauseStartFix) {
                // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation
                pStartTime = typeof pauseStartFix.fix_date_time === 'string'
                  ? pauseStartFix.fix_date_time.replace(' ', 'T') + 'Z'
                  : pauseStartFix.fix_date_time;
              }
              if (pauseEndFix) {
                // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation
                pEndTime = typeof pauseEndFix.fix_date_time === 'string'
                  ? pauseEndFix.fix_date_time.replace(' ', 'T') + 'Z'
                  : pauseEndFix.fix_date_time;
              }
              
              // Berechne Dauer (aus Strings)
              const pStartMs = new Date(pStartTime).getTime();
              const pEndMs = new Date(pEndTime).getTime();
              const duration = pEndMs - pStartMs;
              
              // Parse Pausen-Zeiten
              const pStart = parseTimeString(pStartTime);
              const pEnd = parseTimeString(pEndTime);
              const pStartHours = pStart.hours;
              const pStartMinutes = pStart.minutes;
              const pEndHours = pEnd.hours;
              const pEndMinutes = pEnd.minutes;
              
              const pauseData = {
                start: `${pStartHours.toString().padStart(2,'0')}:${pStartMinutes.toString().padStart(2,'0')}`,
                end: `${pEndHours.toString().padStart(2,'0')}:${pEndMinutes.toString().padStart(2,'0')}`,
                duration: duration,
                fixed: !!(pauseStartFix || pauseEndFix)
              };
              
              if (pauseStartFix || pauseEndFix) {
                const origStart = parseTimeString(originalPStartTime);
                const origEnd = parseTimeString(originalPEndTime);
                pauseData.original = `${origStart.hours.toString().padStart(2,'0')}:${origStart.minutes.toString().padStart(2,'0')} - ${origEnd.hours.toString().padStart(2,'0')}:${origEnd.minutes.toString().padStart(2,'0')}`;
              }
              
              pausePairs.push(pauseData);
              
              delete pauseStarts[entry.relatedTo_id];
            }
          }
        });
        
        // Berechne Pausenzeiten mit Korrektur-Informationen
        workBlock.pauses = pausePairs.map(p => ({
          time: `${p.start} - ${p.end}`,
          fixed: p.fixed,
          original: p.original
        }));
        
        workBlock.pauseTimes = pausePairs.map(p => {
          const pauseMinutes = Math.floor(p.duration / (1000 * 60));
          const pH = Math.floor(pauseMinutes / 60);
          const pM = pauseMinutes % 60;
          return {
            time: `${pH}:${pM.toString().padStart(2, '0')}`,
            fixed: p.fixed,
            original: p.original
          };
        });
        
        const totalPauseDuration = pausePairs.reduce((sum, p) => sum + p.duration, 0);
        const netWorkDuration = workDuration - totalPauseDuration;
        const netHours = Math.floor(netWorkDuration / (1000 * 60 * 60));
        const netMinutes = Math.floor((netWorkDuration % (1000 * 60 * 60)) / (1000 * 60));
        
        workBlock.netWorkTime = `${netHours}:${netMinutes.toString().padStart(2, '0')}`;
        workBlock.completed = true;
        
        // Füge Arbeitsblock zum Tag hinzu
        day.workBlocks.push(workBlock);
        
        // Für Kompatibilität: Setze auch die alten Felder (letzter Block)
        day.workTime = workBlock.workTime;
        day.workTimeFixed = workBlock.workTimeFixed;
        day.workTimeOriginal = workBlock.workTimeOriginal;
        day.pauses = workBlock.pauses;
        day.totalWorkTime = workBlock.totalWorkTime;
        day.pauseTimes = workBlock.pauseTimes;
        day.netWorkTime = workBlock.netWorkTime;
        day.status = 'complete';
        day.statusText = 'Abgeschlossen';
      } else {
        // Laufender Arbeitstag
        
        // Prüfe auf Timefix-Korrektur für Start
        const startFix = timefixMap.get(pair.id)?.find(f => f.fix_type === 'start work');
        
        const parseTimeString = (timeStr) => {
          if (typeof timeStr === 'string') {
            const parts = timeStr.split(' ')[1]; // "HH:MM:SS"
            const [h, m] = parts.split(':').map(Number);
            return { hours: h, minutes: m };
          }
          // Fallback für Date-Objekte (sollte nicht mehr vorkommen)
          return { hours: timeStr.getHours(), minutes: timeStr.getMinutes() };
        };
        
        // Verwende korrigierte Zeit falls vorhanden
        let displayStartTime = pair.start_time;
        if (startFix) {
          // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation
          const fixTime = typeof startFix.fix_date_time === 'string'
            ? startFix.fix_date_time.replace(' ', 'T') + 'Z'
            : startFix.fix_date_time;
          displayStartTime = new Date(fixTime);
        }
        
        const start = parseTimeString(displayStartTime);
        const startHours = start.hours;
        const startMinutes = start.minutes;
        
        workBlock.workTime = `${startHours.toString().padStart(2,'0')}:${startMinutes.toString().padStart(2,'0')} - jetzt`;
        workBlock.workTimeFixed = !!startFix;
        workBlock.completed = false;
        
        if (startFix) {
          // Original-Zeit für Tooltip
          const origStart = parseTimeString(pair.start_time);
          workBlock.workTimeOriginal = `${origStart.hours.toString().padStart(2,'0')}:${origStart.minutes.toString().padStart(2,'0')} - jetzt`;
        }
        
        // Prüfe auf Pausen NUR für diesen laufenden Arbeitsblock
        const blockEntries = allEntries.filter(e => {
          // Parse state if it's a JSON string
          let state = e.state;
          if (typeof state === 'string') {
            try {
              state = JSON.parse(state);
            } catch (err) {
              // state bleibt als String
            }
          }
          
          const action = state?.action || state;
          
          // Einträge gehören zum Block wenn:
          // 1. Sie start/stop pause sind UND ihr relatedTo_id auf pair.id zeigt (direkt oder indirekt)
          
          if (action === 'start pause' && e.relatedTo_id === pair.id) {
            return true; // Pause gehört zu diesem Arbeitsblock
          }
          
          if (action === 'stop pause') {
            // Finde das zugehörige start pause
            const startPause = allEntries.find(sp => {
              const spState = typeof sp.state === 'string' ? JSON.parse(sp.state) : sp.state;
              const spAction = spState?.action || spState;
              return spAction === 'start pause' && sp.id === e.relatedTo_id;
            });
            
            if (startPause && startPause.relatedTo_id === pair.id) {
              return true; // Stop pause gehört zu einem start pause, das zu diesem Block gehört
            }
          }
          
          return false;
        });
        
        // Finde laufende Pause
        const pauseStarts = {};
        const pausePairs = [];
        
        blockEntries.forEach(entry => {
          let state = entry.state;
          if (typeof state === 'string') {
            try {
              state = JSON.parse(state);
            } catch (e) {
              // ignore
            }
          }
          
          const action = state?.action || state;
          
          if (action === 'start pause') {
            pauseStarts[entry.id] = entry;
          } else if (action === 'stop pause' && entry.relatedTo_id) {
            const startPause = pauseStarts[entry.relatedTo_id];
            if (startPause) {
              // Abgeschlossene Pause
              const pStartUTC = new Date(startPause.tstamp);
              const pEndUTC = new Date(entry.tstamp);
              const duration = pEndUTC.getTime() - pStartUTC.getTime();
              
              const pStart = parseTimeString(startPause.tstamp);
              const pEnd = parseTimeString(entry.tstamp);
              const pStartHours = pStart.hours;
              const pStartMinutes = pStart.minutes;
              const pEndHours = pEnd.hours;
              const pEndMinutes = pEnd.minutes;
              
              pausePairs.push({
                start: `${pStartHours.toString().padStart(2,'0')}:${pStartMinutes.toString().padStart(2,'0')}`,
                end: `${pEndHours.toString().padStart(2,'0')}:${pEndMinutes.toString().padStart(2,'0')}`,
                duration: duration,
                fixed: false
              });
              
              delete pauseStarts[entry.relatedTo_id]; // Lösche das START pause, nicht das STOP pause
            }
          }
        });
        
        // Füge laufende Pausen hinzu
        Object.values(pauseStarts).forEach(startPause => {
          const parseTimeString = (timeStr) => {
            if (typeof timeStr === 'string') {
              const parts = timeStr.split(' ')[1];
              const [h, m] = parts.split(':').map(Number);
              return { hours: h, minutes: m };
            }
            // Fallback für Date-Objekte (sollte nicht mehr vorkommen)
            return { hours: timeStr.getHours(), minutes: timeStr.getMinutes() };
          };
          
          const pStart = parseTimeString(startPause.tstamp);
          const pStartHours = pStart.hours;
          const pStartMinutes = pStart.minutes;
          
          pausePairs.push({
            start: `${pStartHours.toString().padStart(2,'0')}:${pStartMinutes.toString().padStart(2,'0')}`,
            end: 'läuft',
            duration: null,
            fixed: false,
            running: true
          });
        });
        
        // Setze Pausen-Daten für diesen Block
        workBlock.pauses = pausePairs.map(p => ({
          time: p.end === 'läuft' ? `${p.start} - jetzt` : `${p.start} - ${p.end}`,
          fixed: p.fixed,
          running: p.running
        }));
        
        workBlock.pauseTimes = pausePairs.filter(p => p.duration).map(p => {
          const pauseMinutes = Math.floor(p.duration / (1000 * 60));
          const pH = Math.floor(pauseMinutes / 60);
          const pM = pauseMinutes % 60;
          return {
            time: `${pH}:${pM.toString().padStart(2, '0')}`,
            fixed: false
          };
        });
        
        // Füge laufenden Block zum Tag hinzu
        day.workBlocks.push(workBlock);
        
        // Für Kompatibilität: Setze auch die alten Felder (letzter Block)
        day.workTime = workBlock.workTime;
        day.pauses = workBlock.pauses;
        day.pauseTimes = workBlock.pauseTimes;
        day.status = 'running';
        day.statusText = 'Läuft';
      }
    });
    
    // Nach dem Sammeln aller Blöcke: Berechne Gesamtwerte pro Tag
    Object.values(dayData).forEach(day => {
      if (day.workBlocks.length === 0) return;
      
      // Berechne Gesamt-Arbeitszeit und -Nettozeit
      let totalWorkMinutes = 0;
      let totalNetMinutes = 0;
      
      day.workBlocks.forEach(block => {
        if (block.totalWorkTime) {
          const [h, m] = block.totalWorkTime.split(':').map(Number);
          totalWorkMinutes += h * 60 + m;
        }
        
        if (block.netWorkTime) {
          const [h, m] = block.netWorkTime.split(':').map(Number);
          totalNetMinutes += h * 60 + m;
        }
      });
      
      // Setze Gesamtwerte (für Wochensumme)
      if (totalWorkMinutes > 0) {
        const tH = Math.floor(totalWorkMinutes / 60);
        const tM = totalWorkMinutes % 60;
        day.totalWorkTime = `${tH}:${tM.toString().padStart(2, '0')}`;
      }
      
      if (totalNetMinutes > 0) {
        const nH = Math.floor(totalNetMinutes / 60);
        const nM = totalNetMinutes % 60;
        day.netWorkTime = `${nH}:${nM.toString().padStart(2, '0')}`;
      }
      
      // NICHT die Pausen auf Day-Level setzen - sie sind bereits in den Blöcken!
      // Das Frontend zeigt die Blöcke einzeln an, nicht die Tag-Level-Pausen.
      
      // Status basierend auf Blöcken
      const hasRunning = day.workBlocks.some(b => !b.completed);
      const hasCompleted = day.workBlocks.some(b => b.completed);
      
      if (hasRunning) {
        day.status = 'running';
        day.statusText = 'Läuft';
      } else if (hasCompleted) {
        day.status = 'complete';
        day.statusText = 'Abgeschlossen';
      }
    });

    // Markiere Wochenenden, integriere Urlaub, Krankheit und Feiertage
    Object.values(dayData).forEach(day => {
      const dayOfWeek = new Date(day.date).getDay();
      
      // Sammle alle Ereignisse für diesen Tag
      const events = [];
      
      // Prüfe auf Krankheit
      const sick = sickMap.get(day.date);
      if (sick) {
        day.sick = {
          hours: 8,
          type: sick.sick_type
        };
        
        const sickLabels = {
          'self': 'Krank',
          'child': 'Kind krank',
          'parents': 'Eltern krank',
          'partner': 'Partner krank'
        };
        events.push(sickLabels[sick.sick_type] || 'Krank');
        
        // Bei Krankheit: Lösche geloggte Arbeitszeit
        day.workTime = null;
        day.pauses = [];
        day.totalWorkTime = null;
        day.pauseTimes = [];
        day.netWorkTime = null;
      }
      
      // Prüfe auf Feiertag
      const holiday = holidayMap.get(day.date);
      if (holiday) {
        day.holiday = {
          hours: holiday.hours,
          description: holiday.description
        };
        events.push(holiday.description || 'Feiertag');
      }
      
      // Prüfe auf Urlaub
      const vacation = vacationMap.get(day.date);
      if (vacation) {
        const isHalfDay = vacation.half_day === 1;
        const vacationHours = isHalfDay ? 4 : 8;
        
        day.vacation = {
          hours: vacationHours,
          halfDay: isHalfDay
        };
        events.push(isHalfDay ? 'Urlaub (halber Tag)' : 'Urlaub');
      }
      
      // Prüfe auf Wochenende
      const isWeekend = (dayOfWeek === 0 || dayOfWeek === 6);
      if (isWeekend) {
        events.push('Wochenende');
      }
      
      // Setze Status basierend auf gesammelten Ereignissen
      if (events.length > 0) {
        if (day.workTime) {
          // Ereignis(se) + Arbeit
          day.statusText = events.join(' + ') + ' + Arbeit';
          day.status = 'mixed-work';
        } else {
          // Nur Ereignis(se), keine Arbeit
          day.statusText = events.join(' + ');
          // Status basierend auf primärem Ereignis
          if (sick) {
            day.status = 'sick';
          } else if (holiday) {
            day.status = 'holiday';
          } else if (vacation) {
            day.status = vacation.halfDay ? 'vacation-half' : 'vacation-full';
          } else if (isWeekend) {
            day.status = 'weekend';
          }
        }
      } else if (isWeekend) {
        // Nur Wochenende, keine anderen Events
        day.status = 'weekend';
        day.statusText = 'Wochenende';
      }
    });

    // Berechne Wochensumme (Arbeit + Urlaub + Krankheit + Feiertage)
    let totalMinutes = 0;
    Object.values(dayData).forEach(day => {
      // Krankheitsstunden (haben Vorrang)
      if (day.sick) {
        totalMinutes += day.sick.hours * 60;
      } else {
        // Nettoarbeitszeit
        if (day.netWorkTime) {
          const [hours, minutes] = day.netWorkTime.split(':').map(Number);
          totalMinutes += hours * 60 + minutes;
        }
        
        // Feiertagsstunden
        if (day.holiday) {
          totalMinutes += day.holiday.hours * 60;
        }
        
        // Urlaubsstunden
        if (day.vacation) {
          totalMinutes += day.vacation.hours * 60;
        }
      }
    });
    
    const weekTotalHours = Math.floor(totalMinutes / 60);
    const weekTotalMinutes = totalMinutes % 60;
    const weekTotal = `${weekTotalHours}:${weekTotalMinutes.toString().padStart(2, '0')}`;

    // Berechne nur die Arbeitszeit (ohne arbeitsfreie Tage)
    let workMinutes = 0;
    Object.values(dayData).forEach(day => {
      if (day.netWorkTime && !day.vacation && !day.sick && !day.holiday) {
        const [hours, minutes] = day.netWorkTime.split(':').map(Number);
        workMinutes += hours * 60 + minutes;
      }
    });

    const workHours = Math.floor(workMinutes / 60);
    const workMins = workMinutes % 60;
    const workTotal = `${workHours}:${workMins.toString().padStart(2, '0')}`;

    // Berechne arbeitsfreie Stunden für die Woche (separat für Anzeige)
    let nonWorkingMinutes = 0;
    let nonWorkingDays = 0;
    const nonWorkingDetails = [];

    Object.values(dayData).forEach(day => {
      if (day.vacation && day.vacation.hours > 0) {
        nonWorkingMinutes += day.vacation.hours * 60;
        nonWorkingDays++;
        nonWorkingDetails.push({
          date: day.date,
          type: 'Urlaub',
          hours: day.vacation.hours
        });
      }
      if (day.sick && day.sick.hours > 0) {
        nonWorkingMinutes += day.sick.hours * 60;
        nonWorkingDays++;
        nonWorkingDetails.push({
          date: day.date,
          type: 'Krankheit',
          hours: day.sick.hours
        });
      }
      if (day.holiday && day.holiday.hours > 0) {
        nonWorkingMinutes += day.holiday.hours * 60;
        nonWorkingDays++;
        nonWorkingDetails.push({
          date: day.date,
          type: 'Feiertag',
          hours: day.holiday.hours
        });
      }
    });

    const nonWorkingHours = Math.floor(nonWorkingMinutes / 60);
    const nonWorkingMins = nonWorkingMinutes % 60;
    const nonWorkingTotal = `${nonWorkingHours}:${nonWorkingMins.toString().padStart(2, '0')}`;

    // Gesamtsumme = Arbeitszeit + arbeitsfreie Zeit
    const totalAllMinutes = workMinutes + nonWorkingMinutes;
    const totalAllHours = Math.floor(totalAllMinutes / 60);
    const totalAllMins = totalAllMinutes % 60;
    const totalAll = `${totalAllHours}:${totalAllMins.toString().padStart(2, '0')}`;

    return {
      weekStart: weekStart.toISOString().split('T')[0],
      weekEnd: weekEnd.toISOString().split('T')[0],
      weekOffset,
      days: Object.values(dayData).sort((a, b) => a.date.localeCompare(b.date)),
      weekTotal: workTotal, // Nur Arbeitszeit
      nonWorkingTotal,
      nonWorkingDays,
      nonWorkingDetails,
      totalAll // Arbeitszeit + arbeitsfreie Zeit
    };
  }

  /**
   * Aktuellen Status/Zustand des Benutzers abrufen
   * @param {number} userId - Benutzer-ID
   * @returns {Promise<string|null>} Letzter Action-Status oder null
   */
  async getCurrentState(userId) {
    const uid = userId || this.defaultUserId;
    
    // Hole letzten Worklog-Eintrag (inkl. Timefix-Korrekturen)
    const lastEntry = await worklogRepository.findLatestByUser(uid);
    
    if (!lastEntry) {
      return null;
    }
    
    // Parse state
    let state = lastEntry.state;
    if (typeof state === 'string') {
      try {
        state = JSON.parse(state);
      } catch (e) {
        // state bleibt als String
      }
    }
    
    const action = state?.action || state;
    
    // Prüfe auf Timefix-Korrektur für diesen Eintrag
    const timefixMap = await worklogRepository.getTimefixesByWorklogIds([lastEntry.id]);
    const timefix = timefixMap.get(lastEntry.id)?.[0];
    
    if (timefix) {
      // Verwende korrigierten Action-Typ
      return timefix.fix_type;
    }
    
    return action;
  }

  /**
   * Stempeln (Clock-Aktion durchführen)
   * @param {number} userId - Benutzer-ID
   * @param {string} action - Aktion: 'start work', 'stop work', 'start pause', 'stop pause'
   * @returns {Promise<Object>} Erstellter Worklog-Eintrag
   */
  async clock(userId, action) {
    const uid = userId || this.defaultUserId;
    
    // Validiere Action
    const validActions = ['start work', 'stop work', 'start pause', 'stop pause'];
    if (!validActions.includes(action)) {
      throw new Error('Ungültige Aktion');
    }
    
    // Hole aktuellen Status
    const currentState = await this.getCurrentState(uid);
    
    // Validiere State-Transition
    const isValidTransition = this._validateTransition(currentState, action);
    if (!isValidTransition) {
      throw new Error(`Ungültiger Übergang: ${currentState} -> ${action}`);
    }
    
    // Erstelle Worklog-Eintrag
    const relatedToId = await this._getRelatedToId(currentState, action, uid);
    
    // Die DB speichert UTC-Zeit (ohne TZ-Info im String)
    // Format: YYYY-MM-DD HH:MM:SS (immer UTC)
    // Das Frontend konvertiert dann zu lokaler Zeit für die Anzeige
    const now = new Date();
    
    const year = now.getUTCFullYear();
    const month = String(now.getUTCMonth() + 1).padStart(2, '0');
    const day = String(now.getUTCDate()).padStart(2, '0');
    const hours = String(now.getUTCHours()).padStart(2, '0');
    const minutes = String(now.getUTCMinutes()).padStart(2, '0');
    const seconds = String(now.getUTCSeconds()).padStart(2, '0');
    const utcTimeString = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    
    const entry = await worklogRepository.create({
      user_id: uid,
      state: action, // Speichere nur den Action-String, nicht als JSON
      tstamp: utcTimeString, // UTC-Zeit als String
      relatedTo_id: relatedToId
    });
    
    return entry;
  }

  /**
   * Validiert ob eine State-Transition erlaubt ist
   * @private
   */
  _validateTransition(currentState, newAction) {
    const transitions = {
      'null': ['start work'],
      'stop work': ['start work'],
      'start work': ['stop work', 'start pause'],
      'stop pause': ['stop work', 'start pause'],
      'start pause': ['stop pause']
    };
    
    const allowedActions = transitions[currentState || 'null'] || [];
    return allowedActions.includes(newAction);
  }

  /**
   * Ermittelt die relatedTo_id für einen neuen Eintrag
   * @private
   */
  async _getRelatedToId(currentState, newAction, userId) {
    if (newAction === 'start work') {
      return null; // Start work hat keine Referenz
    }
    
    // stop work und stop pause referenzieren den entsprechenden Start
    if (newAction === 'stop work') {
      // Finde letzten 'start work' ohne 'stop work'
      return await this._findLastUnpairedStart(userId, 'start work');
    }
    
    if (newAction === 'stop pause') {
      // Finde letzten 'start pause' ohne 'stop pause'
      return await this._findLastUnpairedStart(userId, 'start pause');
    }
    
    if (newAction === 'start pause') {
      // start pause referenziert den laufenden 'start work'
      return await this._findLastUnpairedStart(userId, 'start work');
    }
    
    return null;
  }

  /**
   * Findet den letzten Start-Eintrag ohne passendes End
   * @private
   */
  async _findLastUnpairedStart(userId, startAction) {
    const allEntries = await worklogRepository.findByUser(userId);
    
    // Finde den letzten Start ohne Stop
    for (let i = allEntries.length - 1; i >= 0; i--) {
      const entry = allEntries[i];
      let state = entry.state;
      
      if (typeof state === 'string') {
        try {
          state = JSON.parse(state);
        } catch (e) {
          // ignore - state bleibt als String
        }
      }
      
      const action = state?.action || state;
      
      if (action === startAction) {
        // Prüfe ob es einen passenden Stop gibt
        // WICHTIG: Nur nach dem entsprechenden STOP-Action suchen, nicht nach Pausen!
        const stopAction = startAction === 'start work' ? 'stop work' : 'stop pause';
        
        const hasStop = allEntries.some(e => {
          // Parse state für diesen Eintrag
          let eState = e.state;
          if (typeof eState === 'string') {
            try {
              eState = JSON.parse(eState);
            } catch (err) {
              // ignore
            }
          }
          const eAction = eState?.action || eState;
          
          // Prüfe ob dieser Eintrag ein STOP ist, der auf unseren START zeigt
          return eAction === stopAction && e.relatedTo_id === entry.id;
        });
        
        if (!hasStop) {
          return entry.id;
        }
      }
    }
    
    return null;
  }

  /**
   * Hilfsmethode: Wochentag-Namen
   * @private
   * @param {number} dayOfWeek - 0 = Sonntag, 1 = Montag, ..., 6 = Samstag
   */
  _getDayName(dayOfWeek) {
    const days = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
    return days[dayOfWeek];
  }

  /**
   * Aktuell laufenden Timer abrufen
   * @param {number} userId - Benutzer-ID (optional)
   * @returns {Promise<Object|null>} Der laufende Zeiteintrag oder null
   */
  async getRunningEntry(userId = null) {
    const uid = userId || this.defaultUserId;
    
    // Hole letzten Eintrag
    const lastEntry = await worklogRepository.findLatestByUser(uid);
    
    if (!lastEntry) {
      return null;
    }
    
    // Parse state
    let state = lastEntry.state;
    if (typeof state === 'string') {
      try {
        state = JSON.parse(state);
      } catch (e) {
        // state bleibt als String
      }
    }
    
    const action = state?.action || state;
    
    // Wenn letzter Eintrag "stop work" oder null ist, läuft nichts
    if (!action || action === 'stop work') {
      return null;
    }
    
    // Finde den zugehörigen "start work"
    const startWorkId = await this._findLastUnpairedStart(uid, 'start work');
    
    if (!startWorkId) {
      return null;
    }
    
    // Hole alle Einträge seit dem Start
    const allEntries = await worklogRepository.findByUser(uid);
    const startWorkEntry = allEntries.find(e => e.id === startWorkId);
    
    if (!startWorkEntry) {
      return null;
    }
    
    // Sammle alle abgeschlossenen Pausen
    const pauseDurations = [];
    let currentPauseStart = null;
    
    // Finde alle Pausen-Paare
    const relevantEntries = allEntries.filter(e => {
      const eDate = new Date(e.tstamp);
      const startDate = new Date(startWorkEntry.tstamp);
      return eDate >= startDate;
    });
    
     
    const pauseStarts = {};
    
    // Hole Timefixes für alle relevanten Einträge (inklusive Pausen)
    const allEntryIds = relevantEntries.map(e => e.id);
    const pauseTimefixMap = await worklogRepository.getTimefixesByWorklogIds(allEntryIds);
    
    relevantEntries.forEach(entry => {
      let eState = entry.state;
      if (typeof eState === 'string') {
        try {
          eState = JSON.parse(eState);
        } catch (e) {
          // ignore
        }
      }
      
      const eAction = eState?.action || eState;
      
      if (eAction === 'start pause') {
        pauseStarts[entry.id] = entry;
      } else if (eAction === 'stop pause' && entry.relatedTo_id) {
        const startPause = pauseStarts[entry.relatedTo_id];
        if (startPause) {
          // Prüfe auf Timefix-Korrekturen für Pausen
          const pauseStartFix = pauseTimefixMap.get(startPause.id)?.find(f => f.fix_type === 'start pause');
          const pauseEndFix = pauseTimefixMap.get(entry.id)?.find(f => f.fix_type === 'stop pause');
          
          // Verwende korrigierte Zeiten falls vorhanden
          const pStartTime = pauseStartFix?.fix_date_time || startPause.tstamp;
          const pEndTime = pauseEndFix?.fix_date_time || entry.tstamp;
          
          const duration = new Date(pEndTime).getTime() - new Date(pStartTime).getTime();
          pauseDurations.push(duration);
          delete pauseStarts[entry.relatedTo_id];
        }
      }
    });
    
    // Wenn noch ein pauseStart übrig ist, ist das die laufende Pause
    const runningPauseIds = Object.keys(pauseStarts);
    if (runningPauseIds.length > 0) {
      const pauseId = parseInt(runningPauseIds[0]);
      const pauseEntry = pauseStarts[pauseId];
      
      // Prüfe auf Timefix-Korrektur für laufende Pause
      const currentPauseTimefix = pauseTimefixMap.get(pauseId)?.find(f => f.fix_type === 'start pause');
      currentPauseStart = currentPauseTimefix?.fix_date_time || pauseEntry.tstamp;
    }

    // Prüfe auf Timefix-Korrektur für die Start-Zeit (timefixMap bereits geholt in pauseTimefixMap)
    const startTimefix = pauseTimefixMap.get(startWorkId)?.find(f => f.fix_type === 'start work');
    
    let displayStartTime = startWorkEntry.tstamp;
    if (startTimefix && startTimefix.fix_date_time) {
      // Verwende korrigierte Zeit
      displayStartTime = startTimefix.fix_date_time;
    }
    
    // Stelle sicher, dass startTime ein String ist (kein Date-Objekt)
    // Konvertiere UTC zu lokaler Zeit für Frontend
    let startTimeStr;
    if (typeof displayStartTime === 'string') {
      // Wenn es ein UTC-String ist, konvertiere zu lokaler Zeit
      const utcDate = new Date(displayStartTime);
      const year = utcDate.getFullYear();
      const month = String(utcDate.getMonth() + 1).padStart(2, '0');
      const day = String(utcDate.getDate()).padStart(2, '0');
      const hours = String(utcDate.getHours()).padStart(2, '0');
      const minutes = String(utcDate.getMinutes()).padStart(2, '0');
      const seconds = String(utcDate.getSeconds()).padStart(2, '0');
      startTimeStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    } else {
      startTimeStr = displayStartTime.toISOString();
    }
    
    // Stelle sicher, dass currentPauseStart auch ein String ist
    const currentPauseStartStr = currentPauseStart 
      ? (typeof currentPauseStart === 'string' ? currentPauseStart : currentPauseStart.toISOString())
      : null;

    const result = {
      id: startWorkId,
      startTime: startTimeStr, // Explizit als String
      endTime: null,
      description: (state?.description || ''),
      project: (state?.project || 'Allgemein'),
      duration: null,
      isRunning: true,
      userId: uid,
      pauses: pauseDurations,
      currentPauseStart: currentPauseStartStr
    };
    
    return result;
  }

  /**
   * Alle Einträge nach Projekt filtern
   * @param {string} projectName - Name des Projekts
   * @param {number} userId - Benutzer-ID (optional)
   * @returns {Promise<Array>} Gefilterte Liste der Zeiteinträge
   */
  async getEntriesByProject(projectName, userId = null) {
    const uid = userId || this.defaultUserId;
    const pairs = await worklogRepository.findPairsByUser(uid);
    const safePairs = Array.isArray(pairs) ? pairs : [];
    
    return safePairs
      .map(pair => this._mapWorklogPairToTimeEntry(pair))
      .filter(entry => 
        entry.project.toLowerCase() === projectName.toLowerCase()
      );
  }

  /**
   * Alle Einträge in einem Datumsbereich abrufen
   * @param {Date} startDate - Startdatum
   * @param {Date} endDate - Enddatum
   * @param {number} userId - Benutzer-ID (optional)
   * @returns {Promise<Array>} Gefilterte Liste der Zeiteinträge
   */
  async getEntriesByDateRange(startDate, endDate, userId = null) {
    const uid = userId || this.defaultUserId;
    const worklogs = await worklogRepository.findByDateRange(uid, startDate, endDate);
    
    // Zu Paaren gruppieren
    const pairs = [];
    const startEntries = worklogs.filter(w => w.relatedTo_id === null);
    
    for (const start of startEntries) {
      const end = worklogs.find(w => w.relatedTo_id === start.id);
      
      let duration = null;
      if (end) {
        const startTime = new Date(start.tstamp);
        const endTime = new Date(end.tstamp);
        duration = Math.floor((endTime - startTime) / 1000);
      }

      pairs.push({
        start_id: start.id,
        start_time: start.tstamp,
        start_state: start.state,
        end_id: end ? end.id : null,
        end_time: end ? end.tstamp : null,
        end_state: end ? end.state : null,
        duration
      });
    }

    return pairs.map(pair => this._mapWorklogPairToTimeEntry(pair));
  }

  /**
   * Worklog-Paar zu TimeEntry-Format konvertieren (privat)
   * @private
   */
  _mapWorklogPairToTimeEntry(pair) {
    let startStateData, endStateData;
    
    try {
      startStateData = JSON.parse(pair.start_state);
    } catch {
      startStateData = { project: 'Allgemein', description: '' };
    }

    try {
      endStateData = pair.end_state ? JSON.parse(pair.end_state) : null;
    } catch {
      endStateData = null;
    }

    return {
      id: pair.start_id,
      startTime: pair.start_time,
      endTime: pair.end_time || null,
      description: (endStateData && endStateData.description) || startStateData.description || '',
      project: (endStateData && endStateData.project) || startStateData.project || 'Allgemein',
      duration: pair.duration || null,
      isRunning: !pair.end_time,
      userId: null // Wird vom Repository nicht zurückgegeben im Pair
    };
  }
}

// Singleton-Instanz exportieren
module.exports = new TimeEntryService();
