/**
 * 작업 보고서 관리 서비스
 *
 * 작업 보고서 CRUD 및 조회 관련 비즈니스 로직 처리
 *
 * @author TK-FB-Project
 * @since 2025-12-11
 */

const workReportModel = require('../models/workReportModel');
const { ValidationError, NotFoundError, DatabaseError } = require('../utils/errors');
const logger = require('../utils/logger');
const { getDb } = require('../dbPool');

/**
 * 작업 보고서 생성 (단일 또는 다중)
 */
const createWorkReportService = async (reportData) => {
  const reports = Array.isArray(reportData) ? reportData : [reportData];

  if (reports.length === 0) {
    throw new ValidationError('보고서 데이터가 필요합니다');
  }

  logger.info('작업 보고서 생성 요청', { count: reports.length });

  try {
    const workReport_ids = [];
    for (const report of reports) {
      const id = await workReportModel.create(report);
      workReport_ids.push(id);
    }

    logger.info('작업 보고서 생성 성공', {
      count: workReport_ids.length,
      ids: workReport_ids
    });

    return { workReport_ids };
  } catch (error) {
    logger.error('작업 보고서 생성 실패', {
      count: reports.length,
      error: error.message
    });
    throw new DatabaseError('작업 보고서 생성 중 오류가 발생했습니다');
  }
};

/**
 * 날짜별 작업 보고서 조회
 */
const getWorkReportsByDateService = async (date) => {
  if (!date) {
    throw new ValidationError('날짜가 필요합니다', {
      required: ['date'],
      received: { date }
    });
  }

  logger.info('작업 보고서 날짜별 조회 요청', { date });

  try {
    const rows = await workReportModel.getAllByDate(date);
    logger.info('작업 보고서 조회 성공', { date, count: rows.length });
    return rows;
  } catch (error) {
    logger.error('작업 보고서 조회 실패', { date, error: error.message });
    throw new DatabaseError('작업 보고서 조회 중 오류가 발생했습니다');
  }
};

/**
 * 기간별 작업 보고서 조회
 */
const getWorkReportsInRangeService = async (start, end) => {
  if (!start || !end) {
    throw new ValidationError('시작일과 종료일이 필요합니다', {
      required: ['start', 'end'],
      received: { start, end }
    });
  }

  logger.info('작업 보고서 기간별 조회 요청', { start, end });

  try {
    const rows = await workReportModel.getByRange(start, end);
    logger.info('작업 보고서 조회 성공', { start, end, count: rows.length });
    return rows;
  } catch (error) {
    logger.error('작업 보고서 조회 실패', { start, end, error: error.message });
    throw new DatabaseError('작업 보고서 조회 중 오류가 발생했습니다');
  }
};

/**
 * 단일 작업 보고서 조회
 */
const getWorkReportByIdService = async (id) => {
  if (!id) {
    throw new ValidationError('보고서 ID가 필요합니다');
  }

  logger.info('작업 보고서 조회 요청', { report_id: id });

  try {
    const row = await workReportModel.getById(id);

    if (!row) {
      logger.warn('작업 보고서를 찾을 수 없음', { report_id: id });
      throw new NotFoundError('작업 보고서를 찾을 수 없습니다');
    }

    logger.info('작업 보고서 조회 성공', { report_id: id });
    return row;
  } catch (error) {
    if (error instanceof NotFoundError) throw error;
    logger.error('작업 보고서 조회 실패', { report_id: id, error: error.message });
    throw new DatabaseError('작업 보고서 조회 중 오류가 발생했습니다');
  }
};

/**
 * 작업 보고서 수정
 */
const updateWorkReportService = async (id, updateData) => {
  if (!id) {
    throw new ValidationError('보고서 ID가 필요합니다');
  }

  logger.info('작업 보고서 수정 요청', { report_id: id });

  try {
    const changes = await workReportModel.update(id, updateData);

    if (changes === 0) {
      logger.warn('작업 보고서를 찾을 수 없거나 변경사항 없음', { report_id: id });
      throw new NotFoundError('작업 보고서를 찾을 수 없습니다');
    }

    logger.info('작업 보고서 수정 성공', { report_id: id, changes });
    return { changes };
  } catch (error) {
    if (error instanceof NotFoundError) throw error;
    logger.error('작업 보고서 수정 실패', { report_id: id, error: error.message });
    throw new DatabaseError('작업 보고서 수정 중 오류가 발생했습니다');
  }
};

/**
 * 작업 보고서 삭제
 */
const removeWorkReportService = async (id) => {
  if (!id) {
    throw new ValidationError('보고서 ID가 필요합니다');
  }

  logger.info('작업 보고서 삭제 요청', { report_id: id });

  try {
    const changes = await workReportModel.remove(id);

    if (changes === 0) {
      logger.warn('작업 보고서를 찾을 수 없음', { report_id: id });
      throw new NotFoundError('작업 보고서를 찾을 수 없습니다');
    }

    logger.info('작업 보고서 삭제 성공', { report_id: id, changes });
    return { changes };
  } catch (error) {
    if (error instanceof NotFoundError) throw error;
    logger.error('작업 보고서 삭제 실패', { report_id: id, error: error.message });
    throw new DatabaseError('작업 보고서 삭제 중 오류가 발생했습니다');
  }
};

/**
 * 월간 요약 조회
 */
const getSummaryService = async (year, month) => {
  if (!year || !month) {
    throw new ValidationError('연도와 월이 필요합니다', {
      required: ['year', 'month'],
      received: { year, month }
    });
  }

  const start = `${year.padStart(4, '0')}-${month.padStart(2, '0')}-01`;
  const end = `${year.padStart(4, '0')}-${month.padStart(2, '0')}-31`;

  logger.info('작업 보고서 월간 요약 조회 요청', { year, month, start, end });

  try {
    const rows = await workReportModel.getByRange(start, end);

    if (!rows || rows.length === 0) {
      logger.warn('월간 요약 데이터 없음', { year, month });
      throw new NotFoundError('해당 기간의 작업 보고서가 없습니다');
    }

    logger.info('작업 보고서 월간 요약 조회 성공', { year, month, count: rows.length });
    return rows;
  } catch (error) {
    if (error instanceof NotFoundError) throw error;
    logger.error('작업 보고서 월간 요약 조회 실패', { year, month, error: error.message });
    throw new DatabaseError('월간 요약 조회 중 오류가 발생했습니다');
  }
};

// ========== 부적합 원인 관리 서비스 ==========

/**
 * 작업 보고서의 부적합 원인 목록 조회
 */
const getReportDefectsService = async (reportId) => {
  const db = await getDb();
  try {
    const [rows] = await db.execute(`
      SELECT
        d.defect_id,
        d.report_id,
        d.error_type_id,
        d.issue_report_id,
        d.defect_hours,
        d.note,
        d.created_at,
        et.name as error_type_name,
        et.severity as error_severity,
        ir.content as issue_content,
        ir.status as issue_status,
        irc.category_name as issue_category_name,
        irc.severity as issue_severity,
        iri.item_name as issue_item_name
      FROM work_report_defects d
      LEFT JOIN error_types et ON d.error_type_id = et.id
      LEFT JOIN work_issue_reports ir ON d.issue_report_id = ir.report_id
      LEFT JOIN issue_report_categories irc ON ir.category_id = irc.category_id
      LEFT JOIN issue_report_items iri ON ir.item_id = iri.item_id
      WHERE d.report_id = ?
      ORDER BY d.created_at
    `, [reportId]);

    return rows;
  } catch (error) {
    logger.error('부적합 원인 조회 실패', { reportId, error: error.message });
    throw new DatabaseError('부적합 원인 조회 중 오류가 발생했습니다');
  }
};

/**
 * 부적합 원인 저장 (전체 교체)
 */
const saveReportDefectsService = async (reportId, defects) => {
  const db = await getDb();
  try {
    await db.query('START TRANSACTION');

    await db.execute('DELETE FROM work_report_defects WHERE report_id = ?', [reportId]);

    if (defects && defects.length > 0) {
      for (const defect of defects) {
        await db.execute(`
          INSERT INTO work_report_defects (report_id, error_type_id, issue_report_id, category_id, item_id, defect_hours, note)
          VALUES (?, ?, ?, ?, ?, ?, ?)
        `, [
          reportId,
          (defect.issue_report_id || defect.category_id) ? null : (defect.error_type_id || null),
          defect.issue_report_id || null,
          defect.category_id || null,
          defect.item_id || null,
          defect.defect_hours || 0,
          defect.note || null
        ]);
      }
    }

    const totalErrorHours = defects
      ? defects.reduce((sum, d) => sum + (parseFloat(d.defect_hours) || 0), 0)
      : 0;

    const firstErrorTypeId = defects && defects.length > 0
      ? (defects.find(d => d.error_type_id)?.error_type_id || null)
      : null;

    await db.execute(`
      UPDATE daily_work_reports
      SET error_hours = ?,
          error_type_id = ?,
          work_status_id = ?
      WHERE id = ?
    `, [
      totalErrorHours,
      firstErrorTypeId,
      totalErrorHours > 0 ? 2 : 1,
      reportId
    ]);

    await db.query('COMMIT');

    logger.info('부적합 원인 저장 성공', { reportId, count: defects?.length || 0 });
    return { success: true, count: defects?.length || 0, totalErrorHours };
  } catch (error) {
    await db.query('ROLLBACK');
    logger.error('부적합 원인 저장 실패', { reportId, error: error.message });
    throw new DatabaseError('부적합 원인 저장 중 오류가 발생했습니다');
  }
};

/**
 * 부적합 원인 추가 (단일)
 */
const addReportDefectService = async (reportId, defectData) => {
  const db = await getDb();
  try {
    const [result] = await db.execute(`
      INSERT INTO work_report_defects (report_id, error_type_id, issue_report_id, defect_hours, note)
      VALUES (?, ?, ?, ?, ?)
    `, [
      reportId,
      defectData.issue_report_id ? null : (defectData.error_type_id || null),
      defectData.issue_report_id || null,
      defectData.defect_hours || 0,
      defectData.note || null
    ]);

    await updateTotalErrorHours(reportId);

    logger.info('부적합 원인 추가 성공', { reportId, defectId: result.insertId });
    return { success: true, defect_id: result.insertId };
  } catch (error) {
    logger.error('부적합 원인 추가 실패', { reportId, error: error.message });
    throw new DatabaseError('부적합 원인 추가 중 오류가 발생했습니다');
  }
};

/**
 * 부적합 원인 삭제
 */
const removeReportDefectService = async (defectId) => {
  const db = await getDb();
  try {
    const [defect] = await db.execute('SELECT report_id FROM work_report_defects WHERE defect_id = ?', [defectId]);
    if (defect.length === 0) {
      throw new NotFoundError('부적합 원인을 찾을 수 없습니다');
    }

    const reportId = defect[0].report_id;

    await db.execute('DELETE FROM work_report_defects WHERE defect_id = ?', [defectId]);
    await updateTotalErrorHours(reportId);

    logger.info('부적합 원인 삭제 성공', { defectId, reportId });
    return { success: true };
  } catch (error) {
    if (error instanceof NotFoundError) throw error;
    logger.error('부적합 원인 삭제 실패', { defectId, error: error.message });
    throw new DatabaseError('부적합 원인 삭제 중 오류가 발생했습니다');
  }
};

/**
 * 총 부적합 시간 업데이트 헬퍼
 */
const updateTotalErrorHours = async (reportId) => {
  const db = await getDb();
  const [result] = await db.execute(`
    SELECT COALESCE(SUM(defect_hours), 0) as total
    FROM work_report_defects
    WHERE report_id = ?
  `, [reportId]);

  const totalErrorHours = result[0].total || 0;

  const [firstDefect] = await db.execute(`
    SELECT error_type_id FROM work_report_defects
    WHERE report_id = ? AND error_type_id IS NOT NULL
    ORDER BY created_at LIMIT 1
  `, [reportId]);

  await db.execute(`
    UPDATE daily_work_reports
    SET error_hours = ?,
        error_type_id = ?,
        work_status_id = ?
    WHERE id = ?
  `, [
    totalErrorHours,
    firstDefect.length > 0 ? firstDefect[0].error_type_id : null,
    totalErrorHours > 0 ? 2 : 1,
    reportId
  ]);
};

module.exports = {
  createWorkReportService,
  getWorkReportsByDateService,
  getWorkReportsInRangeService,
  getWorkReportByIdService,
  updateWorkReportService,
  removeWorkReportService,
  getSummaryService,
  getReportDefectsService,
  saveReportDefectsService,
  addReportDefectService,
  removeReportDefectService
};
