const db = require('../config/database');
const { getSetting, getCurrentDateInTimezone, parseDateInTimezone } = require('../config/settingsManager');

/**
 * ATTENDANCE SERVICE
 * Mengelola absensi karyawan (teknisi, admin, cashier, collector)
 */

// Calculate distance between two coordinates (Haversine formula)
function calculateDistance(lat1, lon1, lat2, lon2) {
  const R = 6371; // Radius of Earth in kilometers
  const dLat = (lat2 - lat1) * Math.PI / 180;
  const dLon = (lon2 - lon1) * Math.PI / 180;
  const a =
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
    Math.sin(dLon/2) * Math.sin(dLon/2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  const distance = R * c * 1000; // Convert to meters
  return distance;
}

// Validate if location is within allowed radius
function validateLocation(lat, lng) {
  // Get office location from settings
  const officeLat = parseFloat(getSetting('office_lat', '0'));
  const officeLng = parseFloat(getSetting('office_lng', '0'));
  const allowedRadius = parseInt(getSetting('attendance_radius', '100')); // Default 100 meters
  const geofencingEnabled = getSetting('attendance_geofencing', 'true') === 'true';
  
  // If geofencing disabled or office location not set, allow all
  if (!geofencingEnabled || !officeLat || !officeLng) {
    return { valid: true, distance: 0, message: 'Geofencing disabled' };
  }
  
  // If no GPS provided
  if (!lat || !lng) {
    return { valid: false, distance: 0, message: 'GPS location required' };
  }
  
  // Calculate distance
  const distance = calculateDistance(officeLat, officeLng, parseFloat(lat), parseFloat(lng));
  
  // Check if within radius
  if (distance <= allowedRadius) {
    return {
      valid: true,
      distance: Math.round(distance),
      message: `Within range (${Math.round(distance)}m from office)`
    };
  } else {
    return {
      valid: false,
      distance: Math.round(distance),
      message: `Too far from office (${Math.round(distance)}m, max ${allowedRadius}m)`
    };
  }
}

// Create attendance record (check-in)
function checkIn(data) {
  // Validate location
  const locationCheck = validateLocation(data.lat, data.lng);
  if (!locationCheck.valid) {
    throw new Error(locationCheck.message);
  }
  const stmt = db.prepare(`
    INSERT INTO attendance (
      employee_type, employee_id, employee_name,
      check_in_time, check_in_lat, check_in_lng, check_in_note, check_in_photo
    ) VALUES (?, ?, ?, NOW_LOCAL(), ?, ?, ?, ?)
  `);
  
  return stmt.run(
    data.employee_type,
    data.employee_id,
    data.employee_name,
    data.lat || '',
    data.lng || '',
    data.note || '',
    data.photo || ''
  );
}

// Update attendance record (check-out)
function checkOut(attendanceId, data) {
  const attendance = db.prepare('SELECT * FROM attendance WHERE id = ?').get(attendanceId);
  if (!attendance) {
    throw new Error('Attendance record not found');
  }
  
  if (attendance.status === 'checked_out') {
    throw new Error('Already checked out');
  }
  
  // Validate location for check-out
  const locationCheck = validateLocation(data.lat, data.lng);
  if (!locationCheck.valid) {
    throw new Error(locationCheck.message);
  }
  
  // Calculate work duration in minutes
  const checkInTime = parseDateInTimezone(attendance.check_in_time);
  const checkOutTime = getCurrentDateInTimezone();
  const durationMinutes = Math.floor((checkOutTime - checkInTime) / 1000 / 60);
  
  const stmt = db.prepare(`
    UPDATE attendance 
    SET check_out_time = NOW_LOCAL(),
        check_out_lat = ?,
        check_out_lng = ?,
        check_out_note = ?,
        check_out_photo = ?,
        work_duration_minutes = ?,
        status = 'checked_out'
    WHERE id = ?
  `);
  
  return stmt.run(
    data.lat || '',
    data.lng || '',
    data.note || '',
    data.photo || '',
    durationMinutes,
    attendanceId
  );
}

// Get today's attendance for an employee
function getTodayAttendance(employeeType, employeeId) {
  const stmt = db.prepare(`
    SELECT * FROM attendance 
    WHERE employee_type = ? 
      AND employee_id = ? 
      AND date(check_in_time) = date(NOW_LOCAL())
    ORDER BY check_in_time DESC
    LIMIT 1
  `);
  
  return stmt.get(employeeType, employeeId);
}

// Get attendance history for an employee
function getAttendanceHistory(employeeType, employeeId, limit = 30) {
  const stmt = db.prepare(`
    SELECT * FROM attendance 
    WHERE employee_type = ? AND employee_id = ?
    ORDER BY check_in_time DESC
    LIMIT ?
  `);
  
  return stmt.all(employeeType, employeeId, limit);
}

// Get all attendance records for a specific date
function getAttendanceByDate(date) {
  const stmt = db.prepare(`
    SELECT * FROM attendance 
    WHERE date(check_in_time) = date(?)
    ORDER BY check_in_time DESC
  `);
  
  return stmt.all(date);
}

// Get attendance records for a date range
function getAttendanceByDateRange(startDate, endDate) {
  const stmt = db.prepare(`
    SELECT * FROM attendance 
    WHERE date(check_in_time) BETWEEN date(?) AND date(?)
    ORDER BY check_in_time DESC
  `);
  
  return stmt.all(startDate, endDate);
}

// Get attendance summary for an employee (monthly)
function getMonthlyAttendanceSummary(employeeType, employeeId, year, month) {
  const stmt = db.prepare(`
    SELECT 
      COUNT(*) as total_days,
      SUM(CASE WHEN status = 'checked_out' THEN 1 ELSE 0 END) as completed_days,
      SUM(work_duration_minutes) as total_minutes,
      AVG(work_duration_minutes) as avg_minutes
    FROM attendance 
    WHERE employee_type = ? 
      AND employee_id = ?
      AND strftime('%Y', check_in_time) = ?
      AND strftime('%m', check_in_time) = ?
  `);
  
  const yearStr = String(year);
  const monthStr = String(month).padStart(2, '0');
  
  return stmt.get(employeeType, employeeId, yearStr, monthStr);
}

// Get all attendance for today (for admin dashboard)
function getTodayAllAttendance() {
  const stmt = db.prepare(`
    SELECT * FROM attendance 
    WHERE date(check_in_time) = date(NOW_LOCAL())
    ORDER BY check_in_time DESC
  `);
  
  return stmt.all();
}

// Get attendance statistics for admin
function getAttendanceStats(date = null) {
  const dateFilter = date ? `date(check_in_time) = date('${date}')` : `date(check_in_time) = date(NOW_LOCAL())`;
  
  const stmt = db.prepare(`
    SELECT 
      employee_type,
      COUNT(*) as total,
      SUM(CASE WHEN status = 'checked_in' THEN 1 ELSE 0 END) as checked_in,
      SUM(CASE WHEN status = 'checked_out' THEN 1 ELSE 0 END) as checked_out
    FROM attendance 
    WHERE ${dateFilter}
    GROUP BY employee_type
  `);
  
  return stmt.all();
}

// Check if employee has checked in today
function hasCheckedInToday(employeeType, employeeId) {
  const today = getTodayAttendance(employeeType, employeeId);
  return today !== undefined;
}

// Get late check-ins (after 8:30 AM)
function getLateCheckIns(date = null) {
  const dateFilter = date ? `date(check_in_time) = date('${date}')` : `date(check_in_time) = date(NOW_LOCAL())`;
  
  const stmt = db.prepare(`
    SELECT * FROM attendance 
    WHERE ${dateFilter}
      AND time(check_in_time) > '08:30:00'
    ORDER BY check_in_time DESC
  `);
  
  return stmt.all();
}

// Get employees who haven't checked out
function getNotCheckedOut(date = null) {
  const dateFilter = date ? `date(check_in_time) = date('${date}')` : `date(check_in_time) = date(NOW_LOCAL())`;
  
  const stmt = db.prepare(`
    SELECT * FROM attendance 
    WHERE ${dateFilter}
      AND status = 'checked_in'
    ORDER BY check_in_time DESC
  `);
  
  return stmt.all();
}

// Delete attendance record (admin only)
function deleteAttendance(id) {
  return db.prepare('DELETE FROM attendance WHERE id = ?').run(id);
}

// Update attendance record (admin only - for corrections)
function updateAttendance(id, data) {
  const stmt = db.prepare(`
    UPDATE attendance 
    SET check_in_time = ?,
        check_in_note = ?,
        check_out_time = ?,
        check_out_note = ?,
        work_duration_minutes = ?
    WHERE id = ?
  `);
  
  return stmt.run(
    data.check_in_time,
    data.check_in_note || '',
    data.check_out_time || null,
    data.check_out_note || '',
    data.work_duration_minutes || 0,
    id
  );
}

// Get geofencing settings
function getGeofencingSettings() {
  return {
    enabled: getSetting('attendance_geofencing', 'true') === 'true',
    officeLat: parseFloat(getSetting('office_lat', '0')),
    officeLng: parseFloat(getSetting('office_lng', '0')),
    radius: parseInt(getSetting('attendance_radius', '100'))
  };
}

module.exports = {
  checkIn,
  checkOut,
  getTodayAttendance,
  getAttendanceHistory,
  getAttendanceByDate,
  getAttendanceByDateRange,
  getMonthlyAttendanceSummary,
  getTodayAllAttendance,
  getAttendanceStats,
  hasCheckedInToday,
  getLateCheckIns,
  getNotCheckedOut,
  deleteAttendance,
  updateAttendance,
  validateLocation,
  calculateDistance,
  getGeofencingSettings
};

// Made with Bob
