const database = require('../config/database');
const { Op } = require('sequelize');

/**
 * Service-Klasse für Daten-Export
 * Exportiert Arbeitszeiten in verschiedenen Formaten
 */
class ExportService {
  /**
   * Exportiert Daten als CSV
   * Format: Datum;Uhrzeit;Aktivität;Gesamt-Netto-Arbeitszeit
   * @param {number} userId - User-ID
   * @param {string} startDate - Startdatum (YYYY-MM-DD)
   * @param {string} endDate - Enddatum (YYYY-MM-DD)
   * @returns {Promise<string>} CSV-String
   */
  async exportCSV(userId, startDate, endDate) {
    const data = await this._getExportData(userId, startDate, endDate);
    
    // CSV Header
    let csv = 'Datum;Uhrzeit;Aktivität;Gesamt-Netto-Arbeitszeit\n';
    
    // CSV Zeilen
    data.forEach(row => {
      csv += `${row.date};${row.time};${row.activity};${row.netWorkTime}\n`;
    });
    
    return csv;
  }

  /**
   * Exportiert Daten als echte Excel-Datei (.xlsx)
   * @param {number} userId - User-ID
   * @param {string} startDate - Startdatum
   * @param {string} endDate - Enddatum
   * @returns {Promise<Buffer>} Excel-Datei als Buffer
   */
  async exportExcel(userId, startDate, endDate) {
    const ExcelJS = require('exceljs');
    const data = await this._getExportData(userId, startDate, endDate);
    
    // Erstelle Workbook
    const workbook = new ExcelJS.Workbook();
    const worksheet = workbook.addWorksheet('Zeiterfassung');
    
    // Definiere Spalten
    worksheet.columns = [
      { header: 'Datum', key: 'date', width: 12 },
      { header: 'Uhrzeit', key: 'time', width: 10 },
      { header: 'Aktivität', key: 'activity', width: 20 },
      { header: 'Gesamt-Netto-Arbeitszeit', key: 'netWorkTime', width: 25 }
    ];
    
    // Style für Header
    worksheet.getRow(1).font = { bold: true };
    worksheet.getRow(1).fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FFE0E0E0' }
    };
    
    // Füge Daten hinzu
    data.forEach(row => {
      worksheet.addRow({
        date: row.date,
        time: row.time,
        activity: row.activity,
        netWorkTime: row.netWorkTime
      });
    });
    
    // Generiere Buffer
    const buffer = await workbook.xlsx.writeBuffer();
    return buffer;
  }

  /**
   * Bereitet Daten für PDF-Export vor (Wochen-Format)
   * @param {number} userId - User-ID
   * @param {string} startDate - Startdatum
   * @param {string} endDate - Enddatum
   * @returns {Promise<Object>} Strukturierte Daten für PDF
   */
  async exportPDFData(userId, startDate, endDate) {
    const TimeEntryService = require('./TimeEntryService');
    
    const start = new Date(startDate + 'T00:00:00');
    const end = new Date(endDate + 'T00:00:00');
    
    // Berechne Anzahl Wochen
    const weeks = [];
    let currentDate = new Date(start);
    
    while (currentDate <= end) {
      // Finde Montag der aktuellen Woche
      const dayOfWeek = currentDate.getDay();
      const daysToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
      const weekStart = new Date(currentDate);
      weekStart.setDate(weekStart.getDate() + daysToMonday);
      
      // Berechne Wochen-Offset
      const now = new Date();
      const nowDayOfWeek = now.getDay();
      const nowDaysToMonday = nowDayOfWeek === 0 ? -6 : 1 - nowDayOfWeek;
      const thisWeekMonday = new Date(now);
      thisWeekMonday.setDate(thisWeekMonday.getDate() + nowDaysToMonday);
      thisWeekMonday.setHours(0, 0, 0, 0);
      weekStart.setHours(0, 0, 0, 0);
      
      const weekOffset = Math.round((weekStart - thisWeekMonday) / (7 * 24 * 60 * 60 * 1000));
      
      // Hole Wochendaten
      const weekData = await TimeEntryService.getWeekOverview(userId, weekOffset);
      weeks.push(weekData);
      
      // Nächste Woche
      currentDate.setDate(currentDate.getDate() + 7);
    }
    
    return {
      startDate,
      endDate,
      weeks
    };
  }

  /**
   * Holt Export-Daten (für CSV/Excel)
   * @private
   */
  async _getExportData(userId, startDate, endDate) {
    const { Worklog, Timefix } = database.getModels();
    const sequelize = database.sequelize;
    
    // Hole alle Worklog-Einträge mit Timefix-Korrekturen
    const query = `
      SELECT 
        w.id,
        DATE(w.tstamp) as date,
        w.tstamp,
        w.state,
        w.relatedTo_id,
        COALESCE(tf.fix_date_time, w.tstamp) as corrected_time,
        COALESCE(tf.fix_type, 
          CASE 
            WHEN w.state LIKE '%start work%' THEN 'start work'
            WHEN w.state LIKE '%stop work%' THEN 'stop work'
            WHEN w.state LIKE '%start pause%' THEN 'start pause'
            WHEN w.state LIKE '%stop pause%' THEN 'stop pause'
            ELSE w.state
          END
        ) as corrected_action
      FROM worklog w
      LEFT JOIN timefix tf ON tf.worklog_id = w.id
      WHERE w.user_id = :userId
        AND DATE(w.tstamp) BETWEEN :startDate AND :endDate
      ORDER BY w.tstamp ASC
    `;
    
    const entries = await sequelize.query(query, {
      replacements: { userId, startDate, endDate },
      type: sequelize.QueryTypes.SELECT
    });
    
    // Gruppiere nach Datum und berechne Nettoarbeitszeit
    const dayMap = new Map();
    
    entries.forEach(entry => {
      if (!dayMap.has(entry.date)) {
        dayMap.set(entry.date, {
          entries: [],
          netMinutes: 0
        });
      }
      dayMap.get(entry.date).entries.push(entry);
    });
    
    // Berechne für jeden Tag
    const result = [];
    
    dayMap.forEach((dayData, date) => {
      const dayEntries = dayData.entries;
      let netMinutes = 0;
      
      // Finde alle start work -> stop work Paare
      dayEntries.forEach(entry => {
        const action = entry.corrected_action;
        
        if (action === 'stop work') {
          const startEntry = dayEntries.find(e => e.id === entry.relatedTo_id);
          
          if (startEntry) {
            const start = new Date(startEntry.corrected_time);
            const end = new Date(entry.corrected_time);
            const workMinutes = (end - start) / (1000 * 60);
            
            // Subtrahiere Pausen
            const pauses = dayEntries.filter(e => 
              new Date(e.corrected_time) > start && 
              new Date(e.corrected_time) < end &&
              (e.corrected_action === 'start pause' || e.corrected_action === 'stop pause')
            );
            
            let pauseMinutes = 0;
            pauses.forEach(pauseEntry => {
              if (pauseEntry.corrected_action === 'stop pause') {
                const pauseStart = pauses.find(p => p.id === pauseEntry.relatedTo_id);
                if (pauseStart) {
                  const pStart = new Date(pauseStart.corrected_time);
                  const pEnd = new Date(pauseEntry.corrected_time);
                  pauseMinutes += (pEnd - pStart) / (1000 * 60);
                }
              }
            });
            
            netMinutes += workMinutes - pauseMinutes;
          }
        }
      });
      
      // Formatiere Netto-Arbeitszeit
      const netHours = Math.floor(netMinutes / 60);
      const netMins = Math.round(netMinutes % 60);
      const netTimeFormatted = `${netHours}:${netMins.toString().padStart(2, '0')}`;
      
      // Erstelle Zeilen für alle Einträge dieses Tages
      dayEntries.forEach(entry => {
        const time = new Date(entry.corrected_time);
        const timeStr = time.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' });
        
        const activityLabels = {
          'start work': 'Arbeit gestartet',
          'stop work': 'Arbeit beendet',
          'start pause': 'Pause gestartet',
          'stop pause': 'Pause beendet'
        };
        
        result.push({
          date: new Date(date + 'T00:00:00').toLocaleDateString('de-DE'),
          time: timeStr,
          activity: activityLabels[entry.corrected_action] || entry.corrected_action,
          netWorkTime: entry.corrected_action === 'stop work' ? netTimeFormatted : ''
        });
      });
    });
    
    return result;
  }
}

module.exports = new ExportService();

