// models/equipmentModel.js
const { getDb } = require('../dbPool');
const notifyHelper = require('../shared/utils/notifyHelper');

const EquipmentModel = {
  // CREATE - 설비 생성
  create: async (equipmentData) => {
    const db = await getDb();
    const query = `
      INSERT INTO equipments (
        equipment_code, equipment_name, equipment_type, model_name,
        manufacturer, supplier, purchase_price, installation_date, serial_number, specifications,
        status, notes, workplace_id, map_x_percent, map_y_percent,
        map_width_percent, map_height_percent
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `;

    const values = [
      equipmentData.equipment_code,
      equipmentData.equipment_name,
      equipmentData.equipment_type || null,
      equipmentData.model_name || null,
      equipmentData.manufacturer || null,
      equipmentData.supplier || null,
      equipmentData.purchase_price || null,
      equipmentData.installation_date || null,
      equipmentData.serial_number || null,
      equipmentData.specifications || null,
      equipmentData.status || 'active',
      equipmentData.notes || null,
      equipmentData.workplace_id || null,
      equipmentData.map_x_percent || null,
      equipmentData.map_y_percent || null,
      equipmentData.map_width_percent || null,
      equipmentData.map_height_percent || null
    ];

    const [result] = await db.query(query, values);
    return {
      equipment_id: result.insertId,
      ...equipmentData
    };
  },

  // READ ALL - 모든 설비 조회 (필터링 옵션 포함)
  getAll: async (filters) => {
    const db = await getDb();
    let query = `
      SELECT
        e.*,
        w.workplace_name,
        wc.category_name
      FROM equipments e
      LEFT JOIN workplaces w ON e.workplace_id = w.workplace_id
      LEFT JOIN workplace_categories wc ON w.category_id = wc.category_id
      WHERE 1=1
    `;

    const values = [];

    if (filters.workplace_id) {
      query += ' AND e.workplace_id = ?';
      values.push(filters.workplace_id);
    }

    if (filters.equipment_type) {
      query += ' AND e.equipment_type = ?';
      values.push(filters.equipment_type);
    }

    if (filters.status) {
      query += ' AND e.status = ?';
      values.push(filters.status);
    }

    if (filters.search) {
      query += ' AND (e.equipment_name LIKE ? OR e.equipment_code LIKE ?)';
      const searchTerm = `%${filters.search}%`;
      values.push(searchTerm, searchTerm);
    }

    query += ' ORDER BY e.equipment_code ASC';

    const [rows] = await db.query(query, values);
    return rows;
  },

  // READ ONE - 특정 설비 조회
  getById: async (equipmentId) => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT
        e.*,
        w.workplace_name,
        wc.category_name
      FROM equipments e
      LEFT JOIN workplaces w ON e.workplace_id = w.workplace_id
      LEFT JOIN workplace_categories wc ON w.category_id = wc.category_id
      WHERE e.equipment_id = ?`,
      [equipmentId]
    );
    return rows[0];
  },

  // READ BY WORKPLACE - 특정 작업장의 설비 조회
  getByWorkplace: async (workplaceId) => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT e.*
      FROM equipments e
      WHERE e.workplace_id = ?
      ORDER BY e.equipment_code ASC`,
      [workplaceId]
    );
    return rows;
  },

  // READ ACTIVE - 활성 설비만 조회
  getActive: async () => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT
        e.*,
        w.workplace_name,
        wc.category_name
      FROM equipments e
      LEFT JOIN workplaces w ON e.workplace_id = w.workplace_id
      LEFT JOIN workplace_categories wc ON w.category_id = wc.category_id
      WHERE e.status = 'active'
      ORDER BY e.equipment_code ASC`
    );
    return rows;
  },

  // UPDATE - 설비 수정
  update: async (equipmentId, equipmentData) => {
    const db = await getDb();
    const values = [
      equipmentData.equipment_code,
      equipmentData.equipment_name,
      equipmentData.equipment_type || null,
      equipmentData.model_name || null,
      equipmentData.manufacturer || null,
      equipmentData.supplier || null,
      equipmentData.purchase_price || null,
      equipmentData.installation_date || null,
      equipmentData.serial_number || null,
      equipmentData.specifications || null,
      equipmentData.status || 'active',
      equipmentData.notes || null,
      equipmentData.workplace_id || null,
      equipmentData.map_x_percent || null,
      equipmentData.map_y_percent || null,
      equipmentData.map_width_percent || null,
      equipmentData.map_height_percent || null,
      equipmentId
    ];

    const [result] = await db.query(
      `UPDATE equipments SET
        equipment_code = ?,
        equipment_name = ?,
        equipment_type = ?,
        model_name = ?,
        manufacturer = ?,
        supplier = ?,
        purchase_price = ?,
        installation_date = ?,
        serial_number = ?,
        specifications = ?,
        status = ?,
        notes = ?,
        workplace_id = ?,
        map_x_percent = ?,
        map_y_percent = ?,
        map_width_percent = ?,
        map_height_percent = ?,
        updated_at = NOW()
      WHERE equipment_id = ?`,
      values
    );

    if (result.affectedRows === 0) {
      throw new Error('Equipment not found');
    }
    return { equipment_id: equipmentId, ...equipmentData };
  },

  // UPDATE MAP POSITION - 지도상 위치 업데이트
  updateMapPosition: async (equipmentId, positionData) => {
    const db = await getDb();

    const hasWorkplaceId = positionData.workplace_id !== undefined;

    const query = hasWorkplaceId ? `
      UPDATE equipments SET
        workplace_id = ?,
        map_x_percent = ?,
        map_y_percent = ?,
        map_width_percent = ?,
        map_height_percent = ?,
        updated_at = NOW()
      WHERE equipment_id = ?
    ` : `
      UPDATE equipments SET
        map_x_percent = ?,
        map_y_percent = ?,
        map_width_percent = ?,
        map_height_percent = ?,
        updated_at = NOW()
      WHERE equipment_id = ?
    `;

    const values = hasWorkplaceId ? [
      positionData.workplace_id,
      positionData.map_x_percent,
      positionData.map_y_percent,
      positionData.map_width_percent,
      positionData.map_height_percent,
      equipmentId
    ] : [
      positionData.map_x_percent,
      positionData.map_y_percent,
      positionData.map_width_percent,
      positionData.map_height_percent,
      equipmentId
    ];

    const [result] = await db.query(query, values);
    if (result.affectedRows === 0) {
      throw new Error('Equipment not found');
    }
    return { equipment_id: equipmentId, ...positionData };
  },

  // DELETE - 설비 삭제
  delete: async (equipmentId) => {
    const db = await getDb();
    const [result] = await db.query('DELETE FROM equipments WHERE equipment_id = ?', [equipmentId]);
    if (result.affectedRows === 0) {
      throw new Error('Equipment not found');
    }
    return { equipment_id: equipmentId };
  },

  // CHECK DUPLICATE CODE - 설비 코드 중복 확인
  checkDuplicateCode: async (equipmentCode, excludeEquipmentId) => {
    const db = await getDb();
    let query = 'SELECT equipment_id FROM equipments WHERE equipment_code = ?';
    const values = [equipmentCode];

    if (excludeEquipmentId) {
      query += ' AND equipment_id != ?';
      values.push(excludeEquipmentId);
    }

    const [rows] = await db.query(query, values);
    return rows.length > 0;
  },

  // GET EQUIPMENT TYPES - 사용 중인 설비 유형 목록 조회
  getEquipmentTypes: async () => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT DISTINCT equipment_type
      FROM equipments
      WHERE equipment_type IS NOT NULL
      ORDER BY equipment_type ASC`
    );
    return rows.map(row => row.equipment_type);
  },

  // GET NEXT EQUIPMENT CODE - 다음 관리번호 자동 생성
  getNextEquipmentCode: async (prefix = 'TKP') => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT equipment_code
      FROM equipments
      WHERE equipment_code LIKE ?
      ORDER BY equipment_code DESC
      LIMIT 1`,
      [`${prefix}-%`]
    );

    let nextNumber = 1;
    if (rows.length > 0) {
      const lastCode = rows[0].equipment_code;
      const match = lastCode.match(new RegExp(`^${prefix}-(\\d+)$`));
      if (match) {
        nextNumber = parseInt(match[1], 10) + 1;
      }
    }

    return `${prefix}-${String(nextNumber).padStart(3, '0')}`;
  },

  // ==========================================
  // 설비 사진 관리
  // ==========================================

  addPhoto: async (equipmentId, photoData) => {
    const db = await getDb();
    const values = [
      equipmentId,
      photoData.photo_path,
      photoData.description || null,
      photoData.display_order || 0,
      photoData.uploaded_by || null
    ];

    const [result] = await db.query(
      `INSERT INTO equipment_photos (
        equipment_id, photo_path, description, display_order, uploaded_by
      ) VALUES (?, ?, ?, ?, ?)`,
      values
    );

    return {
      photo_id: result.insertId,
      equipment_id: equipmentId,
      ...photoData
    };
  },

  getPhotos: async (equipmentId) => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT ep.*, u.name AS uploaded_by_name
      FROM equipment_photos ep
      LEFT JOIN users u ON ep.uploaded_by = u.user_id
      WHERE ep.equipment_id = ?
      ORDER BY ep.display_order ASC, ep.created_at ASC`,
      [equipmentId]
    );
    return rows;
  },

  deletePhoto: async (photoId) => {
    const db = await getDb();

    const [photo] = await db.query(
      'SELECT photo_path FROM equipment_photos WHERE photo_id = ?',
      [photoId]
    );

    const [result] = await db.query('DELETE FROM equipment_photos WHERE photo_id = ?', [photoId]);

    if (result.affectedRows === 0) {
      throw new Error('Photo not found');
    }

    return { photo_id: photoId, photo_path: photo[0]?.photo_path };
  },

  // ==========================================
  // 설비 임시 이동
  // ==========================================

  moveTemporarily: async (equipmentId, moveData) => {
    const db = await getDb();

    const [result] = await db.query(
      `UPDATE equipments SET
        current_workplace_id = ?,
        current_map_x_percent = ?,
        current_map_y_percent = ?,
        current_map_width_percent = ?,
        current_map_height_percent = ?,
        is_temporarily_moved = TRUE,
        moved_at = NOW(),
        moved_by = ?,
        updated_at = NOW()
      WHERE equipment_id = ?`,
      [
        moveData.target_workplace_id,
        moveData.target_x_percent,
        moveData.target_y_percent,
        moveData.target_width_percent || null,
        moveData.target_height_percent || null,
        moveData.moved_by || null,
        equipmentId
      ]
    );

    if (result.affectedRows === 0) {
      throw new Error('Equipment not found');
    }

    await db.query(
      `INSERT INTO equipment_move_logs (
        equipment_id, move_type,
        from_workplace_id, to_workplace_id,
        from_x_percent, from_y_percent,
        to_x_percent, to_y_percent,
        reason, moved_by
      ) VALUES (?, 'temporary', ?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        equipmentId,
        moveData.from_workplace_id || null,
        moveData.target_workplace_id,
        moveData.from_x_percent || null,
        moveData.from_y_percent || null,
        moveData.target_x_percent,
        moveData.target_y_percent,
        moveData.reason || null,
        moveData.moved_by || null
      ]
    );

    return { equipment_id: equipmentId, moved: true };
  },

  returnToOriginal: async (equipmentId, userId) => {
    const db = await getDb();

    const [equipment] = await db.query(
      'SELECT current_workplace_id, current_map_x_percent, current_map_y_percent FROM equipments WHERE equipment_id = ?',
      [equipmentId]
    );

    if (!equipment[0]) {
      throw new Error('Equipment not found');
    }

    await db.query(
      `UPDATE equipments SET
        current_workplace_id = NULL,
        current_map_x_percent = NULL,
        current_map_y_percent = NULL,
        current_map_width_percent = NULL,
        current_map_height_percent = NULL,
        is_temporarily_moved = FALSE,
        moved_at = NULL,
        moved_by = NULL,
        updated_at = NOW()
      WHERE equipment_id = ?`,
      [equipmentId]
    );

    await db.query(
      `INSERT INTO equipment_move_logs (
        equipment_id, move_type,
        from_workplace_id, from_x_percent, from_y_percent,
        reason, moved_by
      ) VALUES (?, 'return', ?, ?, ?, '원위치 복귀', ?)`,
      [
        equipmentId,
        equipment[0].current_workplace_id,
        equipment[0].current_map_x_percent,
        equipment[0].current_map_y_percent,
        userId || null
      ]
    );

    return { equipment_id: equipmentId, returned: true };
  },

  getTemporarilyMoved: async () => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT
        e.*,
        w_orig.workplace_name AS original_workplace_name,
        w_curr.workplace_name AS current_workplace_name,
        u.name AS moved_by_name
      FROM equipments e
      LEFT JOIN workplaces w_orig ON e.workplace_id = w_orig.workplace_id
      LEFT JOIN workplaces w_curr ON e.current_workplace_id = w_curr.workplace_id
      LEFT JOIN users u ON e.moved_by = u.user_id
      WHERE e.is_temporarily_moved = TRUE
      ORDER BY e.moved_at DESC`
    );
    return rows;
  },

  getMoveLogs: async (equipmentId) => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT
        eml.*,
        w_from.workplace_name AS from_workplace_name,
        w_to.workplace_name AS to_workplace_name,
        u.name AS moved_by_name
      FROM equipment_move_logs eml
      LEFT JOIN workplaces w_from ON eml.from_workplace_id = w_from.workplace_id
      LEFT JOIN workplaces w_to ON eml.to_workplace_id = w_to.workplace_id
      LEFT JOIN users u ON eml.moved_by = u.user_id
      WHERE eml.equipment_id = ?
      ORDER BY eml.moved_at DESC`,
      [equipmentId]
    );
    return rows;
  },

  // ==========================================
  // 설비 외부 반출/반입
  // ==========================================

  exportEquipment: async (exportData) => {
    const db = await getDb();

    const [logResult] = await db.query(
      `INSERT INTO equipment_external_logs (
        equipment_id, log_type, export_date, expected_return_date,
        destination, reason, notes, exported_by
      ) VALUES (?, 'export', ?, ?, ?, ?, ?, ?)`,
      [
        exportData.equipment_id,
        exportData.export_date || new Date().toISOString().slice(0, 10),
        exportData.expected_return_date || null,
        exportData.destination || null,
        exportData.reason || null,
        exportData.notes || null,
        exportData.exported_by || null
      ]
    );

    const status = exportData.is_repair ? 'repair_external' : 'external';
    await db.query(
      'UPDATE equipments SET status = ?, updated_at = NOW() WHERE equipment_id = ?',
      [status, exportData.equipment_id]
    );

    return {
      log_id: logResult.insertId,
      equipment_id: exportData.equipment_id,
      exported: true
    };
  },

  returnEquipment: async (logId, returnData) => {
    const db = await getDb();

    const [logs] = await db.query(
      'SELECT equipment_id FROM equipment_external_logs WHERE log_id = ?',
      [logId]
    );

    if (!logs[0]) {
      throw new Error('Export log not found');
    }

    const equipmentId = logs[0].equipment_id;

    await db.query(
      `UPDATE equipment_external_logs SET
        actual_return_date = ?,
        returned_by = ?,
        notes = CONCAT(IFNULL(notes, ''), '\n반입: ', IFNULL(?, '')),
        updated_at = NOW()
      WHERE log_id = ?`,
      [
        returnData.return_date || new Date().toISOString().slice(0, 10),
        returnData.returned_by || null,
        returnData.notes || '',
        logId
      ]
    );

    await db.query(
      'UPDATE equipments SET status = ?, updated_at = NOW() WHERE equipment_id = ?',
      [returnData.new_status || 'active', equipmentId]
    );

    return {
      log_id: logId,
      equipment_id: equipmentId,
      returned: true
    };
  },

  getExternalLogs: async (equipmentId) => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT
        eel.*,
        u_exp.name AS exported_by_name,
        u_ret.name AS returned_by_name
      FROM equipment_external_logs eel
      LEFT JOIN users u_exp ON eel.exported_by = u_exp.user_id
      LEFT JOIN users u_ret ON eel.returned_by = u_ret.user_id
      WHERE eel.equipment_id = ?
      ORDER BY eel.created_at DESC`,
      [equipmentId]
    );
    return rows;
  },

  getExportedEquipments: async () => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT
        e.*,
        w.workplace_name,
        eel.export_date,
        eel.expected_return_date,
        eel.destination,
        eel.reason,
        u.name AS exported_by_name
      FROM equipments e
      INNER JOIN (
        SELECT equipment_id, MAX(log_id) AS latest_log_id
        FROM equipment_external_logs
        WHERE actual_return_date IS NULL
        GROUP BY equipment_id
      ) latest ON e.equipment_id = latest.equipment_id
      INNER JOIN equipment_external_logs eel ON eel.log_id = latest.latest_log_id
      LEFT JOIN workplaces w ON e.workplace_id = w.workplace_id
      LEFT JOIN users u ON eel.exported_by = u.user_id
      WHERE e.status IN ('external', 'repair_external')
      ORDER BY eel.export_date DESC`
    );
    return rows;
  },

  // ==========================================
  // 설비 수리 신청
  // ==========================================

  createRepairRequest: async (requestData) => {
    const db = await getDb();

    const [categories] = await db.query(
      "SELECT category_id FROM issue_report_categories WHERE category_name = '설비 수리' LIMIT 1"
    );

    if (!categories[0]) {
      throw new Error('설비 수리 카테고리가 없습니다');
    }

    const categoryId = categories[0].category_id;

    let itemId = requestData.item_id;
    if (!itemId) {
      const [items] = await db.query(
        'SELECT item_id FROM issue_report_items WHERE category_id = ? LIMIT 1',
        [categoryId]
      );
      itemId = items[0]?.item_id;
    }

    const photos = requestData.photo_paths || [];

    const [result] = await db.query(
      `INSERT INTO work_issue_reports (
        reporter_id, issue_category_id, issue_item_id,
        workplace_id, equipment_id,
        additional_description,
        photo_path1, photo_path2, photo_path3, photo_path4, photo_path5,
        status
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'reported')`,
      [
        requestData.reported_by || null,
        categoryId,
        itemId,
        requestData.workplace_id || null,
        requestData.equipment_id,
        requestData.description || null,
        photos[0] || null,
        photos[1] || null,
        photos[2] || null,
        photos[3] || null,
        photos[4] || null
      ]
    );

    await db.query(
      'UPDATE equipments SET status = ?, updated_at = NOW() WHERE equipment_id = ?',
      ['repair_needed', requestData.equipment_id]
    );

    // fire-and-forget: 알림 실패가 수리 신청을 블로킹하면 안 됨
    notifyHelper.send({
      type: 'repair',
      title: `수리 신청: ${requestData.equipment_name || '설비'}`,
      message: `${requestData.repair_type || '일반 수리'} 수리가 신청되었습니다.`,
      link_url: '/pages/admin/repair-management.html',
      reference_type: 'work_issue_reports',
      reference_id: result.insertId,
      created_by: requestData.reported_by
    }).catch(() => {});

    return {
      report_id: result.insertId,
      equipment_id: requestData.equipment_id,
      created: true
    };
  },

  getRepairHistory: async (equipmentId) => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT
        wir.*,
        irc.category_name,
        iri.item_name,
        u_rep.name AS reported_by_name,
        u_res.name AS resolved_by_name,
        w.workplace_name
      FROM work_issue_reports wir
      LEFT JOIN issue_report_categories irc ON wir.issue_category_id = irc.category_id
      LEFT JOIN issue_report_items iri ON wir.issue_item_id = iri.item_id
      LEFT JOIN users u_rep ON wir.reporter_id = u_rep.user_id
      LEFT JOIN users u_res ON wir.resolved_by = u_res.user_id
      LEFT JOIN workplaces w ON wir.workplace_id = w.workplace_id
      WHERE wir.equipment_id = ?
      ORDER BY wir.created_at DESC`,
      [equipmentId]
    );
    return rows;
  },

  getRepairRequests: async (status) => {
    const db = await getDb();
    let query = `
      SELECT wir.report_id, wir.status, wir.additional_description, wir.created_at,
             e.equipment_name, irc.category_name, iri.item_name,
             u_rep.name AS reported_by_name, w.workplace_name
      FROM work_issue_reports wir
      INNER JOIN issue_report_categories irc ON wir.issue_category_id = irc.category_id
      LEFT JOIN issue_report_items iri ON wir.issue_item_id = iri.item_id
      LEFT JOIN equipments e ON wir.equipment_id = e.equipment_id
      LEFT JOIN users u_rep ON wir.reporter_id = u_rep.user_id
      LEFT JOIN workplaces w ON wir.workplace_id = w.workplace_id
      WHERE irc.category_name = '설비 수리'
    `;
    const values = [];

    if (status) {
      query += ' AND wir.status = ?';
      values.push(status);
    }

    query += ' ORDER BY wir.created_at DESC';

    const [rows] = await db.query(query, values);
    return rows;
  },

  getRepairCategories: async () => {
    const db = await getDb();
    const [rows] = await db.query(
      `SELECT iri.item_id, iri.item_name, iri.description, iri.severity
      FROM issue_report_items iri
      INNER JOIN issue_report_categories irc ON iri.category_id = irc.category_id
      WHERE irc.category_name = '설비 수리' AND iri.is_active = 1
      ORDER BY iri.display_order ASC`
    );
    return rows;
  },

  addRepairCategory: async (itemName) => {
    const db = await getDb();

    const [categories] = await db.query(
      "SELECT category_id FROM issue_report_categories WHERE category_name = '설비 수리'"
    );

    if (categories.length === 0) {
      throw new Error('설비 수리 카테고리가 없습니다.');
    }

    const categoryId = categories[0].category_id;

    const [existing] = await db.query(
      'SELECT item_id FROM issue_report_items WHERE category_id = ? AND item_name = ?',
      [categoryId, itemName]
    );

    if (existing.length > 0) {
      return { item_id: existing[0].item_id, item_name: itemName, isNew: false };
    }

    const [maxOrder] = await db.query(
      'SELECT MAX(display_order) as max_order FROM issue_report_items WHERE category_id = ?',
      [categoryId]
    );
    const nextOrder = (maxOrder[0].max_order || 0) + 1;

    const [result] = await db.query(
      `INSERT INTO issue_report_items (category_id, item_name, display_order, is_active)
       VALUES (?, ?, ?, 1)`,
      [categoryId, itemName, nextOrder]
    );

    return { item_id: result.insertId, item_name: itemName, isNew: true };
  }
};

module.exports = EquipmentModel;
