const express = require('express');
const path = require('path');
const fs = require('fs');
const Database = require('better-sqlite3');

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(express.json());
app.use(express.static('public'));

// Initialize Database
const dbPath = path.join(__dirname, 'db', 'timetracker.db');
const schemaPath = path.join(__dirname, 'db', 'schema.sql');

// Ensure db directory exists
const dbDir = path.dirname(dbPath);
if (!fs.existsSync(dbDir)) {
  fs.mkdirSync(dbDir, { recursive: true });
}

const db = new Database(dbPath);

// Create table if it doesn't exist
const schema = fs.readFileSync(schemaPath, 'utf8');
db.exec(schema);

// Migration: Add location column if it doesn't exist
try {
  const tableInfo = db.pragma('table_info(entries)');
  const hasLocationColumn = tableInfo.some(col => col.name === 'location');
  
  if (!hasLocationColumn) {
    console.log('Adding location column to entries table...');
    db.exec(`ALTER TABLE entries ADD COLUMN location TEXT DEFAULT 'office' CHECK(location IN ('office', 'home'))`);
    console.log('Location column added successfully');
  }
} catch (error) {
  console.error('Error during migration:', error);
}

console.log('Database initialized successfully');

// ============================================
// BUSINESS LOGIC: Net Hours Calculation & Caps
// ============================================

/**
 * Auto-calculate pause based on German break rules
 * @param {number} grossHours - Total work hours
 * @returns {number} - Pause in minutes
 */
function calculateAutoPause(grossHours) {
  if (grossHours > 9) {
    return 45;
  } else if (grossHours > 6) {
    return 30;
  }
  return 0;
}

/**
 * Calculate net hours with pause and 10-hour cap
 * @param {string} startTime - Format: "HH:MM"
 * @param {string} endTime - Format: "HH:MM"
 * @param {number|null} pauseMinutes - Manual pause in minutes (null for auto-calculation)
 * @returns {object} - { grossHours, pauseMinutes, netHours }
 */
function calculateNetHours(startTime, endTime, pauseMinutes = null) {
  const [startHour, startMin] = startTime.split(':').map(Number);
  const [endHour, endMin] = endTime.split(':').map(Number);
  
  const startTotalMin = startHour * 60 + startMin;
  const endTotalMin = endHour * 60 + endMin;
  
  // Handle overnight shifts
  let diffMin = endTotalMin - startTotalMin;
  if (diffMin < 0) {
    diffMin += 24 * 60; // Add 24 hours
  }
  
  const grossHours = diffMin / 60;
  
  // Calculate required minimum pause based on gross hours
  const requiredMinPause = calculateAutoPause(grossHours);
  
  // Determine actual pause to use
  let actualPause;
  if (pauseMinutes !== null && pauseMinutes !== undefined) {
    // Manual pause provided - enforce minimum
    actualPause = Math.max(pauseMinutes, requiredMinPause);
  } else {
    // No pause provided - use required minimum
    actualPause = requiredMinPause;
  }
  
  // Calculate net hours
  const netMinutes = diffMin - actualPause;
  let netHours = netMinutes / 60;
  
  // Cap at 10 hours
  if (netHours > 10) {
    netHours = 10.0;
  }
  
  return {
    grossHours: parseFloat(grossHours.toFixed(2)),
    pauseMinutes: actualPause,
    netHours: parseFloat(netHours.toFixed(2))
  };
}

// ============================================
// API ENDPOINTS
// ============================================

/**
 * GET /api/entries?from=YYYY-MM-DD&to=YYYY-MM-DD
 * Get all entries in a date range
 */
app.get('/api/entries', (req, res) => {
  try {
    const { from, to } = req.query;
    
    let query = 'SELECT * FROM entries';
    const params = [];
    
    if (from && to) {
      query += ' WHERE date >= ? AND date <= ?';
      params.push(from, to);
    } else if (from) {
      query += ' WHERE date >= ?';
      params.push(from);
    } else if (to) {
      query += ' WHERE date <= ?';
      params.push(to);
    }
    
    query += ' ORDER BY date DESC, start_time DESC';
    
    const stmt = db.prepare(query);
    const entries = stmt.all(...params);
    
    // Add calculated net hours to each entry
    const enrichedEntries = entries.map(entry => {
      const calculated = calculateNetHours(entry.start_time, entry.end_time, entry.pause_minutes);
      return {
        id: entry.id,
        date: entry.date,
        startTime: entry.start_time,
        endTime: entry.end_time,
        pauseMinutes: entry.pause_minutes,
        netHours: calculated.netHours,
        location: entry.location || 'office'
      };
    });
    
    res.json(enrichedEntries);
  } catch (error) {
    console.error('Error fetching entries:', error);
    res.status(500).json({ error: 'Failed to fetch entries' });
  }
});

/**
 * POST /api/entries
 * Create a new entry
 */
app.post('/api/entries', (req, res) => {
  try {
    const { date, startTime, endTime, pauseMinutes, location } = req.body;
    
    if (!date || !startTime || !endTime) {
      return res.status(400).json({ error: 'Missing required fields: date, startTime, endTime' });
    }
    
    // Calculate with auto-pause or use provided pause
    const calculated = calculateNetHours(startTime, endTime, pauseMinutes);
    const pause = calculated.pauseMinutes;
    const loc = location || 'office';
    
    try {
      const stmt = db.prepare('INSERT INTO entries (date, start_time, end_time, pause_minutes, location) VALUES (?, ?, ?, ?, ?)');
      const result = stmt.run(date, startTime, endTime, pause, loc);
      
      // Return the created entry with calculated fields
      const newEntry = {
        id: result.lastInsertRowid,
        date,
        startTime,
        endTime,
        pauseMinutes: pause,
        netHours: calculated.netHours,
        location: loc
      };
      
      res.status(201).json(newEntry);
    } catch (dbError) {
      // Check for UNIQUE constraint violation
      if (dbError.message.includes('UNIQUE constraint failed')) {
        return res.status(409).json({ error: 'Ein Eintrag für dieses Datum existiert bereits' });
      }
      throw dbError;
    }
  } catch (error) {
    console.error('Error creating entry:', error);
    res.status(500).json({ error: 'Failed to create entry' });
  }
});

/**
 * PUT /api/entries/:id
 * Update an existing entry
 */
app.put('/api/entries/:id', (req, res) => {
  try {
    const { id } = req.params;
    const { date, startTime, endTime, pauseMinutes, location } = req.body;
    
    if (!date || !startTime || !endTime) {
      return res.status(400).json({ error: 'Missing required fields: date, startTime, endTime' });
    }
    
    // Calculate with auto-pause or use provided pause
    const calculated = calculateNetHours(startTime, endTime, pauseMinutes);
    const pause = calculated.pauseMinutes;
    const loc = location || 'office';
    
    try {
      const stmt = db.prepare('UPDATE entries SET date = ?, start_time = ?, end_time = ?, pause_minutes = ?, location = ? WHERE id = ?');
      const result = stmt.run(date, startTime, endTime, pause, loc, id);
      
      if (result.changes === 0) {
        return res.status(404).json({ error: 'Entry not found' });
      }
      
      // Return the updated entry with calculated fields
      const updatedEntry = {
        id: parseInt(id),
        date,
        startTime,
        endTime,
        pauseMinutes: pause,
        netHours: calculated.netHours,
        location: loc
      };
      
      res.json(updatedEntry);
    } catch (dbError) {
      // Check for UNIQUE constraint violation
      if (dbError.message.includes('UNIQUE constraint failed')) {
        return res.status(409).json({ error: 'Ein Eintrag für dieses Datum existiert bereits' });
      }
      throw dbError;
    }
  } catch (error) {
    console.error('Error updating entry:', error);
    res.status(500).json({ error: 'Failed to update entry' });
  }
});

/**
 * DELETE /api/entries/:id
 * Delete an entry
 */
app.delete('/api/entries/:id', (req, res) => {
  try {
    const { id } = req.params;
    
    const stmt = db.prepare('DELETE FROM entries WHERE id = ?');
    const result = stmt.run(id);
    
    if (result.changes === 0) {
      return res.status(404).json({ error: 'Entry not found' });
    }
    
    res.json({ message: 'Entry deleted successfully' });
  } catch (error) {
    console.error('Error deleting entry:', error);
    res.status(500).json({ error: 'Failed to delete entry' });
  }
});

/**
 * GET /api/export?from=YYYY-MM-DD&to=YYYY-MM-DD
 * Export entries as CSV
 */
app.get('/api/export', (req, res) => {
  try {
    const { from, to } = req.query;
    
    let query = 'SELECT * FROM entries';
    const params = [];
    
    if (from && to) {
      query += ' WHERE date >= ? AND date <= ?';
      params.push(from, to);
    } else if (from) {
      query += ' WHERE date >= ?';
      params.push(from);
    } else if (to) {
      query += ' WHERE date <= ?';
      params.push(to);
    }
    
    query += ' ORDER BY date ASC, start_time ASC';
    
    const stmt = db.prepare(query);
    const entries = stmt.all(...params);
    
    // Generate CSV with German formatting
    let csv = 'Datum,Startzeit,Endzeit,Pause in Minuten,Gesamtstunden\n';
    
    entries.forEach(entry => {
      const calculated = calculateNetHours(entry.start_time, entry.end_time, entry.pause_minutes);
      
      // Format date as DD.MM.YYYY
      const [year, month, day] = entry.date.split('-');
      const formattedDate = `${day}.${month}.${year}`;
      
      // Use comma as decimal separator for hours
      const netHoursFormatted = calculated.netHours.toFixed(2).replace('.', ',');
      
      csv += `${formattedDate},${entry.start_time},${entry.end_time},${entry.pause_minutes},${netHoursFormatted}\n`;
    });
    
    res.setHeader('Content-Type', 'text/csv; charset=utf-8');
    res.setHeader('Content-Disposition', 'attachment; filename="zeiterfassung.csv"');
    res.send(csv);
  } catch (error) {
    console.error('Error exporting entries:', error);
    res.status(500).json({ error: 'Failed to export entries' });
  }
});

// Start server
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});
