const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const { query } = require('../db');
const auth = require('../middleware/auth');
const config = require('../config');

const router = express.Router();
const storageSvc = require('../services/storage');

const multerStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    const dir = path.join(process.cwd(), config.uploadDir, 'selfies');
    fs.mkdirSync(dir, { recursive: true });
    cb(null, dir);
  },
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname) || '.jpg';
    const name = `${Date.now()}_${Math.random().toString(36).slice(2)}${ext}`;
    cb(null, name);
  }
});
const upload = multer({ storage: multerStorage });

function distanceMeters(lat1, lon1, lat2, lon2) {
  const toRad = (v) => (v * Math.PI) / 180;
  const R = 6371000;
  const dLat = toRad(lat2 - lat1);
  const dLon = toRad(lon2 - lon1);
  const a = Math.sin(dLat/2)**2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon/2)**2;
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  return R * c;
}

router.post('/punch', auth(), upload.single('photo'), async (req, res) => {
  const { type, latitude, longitude, siteId } = req.body;
  if (!type || !latitude || !longitude) return res.status(400).json({ error: 'Missing type/latitude/longitude' });
  if (!['IN','OUT'].includes(type.toUpperCase())) return res.status(400).json({ error: 'Invalid type' });

  const employeeId = req.user.id;
  const companyId = req.user.companyId;
  const normalizedType = type.toUpperCase();

  // STRICT: Check today's punch status - only ONE IN and ONE OUT allowed per day
  const today = new Date().toISOString().split('T')[0];
  const todayLogs = await query(
    'SELECT type FROM attendance_logs WHERE employee_id = ? AND DATE(created_at) = ? ORDER BY created_at ASC',
    [employeeId, today]
  );
  
  // Count punch types today
  const punchInCount = todayLogs.filter(log => log.type === 'IN').length;
  const punchOutCount = todayLogs.filter(log => log.type === 'OUT').length;
  
  if (normalizedType === 'IN') {
    if (punchInCount >= 1) {
      return res.status(400).json({ error: 'You have already punched in today. Only one punch in per day allowed.' });
    }
    if (punchInCount === 0 && punchOutCount > 0) {
      return res.status(400).json({ error: 'Invalid punch sequence. Please contact admin.' });
    }
  }
  
  if (normalizedType === 'OUT') {
    if (punchInCount === 0) {
      return res.status(400).json({ error: 'No punch in found today. Please punch in first.' });
    }
    if (punchOutCount >= 1) {
      return res.status(400).json({ error: 'You have already punched out today. Only one punch out per day allowed.' });
    }
  }

  // Get employee name for folder structure
  const empRows = await query('SELECT first_name, last_name, email FROM employees WHERE id = ?', [employeeId]);
  const employee = empRows[0];
  const userName = employee ? `${employee.first_name}_${employee.last_name}`.replace(/\s+/g, '_') : `employee_${employeeId}`;

  // Geofence validation - CRITICAL: Must be within company site radius
  const sites = await query('SELECT id, name, latitude, longitude, radius_m FROM sites WHERE company_id = ?', [companyId]);
  
  if (!sites || sites.length === 0) {
    return res.status(400).json({ error: 'No geofence sites configured for your company' });
  }

  let targetSite = null;
  let nearestDistance = Infinity;
  let nearestSite = null;

  // Find nearest site and check if within radius
  for (const s of sites) {
    const dist = distanceMeters(Number(latitude), Number(longitude), Number(s.latitude), Number(s.longitude));
    
    if (dist < nearestDistance) {
      nearestDistance = dist;
      nearestSite = s;
    }
    
    if (dist <= Number(s.radius_m)) {
      targetSite = s;
      break;
    }
  }

  if (!targetSite) {
    const distanceMsg = nearestSite 
      ? `You are ${Math.round(nearestDistance)}m away from nearest site "${nearestSite.name}" (allowed: ${nearestSite.radius_m}m)`
      : 'No sites found';
    return res.status(400).json({ 
      error: `Outside geofence area! ${distanceMsg}`,
      distance: Math.round(nearestDistance),
      nearestSite: nearestSite ? nearestSite.name : null,
      allowedRadius: nearestSite ? nearestSite.radius_m : null
    });
  }

  // Check if employee is late (only for PUNCH IN)
  let isLate = false;
  let lateMessage = null;
  
  if (normalizedType === 'IN') {
    // Fetch company office timings
    const companyRows = await query(
      'SELECT office_open, office_lastentrytime FROM companies WHERE id = ?',
      [companyId]
    );
    
    if (companyRows.length > 0 && companyRows[0].office_lastentrytime) {
      const company = companyRows[0];
      const now = new Date();
      
      // Get current time in HH:MM format (IST)
      const istOffset = 5.5 * 60 * 60 * 1000; // IST is UTC+5:30
      const istTime = new Date(now.getTime() + istOffset);
      const currentTime = istTime.toISOString().substring(11, 16); // HH:MM format
      
      // Check if current time is after office_lastentrytime
      if (currentTime > company.office_lastentrytime) {
        isLate = true;
        lateMessage = `You are late! Grace period was till ${company.office_lastentrytime}. You punched in at ${currentTime}`;
      }
    }
  }

  let photoUrl = null;
  let photoPath = null;
  if (req.file) {
    const saved = await storageSvc.uploadSelfie(req.file.path, userName);
    photoUrl = saved.url; // Cloudflare R2 or local URL
    photoPath = saved.path; // key or relative path
  }

  await query('INSERT INTO attendance_logs (employee_id, company_id, type, is_late, site_id, latitude, longitude, photo_path, photo_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
    [employeeId, companyId, normalizedType, isLate, targetSite.id, latitude, longitude, photoPath, photoUrl]);

  res.status(201).json({ 
    ok: true, 
    type: normalizedType, 
    site: { id: targetSite.id, name: targetSite.name }, 
    photoUrl,
    isLate: isLate,
    lateMessage: lateMessage
  });
});

router.get('/me', auth(), async (req, res) => {
  const rows = await query('SELECT id, type, created_at, site_id, latitude, longitude, photo_url FROM attendance_logs WHERE employee_id = ? ORDER BY created_at DESC LIMIT 100', [req.user.id]);
  res.json(rows);
});

// Get monthly statistics with working days, sundays, and attendance
router.get('/monthly-stats', auth(), async (req, res) => {
  const now = new Date();
  const year = req.query.year || now.getFullYear();
  const month = req.query.month || (now.getMonth() + 1);
  
  const startDate = `${year}-${String(month).padStart(2, '0')}-01`;
  const endDate = new Date(year, month, 0).toISOString().split('T')[0];
  
  // Get attendance logs for the month
  const logs = await query(
    'SELECT DATE(created_at) as date, type, created_at, latitude, longitude, photo_url FROM attendance_logs WHERE employee_id = ? AND DATE(created_at) BETWEEN ? AND ? ORDER BY created_at',
    [req.user.id, startDate, endDate]
  );
  
  // Calculate days
  const daysInMonth = new Date(year, month, 0).getDate();
  let sundays = 0;
  let workingDays = 0;
  const datesWithAttendance = new Set();
  
  // Count sundays and working days
  for (let day = 1; day <= daysInMonth; day++) {
    const date = new Date(year, month - 1, day);
    if (date.getDay() === 0) {
      sundays++;
    } else {
      workingDays++;
    }
  }
  
  // Count unique attendance dates (present days)
  logs.forEach(log => {
    datesWithAttendance.add(log.date);
  });
  
  const presentDays = datesWithAttendance.size;
  const leaves = workingDays - presentDays;
  
  res.json({
    year,
    month,
    daysInMonth,
    sundays,
    workingDays,
    presentDays,
    leaves: leaves < 0 ? 0 : leaves,
    logs
  });
});

// Get monthly statistics with working days, sundays, and attendance
router.get('/monthly-stats', auth(), async (req, res) => {
  const now = new Date();
  const year = req.query.year || now.getFullYear();
  const month = req.query.month || (now.getMonth() + 1);
  
  const startDate = `${year}-${String(month).padStart(2, '0')}-01`;
  const endDate = new Date(year, month, 0).toISOString().split('T')[0];
  
  // Get attendance logs for the month
  const logs = await query(
    'SELECT DATE(created_at) as date, type, created_at, latitude, longitude, photo_url FROM attendance_logs WHERE employee_id = ? AND DATE(created_at) BETWEEN ? AND ? ORDER BY created_at',
    [req.user.id, startDate, endDate]
  );
  
  // Calculate days
  const daysInMonth = new Date(year, month, 0).getDate();
  let sundays = 0;
  let workingDays = 0;
  const datesWithAttendance = new Set();
  
  // Count sundays and working days
  for (let day = 1; day <= daysInMonth; day++) {
    const date = new Date(year, month - 1, day);
    if (date.getDay() === 0) {
      sundays++;
    } else {
      workingDays++;
    }
  }
  
  // Count unique attendance dates (present days)
  logs.forEach(log => {
    datesWithAttendance.add(log.date);
  });
  
  const presentDays = datesWithAttendance.size;
  const leaves = workingDays - presentDays;
  
  res.json({
    year,
    month,
    daysInMonth,
    sundays,
    workingDays,
    presentDays,
    leaves: leaves < 0 ? 0 : leaves,
    logs
  });
});

// Get today's punch status
router.get('/today-status', auth(), async (req, res) => {
  const today = new Date().toISOString().split('T')[0];
  const todayLogs = await query(
    'SELECT type, created_at FROM attendance_logs WHERE employee_id = ? AND DATE(created_at) = ? ORDER BY created_at DESC',
    [req.user.id, today]
  );
  
  const lastPunch = todayLogs.length > 0 ? todayLogs[0] : null;
  const canPunchIn = !lastPunch || lastPunch.type === 'OUT';
  const canPunchOut = lastPunch && lastPunch.type === 'IN';
  
  res.json({
    lastPunch,
    canPunchIn,
    canPunchOut,
    todayLogs
  });
});

module.exports = router;
