// controllers/monthlyComparisonController.js — 월간 비교·확인·정산
const Model = require('../models/monthlyComparisonModel');
const logger = require('../utils/logger');

const ADMIN_ROLES = ['support_team', 'admin', 'system'];

// 일별 비교 상태 판정
function determineStatus(report, attendance, isHoliday) {
  const hasReport = report && report.total_hours > 0;
  const hasAttendance = attendance && attendance.total_work_hours > 0;
  const isVacation = attendance && attendance.vacation_type_id;

  if (isHoliday && !hasReport && !hasAttendance) return 'holiday';
  if (isVacation) return 'vacation';
  if (!hasReport && !hasAttendance) return 'none';
  if (hasReport && !hasAttendance) return 'report_only';
  if (!hasReport && hasAttendance) return 'attend_only';

  const diff = Math.abs(report.total_hours - attendance.total_work_hours);
  return diff <= 0.5 ? 'match' : 'mismatch';
}

// 날짜별 비교 데이터 생성
async function buildComparisonData(userId, year, month) {
  const [reports, attendances, confirmation] = await Promise.all([
    Model.getWorkReports(userId, year, month),
    Model.getAttendanceRecords(userId, year, month),
    Model.getConfirmation(userId, year, month)
  ]);

  // 날짜 맵 생성
  const reportMap = {};
  reports.forEach(r => {
    const key = r.report_date instanceof Date
      ? r.report_date.toISOString().split('T')[0]
      : String(r.report_date).split('T')[0];
    reportMap[key] = r;
  });

  const attendMap = {};
  attendances.forEach(a => {
    const key = a.record_date instanceof Date
      ? a.record_date.toISOString().split('T')[0]
      : String(a.record_date).split('T')[0];
    attendMap[key] = a;
  });

  // 해당 월의 모든 날짜 생성
  const daysInMonth = new Date(year, month, 0).getDate();
  const DAYS_KR = ['일', '월', '화', '수', '목', '금', '토'];
  const dailyRecords = [];
  let totalWorkDays = 0, totalWorkHours = 0, totalOvertimeHours = 0;
  let vacationDays = 0, mismatchCount = 0;
  const mismatchDetails = { hours_diff: 0, missing_report: 0, missing_attendance: 0 };

  for (let day = 1; day <= daysInMonth; day++) {
    const date = new Date(year, month - 1, day);
    const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
    const dayOfWeek = date.getDay();
    const isHoliday = dayOfWeek === 0 || dayOfWeek === 6;

    const report = reportMap[dateStr] || null;
    const attend = attendMap[dateStr] || null;
    const status = determineStatus(report, attend, isHoliday);

    let hoursDiff = 0;
    if (report && attend && report.total_hours && attend.total_work_hours) {
      hoursDiff = parseFloat((report.total_hours - attend.total_work_hours).toFixed(2));
    }

    // 통계
    if (status === 'match' || status === 'mismatch') {
      totalWorkDays++;
      totalWorkHours += parseFloat(attend?.total_work_hours || report?.total_hours || 0);
    }
    if (status === 'report_only') { totalWorkDays++; totalWorkHours += parseFloat(report.total_hours || 0); }
    if (status === 'attend_only') { totalWorkDays++; totalWorkHours += parseFloat(attend.total_work_hours || 0); }
    if (status === 'vacation') { vacationDays++; }
    if (status === 'mismatch') { mismatchCount++; mismatchDetails.hours_diff++; }
    if (status === 'report_only') { mismatchCount++; mismatchDetails.missing_attendance++; }
    if (status === 'attend_only') { mismatchCount++; mismatchDetails.missing_report++; }

    // 연장근로: 8h 초과분
    if (attend && attend.total_work_hours > 8) {
      totalOvertimeHours += parseFloat(attend.total_work_hours) - 8;
    }

    dailyRecords.push({
      date: dateStr,
      day_of_week: DAYS_KR[dayOfWeek],
      is_holiday: isHoliday,
      work_report: report ? {
        total_hours: parseFloat(report.total_hours),
        entries: [{ project_name: report.project_names || '', work_type: report.work_type_names || '', hours: parseFloat(report.total_hours) }]
      } : null,
      attendance: attend ? {
        total_work_hours: parseFloat(attend.total_work_hours),
        attendance_type: attend.attendance_type_name || '',
        vacation_type: attend.vacation_type_name || null
      } : null,
      status,
      hours_diff: hoursDiff
    });
  }

  return {
    summary: {
      total_work_days: totalWorkDays,
      total_work_hours: parseFloat(totalWorkHours.toFixed(2)),
      total_overtime_hours: parseFloat(totalOvertimeHours.toFixed(2)),
      vacation_days: vacationDays,
      mismatch_count: mismatchCount,
      mismatch_details: mismatchDetails
    },
    confirmation: confirmation ? {
      status: confirmation.status,
      confirmed_at: confirmation.confirmed_at,
      rejected_at: confirmation.rejected_at,
      reject_reason: confirmation.reject_reason
    } : { status: 'pending', confirmed_at: null, reject_reason: null },
    daily_records: dailyRecords
  };
}

const MonthlyComparisonController = {
  // GET /my-records
  getMyRecords: async (req, res) => {
    try {
      const userId = req.user.user_id || req.user.id;
      const { year, month } = req.query;
      if (!year || !month) return res.status(400).json({ success: false, message: 'year, month 필수' });

      const worker = await Model.getWorkerInfo(userId);
      const data = await buildComparisonData(userId, parseInt(year), parseInt(month));

      res.json({
        success: true,
        data: {
          user: worker || { user_id: userId },
          period: { year: parseInt(year), month: parseInt(month) },
          ...data
        }
      });
    } catch (err) {
      logger.error('monthlyComparison getMyRecords error:', err);
      res.status(500).json({ success: false, message: '서버 오류가 발생했습니다.' });
    }
  },

  // GET /records (관리자용)
  getRecords: async (req, res) => {
    try {
      const { year, month, user_id } = req.query;
      if (!year || !month || !user_id) return res.status(400).json({ success: false, message: 'year, month, user_id 필수' });

      const reqUserId = req.user.user_id || req.user.id;
      const targetUserId = parseInt(user_id);

      // 본인 아니면 support_team 이상 필요
      if (targetUserId !== reqUserId && !ADMIN_ROLES.includes(req.user.role)) {
        return res.status(403).json({ success: false, message: '접근 권한이 없습니다.' });
      }

      const worker = await Model.getWorkerInfo(targetUserId);
      const data = await buildComparisonData(targetUserId, parseInt(year), parseInt(month));

      res.json({
        success: true,
        data: {
          user: worker || { user_id: targetUserId },
          period: { year: parseInt(year), month: parseInt(month) },
          ...data
        }
      });
    } catch (err) {
      logger.error('monthlyComparison getRecords error:', err);
      res.status(500).json({ success: false, message: '서버 오류가 발생했습니다.' });
    }
  },

  // POST /confirm
  confirm: async (req, res) => {
    try {
      const userId = req.user.user_id || req.user.id;
      const { year, month, status, reject_reason } = req.body;

      if (!year || !month || !status) return res.status(400).json({ success: false, message: 'year, month, status 필수' });
      if (!['confirmed', 'rejected'].includes(status)) return res.status(400).json({ success: false, message: "status는 'confirmed' 또는 'rejected'만 허용" });
      if (status === 'rejected' && (!reject_reason || !reject_reason.trim())) {
        return res.status(400).json({ success: false, message: '반려 사유를 입력해주세요.' });
      }

      // 요약 통계 계산
      const compData = await buildComparisonData(userId, parseInt(year), parseInt(month));

      let notificationData = null;
      if (status === 'rejected') {
        const worker = await Model.getWorkerInfo(userId);
        const recipients = await Model.getSupportTeamUsers();
        notificationData = {
          recipients,
          title: '월간 근무 내역 이의 제기',
          message: `${worker?.worker_name || '작업자'}(${worker?.department_name || ''})님이 ${year}년 ${month}월 근무 내역에 이의를 제기했습니다. 사유: ${reject_reason}`,
          linkUrl: `/pages/attendance/monthly-comparison.html?user_id=${userId}&year=${year}&month=${month}`,
          createdBy: userId
        };
      }

      const result = await Model.upsertConfirmation({
        user_id: userId, year: parseInt(year), month: parseInt(month), status,
        reject_reason: reject_reason || null,
        ...compData.summary
      }, notificationData);

      if (result.error) return res.status(409).json({ success: false, message: result.error });

      const msg = status === 'confirmed' ? '확인이 완료되었습니다.' : '이의가 접수되었습니다. 지원팀에 알림이 전달됩니다.';
      res.json({ success: true, data: result, message: msg });
    } catch (err) {
      logger.error('monthlyComparison confirm error:', err);
      res.status(500).json({ success: false, message: '서버 오류가 발생했습니다.' });
    }
  },

  // GET /all-status (support_team+)
  getAllStatus: async (req, res) => {
    try {
      const { year, month, department_id } = req.query;
      if (!year || !month) return res.status(400).json({ success: false, message: 'year, month 필수' });

      const workers = await Model.getAllStatus(parseInt(year), parseInt(month), department_id ? parseInt(department_id) : null);

      let confirmed = 0, pending = 0, rejected = 0;
      workers.forEach(w => {
        if (w.status === 'confirmed') confirmed++;
        else if (w.status === 'rejected') rejected++;
        else pending++;
      });

      res.json({
        success: true,
        data: {
          period: { year: parseInt(year), month: parseInt(month) },
          summary: { total_workers: workers.length, confirmed, pending, rejected },
          workers: workers.map(w => ({
            user_id: w.user_id, worker_name: w.worker_name, job_type: w.job_type,
            department_name: w.department_name, status: w.status || 'pending',
            confirmed_at: w.confirmed_at, reject_reason: w.reject_reason,
            total_work_days: w.total_work_days || 0,
            total_work_hours: parseFloat(w.total_work_hours || 0),
            total_overtime_hours: parseFloat(w.total_overtime_hours || 0),
            mismatch_count: w.mismatch_count || 0
          }))
        }
      });
    } catch (err) {
      logger.error('monthlyComparison getAllStatus error:', err);
      res.status(500).json({ success: false, message: '서버 오류가 발생했습니다.' });
    }
  },

  // GET /export (support_team+, pending 0명일 때만)
  exportExcel: async (req, res) => {
    try {
      const { year, month } = req.query;
      if (!year || !month) return res.status(400).json({ success: false, message: 'year, month 필수' });

      const y = parseInt(year), m = parseInt(month);

      // pending 체크
      const workers = await Model.getAllStatus(y, m);
      const pendingCount = workers.filter(w => !w.status || w.status === 'pending').length;
      if (pendingCount > 0) {
        return res.status(403).json({ success: false, message: `${pendingCount}명이 미확인 상태입니다. 전원 확인 후 다운로드 가능합니다.` });
      }

      const ExcelJS = require('exceljs');
      const workbook = new ExcelJS.Workbook();

      // Sheet 1: 월간 근무 현황
      const sheet1 = workbook.addWorksheet('월간 근무 현황');
      const headerStyle = { fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF4472C4' } }, font: { color: { argb: 'FFFFFFFF' }, bold: true }, alignment: { horizontal: 'center' } };

      sheet1.columns = [
        { header: 'No', key: 'no', width: 6 },
        { header: '이름', key: 'name', width: 12 },
        { header: '부서', key: 'dept', width: 12 },
        { header: '직종', key: 'job', width: 10 },
        { header: '총근무일', key: 'days', width: 10 },
        { header: '총근무시간', key: 'hours', width: 12 },
        { header: '연장근로(h)', key: 'overtime', width: 12 },
        { header: '휴가(일)', key: 'vacation', width: 10 },
        { header: '확인상태', key: 'status', width: 10 },
        { header: '확인일시', key: 'confirmed', width: 18 },
      ];
      sheet1.getRow(1).eachCell(cell => { Object.assign(cell, headerStyle); });

      workers.forEach((w, i) => {
        sheet1.addRow({
          no: i + 1, name: w.worker_name, dept: w.department_name, job: w.job_type,
          days: w.total_work_days || 0, hours: parseFloat(w.total_work_hours || 0),
          overtime: parseFloat(w.total_overtime_hours || 0),
          vacation: parseFloat(w.vacation_days || 0),
          status: { confirmed: '확인', rejected: '반려', pending: '대기' }[w.status || 'pending'],
          confirmed: w.confirmed_at ? new Date(w.confirmed_at).toLocaleString('ko') : '-'
        });
      });

      // Sheet 2: 일별 상세
      const sheet2 = workbook.addWorksheet('일별 상세');
      sheet2.columns = [
        { header: '이름', key: 'name', width: 12 },
        { header: '날짜', key: 'date', width: 12 },
        { header: '요일', key: 'dow', width: 6 },
        { header: '작업보고서(h)', key: 'report', width: 14 },
        { header: '근태관리(h)', key: 'attend', width: 12 },
        { header: '근태유형', key: 'atype', width: 12 },
        { header: '휴가유형', key: 'vtype', width: 10 },
        { header: '시간차이', key: 'diff', width: 10 },
        { header: '상태', key: 'status', width: 10 },
      ];
      sheet2.getRow(1).eachCell(cell => { Object.assign(cell, headerStyle); });

      const detailData = await Model.getExcelData(y, m);
      const DAYS_KR = ['일', '월', '화', '수', '목', '금', '토'];
      detailData.forEach(row => {
        if (!row.record_date) return;
        const d = new Date(row.record_date);
        const diff = (parseFloat(row.report_hours || 0) - parseFloat(row.attendance_hours || 0)).toFixed(2);
        const r = sheet2.addRow({
          name: row.worker_name, date: row.record_date instanceof Date ? row.record_date.toISOString().split('T')[0] : String(row.record_date).split('T')[0],
          dow: DAYS_KR[d.getDay()],
          report: parseFloat(row.report_hours || 0),
          attend: parseFloat(row.attendance_hours || 0),
          atype: row.attendance_type_name || '', vtype: row.vacation_type_name || '',
          diff: parseFloat(diff),
          status: Math.abs(parseFloat(diff)) > 0.5 ? '불일치' : '일치'
        });
        if (Math.abs(parseFloat(diff)) > 0.5) {
          r.eachCell(cell => { cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFF2CC' } }; });
        }
        if (row.vacation_type_name) {
          r.eachCell(cell => { cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE2EFDA' } }; });
        }
      });

      const filename = encodeURIComponent(`생산팀_월간근무현황_${year}년${String(month).padStart(2, '0')}월.xlsx`);
      res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
      res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
      await workbook.xlsx.write(res);
      res.end();
    } catch (err) {
      logger.error('monthlyComparison exportExcel error:', err);
      res.status(500).json({ success: false, message: '엑셀 생성 실패' });
    }
  }
};

module.exports = MonthlyComparisonController;
