/**
 * 근태 관리 서비스
 *
 * 근태 기록 관련 비즈니스 로직 처리
 *
 * @author TK-FB-Project
 * @since 2025-12-11
 */

const AttendanceModel = require('../models/attendanceModel');
const vacationBalanceModel = require('../models/vacationBalanceModel');
const { ValidationError, NotFoundError, DatabaseError } = require('../utils/errors');
const logger = require('../utils/logger');

/**
 * 휴가 사용 유형 ID를 차감 일수로 변환
 * vacation_type_id: 1=연차(1일), 2=반차(0.5일), 3=반반차(0.25일)
 */
const getVacationDays = (vacationTypeId) => {
  const daysMap = { 1: 1, 2: 0.5, 3: 0.25 };
  return daysMap[vacationTypeId] || 0;
};

/**
 * 일일 근태 현황 조회
 */
const getDailyAttendanceStatusService = async (date) => {
  if (!date) {
    throw new ValidationError('날짜가 필요합니다', {
      required: ['date'],
      received: { date }
    });
  }

  logger.info('일일 근태 현황 조회 요청', { date });

  try {
    // 조회 전 초기화 수행 (Lazy Initialization)
    // 생성자는 시스템(1) 또는 요청자가 될 수 있으나, 여기서는 안전하게 1(System/Admin) 사용 
    // 혹은 req.user가 없으므로 서비스 레벨에서는 1로 가정하거나 파라미터로 받아야 함. 
    // 서비스 인터페이스 변경 최소화를 위해 하드코딩 또는 안전장치.
    await AttendanceModel.initializeDailyRecords(date, 1);

    const attendanceStatus = await AttendanceModel.getWorkerAttendanceStatus(date);
    logger.info('일일 근태 현황 조회 성공', { date, count: attendanceStatus.length });
    return attendanceStatus;
  } catch (error) {
    logger.error('일일 근태 현황 조회 실패', { date, error: error.message });
    throw new DatabaseError('근태 현황 조회 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 일일 근태 기록 조회
 */
const getDailyAttendanceRecordsService = async (date, userId = null) => {
  if (!date) {
    throw new ValidationError('날짜가 필요합니다', {
      required: ['date'],
      received: { date }
    });
  }

  logger.info('일일 근태 기록 조회 요청', { date, userId });

  try {
    const records = await AttendanceModel.getDailyAttendanceRecords(date, userId);
    logger.info('일일 근태 기록 조회 성공', { date, count: records.length });
    return records;
  } catch (error) {
    logger.error('일일 근태 기록 조회 실패', { date, error: error.message });
    throw new DatabaseError('근태 기록 조회 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 기간별 근태 기록 조회 (월별 조회용)
 */
const getAttendanceRecordsByRangeService = async (startDate, endDate, userId = null) => {
  if (!startDate || !endDate) {
    throw new ValidationError('시작 날짜와 종료 날짜가 필요합니다', {
      required: ['start_date', 'end_date'],
      received: { startDate, endDate }
    });
  }

  logger.info('기간별 근태 기록 조회 요청', { startDate, endDate, userId });

  try {
    const records = await AttendanceModel.getDailyRecords(startDate, endDate, userId);
    logger.info('기간별 근태 기록 조회 성공', { startDate, endDate, count: records.length });
    return records;
  } catch (error) {
    logger.error('기간별 근태 기록 조회 실패', { startDate, endDate, error: error.message });
    throw new DatabaseError('근태 기록 조회 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 근태 기록 생성/업데이트
 * - 휴가 기록 시 vacation_balance_details의 used_days 자동 연동
 */
const upsertAttendanceRecordService = async (recordData) => {
  const {
    record_date,
    user_id,
    total_work_hours,
    attendance_type_id,
    vacation_type_id,
    is_vacation_processed,
    overtime_approved,
    status,
    notes,
    created_by
  } = recordData;

  // 필수 필드 검증
  if (!record_date || !user_id) {
    throw new ValidationError('필수 필드가 누락되었습니다', {
      required: ['record_date', 'user_id'],
      received: { record_date, user_id }
    });
  }

  logger.info('근태 기록 저장 요청', { record_date, user_id, vacation_type_id });

  try {
    // 1. 기존 기록 조회 (휴가 연동을 위해)
    const existingRecords = await AttendanceModel.getDailyAttendanceRecords(record_date, user_id);
    const existingRecord = existingRecords.find(r => r.user_id === user_id);
    const previousVacationTypeId = existingRecord?.vacation_type_id || null;

    // 2. 근태 기록 저장
    const result = await AttendanceModel.upsertAttendanceRecord({
      record_date,
      user_id,
      total_work_hours,
      work_attendance_type_id: attendance_type_id,
      vacation_type_id,
      is_overtime_approved: overtime_approved,
      created_by
    });

    // 3. 휴가 잔액 연동 (vacation_balance_details.used_days 업데이트)
    const year = new Date(record_date).getFullYear();
    const previousDays = getVacationDays(previousVacationTypeId);
    const newDays = getVacationDays(vacation_type_id);

    // 이전 휴가가 있었고 변경된 경우 → 복구 후 차감
    if (previousDays !== newDays) {
      // 이전 휴가 복구
      if (previousDays > 0) {
        await vacationBalanceModel.restoreByPriority(user_id, year, previousDays);
        logger.info('휴가 잔액 복구', { user_id, year, restored: previousDays });
      }

      // 새 휴가 차감
      if (newDays > 0) {
        await vacationBalanceModel.deductByPriority(user_id, year, newDays);
        logger.info('휴가 잔액 차감', { user_id, year, deducted: newDays });
      }
    }

    logger.info('근태 기록 저장 성공', { record_date, user_id });
    return result;
  } catch (error) {
    logger.error('근태 기록 저장 실패', { record_date, user_id, error: error.message });
    throw new DatabaseError('근태 기록 저장 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 휴가 처리
 */
const processVacationService = async (vacationData) => {
  const { record_date, user_id, vacation_type_id } = vacationData;

  if (!record_date || !user_id || !vacation_type_id) {
    throw new ValidationError('필수 필드가 누락되었습니다', {
      required: ['record_date', 'user_id', 'vacation_type_id'],
      received: { record_date, user_id, vacation_type_id }
    });
  }

  logger.info('휴가 처리 요청', { record_date, user_id, vacation_type_id });

  try {
    const result = await AttendanceModel.processVacation({
      record_date,
      user_id,
      vacation_type_id
    });

    logger.info('휴가 처리 성공', { record_date, user_id });
    return result;
  } catch (error) {
    logger.error('휴가 처리 실패', { record_date, user_id, error: error.message });
    throw new DatabaseError('휴가 처리 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 초과 근무 승인
 */
const approveOvertimeService = async (overtimeData) => {
  const { record_date, user_id, overtime_approved } = overtimeData;

  if (!record_date || !user_id || overtime_approved === undefined) {
    throw new ValidationError('필수 필드가 누락되었습니다', {
      required: ['record_date', 'user_id', 'overtime_approved'],
      received: { record_date, user_id, overtime_approved }
    });
  }

  logger.info('초과 근무 승인 요청', { record_date, user_id, overtime_approved });

  try {
    const result = await AttendanceModel.approveOvertime({
      record_date,
      user_id,
      overtime_approved
    });

    logger.info('초과 근무 승인 처리 성공', { record_date, user_id });
    return result;
  } catch (error) {
    logger.error('초과 근무 승인 실패', { record_date, user_id, error: error.message });
    throw new DatabaseError('초과 근무 승인 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 근태 유형 목록 조회
 */
const getAttendanceTypesService = async () => {
  logger.info('근태 유형 목록 조회 요청');

  try {
    const types = await AttendanceModel.getAttendanceTypes();
    logger.info('근태 유형 목록 조회 성공', { count: types.length });
    return types;
  } catch (error) {
    logger.error('근태 유형 목록 조회 실패', { error: error.message });
    throw new DatabaseError('근태 유형 목록 조회 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 휴가 유형 목록 조회
 */
const getVacationTypesService = async () => {
  logger.info('휴가 유형 목록 조회 요청');

  try {
    const types = await AttendanceModel.getVacationTypes();
    logger.info('휴가 유형 목록 조회 성공', { count: types.length });
    return types;
  } catch (error) {
    logger.error('휴가 유형 목록 조회 실패', { error: error.message });
    throw new DatabaseError('휴가 유형 목록 조회 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 작업자 휴가 잔여 일수 조회
 */
const getWorkerVacationBalanceService = async (userId) => {
  if (!userId) {
    throw new ValidationError('작업자 ID가 필요합니다', {
      required: ['user_id'],
      received: { userId }
    });
  }

  logger.info('휴가 잔여 일수 조회 요청', { userId });

  try {
    const balance = await AttendanceModel.getWorkerVacationBalance(userId);
    logger.info('휴가 잔여 일수 조회 성공', { userId });
    return balance;
  } catch (error) {
    logger.error('휴가 잔여 일수 조회 실패', { userId, error: error.message });
    throw new DatabaseError('휴가 잔여 일수 조회 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 월별 근태 통계 조회
 */
const getMonthlyAttendanceStatsService = async (year, month, userId = null) => {
  if (!year || !month) {
    throw new ValidationError('연도와 월이 필요합니다', {
      required: ['year', 'month'],
      received: { year, month }
    });
  }

  logger.info('월별 근태 통계 조회 요청', { year, month, userId });

  try {
    const stats = await AttendanceModel.getMonthlyAttendanceStats(year, month, userId);
    logger.info('월별 근태 통계 조회 성공', { year, month });
    return stats;
  } catch (error) {
    logger.error('월별 근태 통계 조회 실패', { year, month, error: error.message });
    throw new DatabaseError('월별 근태 통계 조회 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 출근 체크 목록 조회 (휴가 정보 포함)
 */
const getCheckinListService = async (date) => {
  if (!date) {
    throw new ValidationError('날짜가 필요합니다', {
      required: ['date'],
      received: { date }
    });
  }

  logger.info('출근 체크 목록 조회 요청', { date });

  try {
    const checkinList = await AttendanceModel.getCheckinList(date);
    logger.info('출근 체크 목록 조회 성공', { date, count: checkinList.length });
    return checkinList;
  } catch (error) {
    logger.error('출근 체크 목록 조회 실패', { date, error: error.message });
    throw new DatabaseError('출근 체크 목록 조회 중 데이터베이스 오류가 발생했습니다');
  }
};

/**
 * 출근 체크 일괄 저장
 */
const saveCheckinsService = async (date, checkins) => {
  if (!date || !checkins || !Array.isArray(checkins)) {
    throw new ValidationError('날짜와 출근 체크 목록이 필요합니다', {
      required: ['date', 'checkins'],
      received: { date, checkins: checkins ? `Array[${checkins.length}]` : null }
    });
  }

  logger.info('출근 체크 일괄 저장 요청', { date, count: checkins.length });

  try {
    const results = [];

    for (const checkin of checkins) {
      const { user_id, is_present } = checkin;

      if (!user_id || is_present === undefined) {
        logger.warn('출근 체크 데이터 누락', { checkin });
        continue;
      }

      const result = await AttendanceModel.upsertCheckin({
        user_id,
        record_date: date,
        is_present
      });

      results.push({
        user_id,
        record_id: result,
        is_present
      });
    }

    logger.info('출근 체크 일괄 저장 성공', { date, saved: results.length });
    return {
      saved_count: results.length,
      results
    };
  } catch (error) {
    logger.error('출근 체크 일괄 저장 실패', { date, error: error.message });
    throw new DatabaseError('출근 체크 저장 중 데이터베이스 오류가 발생했습니다');
  }
};

module.exports = {
  getDailyAttendanceStatusService,
  getDailyAttendanceRecordsService,
  getAttendanceRecordsByRangeService,
  upsertAttendanceRecordService,
  processVacationService,
  approveOvertimeService,
  getAttendanceTypesService,
  getVacationTypesService,
  getWorkerVacationBalanceService,
  getMonthlyAttendanceStatsService,
  getCheckinListService,
  saveCheckinsService
};
