// tbm.js - TBM 관리 페이지 JavaScript
// 전역 변수: TbmState 프록시 사용 (state.js에서 정의)
// allSessions, todaySessions, allWorkers, allProjects, allWorkTypes, allTasks,
// allSafetyChecks, allWorkplaces, allWorkplaceCategories, currentUser,
// currentSessionId, selectedWorkers, workerTaskList, selectedWorkersInModal,
// currentEditingTaskLine, selectedCategory, selectedWorkplace, selectedCategoryName,
// selectedWorkplaceName, isBulkMode, bulkSelectedWorkers, loadedDaysCount,
// dateGroupedSessions, allLoadedSessions → window 프록시로 접근

// UI 전용 변수 (프록시 없음)
let currentTab = 'tbm-input';

// 모달 스크롤 잠금
let scrollLockY = 0;
let scrollLockCount = 0;
function lockBodyScroll() {
  scrollLockCount++;
  if (scrollLockCount > 1) return; // 이미 잠금 상태
  scrollLockY = window.scrollY;
  document.body.style.overflow = 'hidden';
  document.body.style.position = 'fixed';
  document.body.style.width = '100%';
  document.body.style.top = `-${scrollLockY}px`;
  document.body.classList.add('tbm-modal-open');
}
function unlockBodyScroll() {
  scrollLockCount--;
  if (scrollLockCount > 0) return; // 아직 열린 모달 있음
  scrollLockCount = 0;
  document.body.style.overflow = '';
  document.body.style.position = '';
  document.body.style.width = '';
  document.body.style.top = '';
  window.scrollTo(0, scrollLockY);
  document.body.classList.remove('tbm-modal-open');
}

// ==================== 유틸리티 함수 (CommonUtils 위임) ====================
// getTodayKST, formatDate → window.CommonUtils 사용 (common/utils.js)
function getTodayKST() { return window.CommonUtils.getTodayKST(); }
function formatDate(d) { return window.CommonUtils.formatDate(d); }

// ==================== 페이지 초기화 ====================

// 페이지 초기화
document.addEventListener('DOMContentLoaded', async () => {

  // API 함수가 로드될 때까지 대기
  let retryCount = 0;
  while (!window.apiCall && retryCount < 50) {
    await new Promise(resolve => setTimeout(resolve, 100));
    retryCount++;
  }

  if (!window.apiCall) {
    showToast('시스템을 초기화할 수 없습니다. 페이지를 새로고침해주세요.', 'error');
    return;
  }

  // 오늘 날짜 설정 (서울 시간대 기준)
  const today = getTodayKST();
  const tbmDateEl = document.getElementById('tbmDate');
  const sessionDateEl = document.getElementById('sessionDate');
  if (tbmDateEl) tbmDateEl.value = today;
  if (sessionDateEl) sessionDateEl.value = today;

  // 이벤트 리스너 설정
  setupEventListeners();

  // 초기 데이터 로드
  await loadInitialData();
  await loadTodayOnlyTbm();
});

// 이벤트 리스너 설정
function setupEventListeners() {
  // 날짜 선택기 제거됨 - 날짜별 그룹 뷰 사용
}

// 초기 데이터 로드 → TbmAPI 위임
async function loadInitialData() {
  await window.TbmAPI.loadInitialData();
  // TbmAPI가 TbmState에 데이터를 설정 → 프록시를 통해 전역 변수로 접근 가능
  // UI 드롭다운 채우기
  populateProjectSelect();
}

// ==================== 탭 전환 ====================

// 탭 전환
function switchTbmTab(tabName) {
  currentTab = tabName;

  // 탭 버튼 활성화 상태 변경
  document.querySelectorAll('.tbm-tab-btn').forEach(btn => {
    if (btn.dataset.tab === tabName) {
      btn.classList.add('active');
    } else {
      btn.classList.remove('active');
    }
  });

  // 탭 컨텐츠 표시 변경
  document.querySelectorAll('.tbm-tab-content').forEach(content => {
    content.classList.remove('active');
  });
  document.getElementById(`${tabName}-tab`).classList.add('active');

  // 탭에 따라 데이터 로드
  if (tabName === 'tbm-input') {
    loadTodayOnlyTbm();
  } else if (tabName === 'tbm-manage') {
    loadRecentTbmGroupedByDate();
  }
}
window.switchTbmTab = switchTbmTab;

// ==================== TBM 입력 탭 ====================

// 오늘의 TBM만 로드 → TbmAPI 위임
async function loadTodayOnlyTbm() {
  await window.TbmAPI.loadTodayOnlyTbm();
  displayTodayTbmSessions();
}
window.loadTodayOnlyTbm = loadTodayOnlyTbm;

// 오늘의 TBM 세션 표시
function displayTodayTbmSessions() {
  const grid = document.getElementById('todayTbmGrid');
  const emptyState = document.getElementById('todayEmptyState');
  const todayTotalEl = document.getElementById('todayTotalSessions');
  const todayCompletedEl = document.getElementById('todayCompletedSessions');
  const todayActiveEl = document.getElementById('todayActiveSessions');

  if (todaySessions.length === 0) {
    grid.innerHTML = '';
    emptyState.style.display = 'flex';
    todayTotalEl.textContent = '0';
    todayCompletedEl.textContent = '0';
    todayActiveEl.textContent = '0';
    return;
  }

  emptyState.style.display = 'none';

  const completedCount = todaySessions.filter(s => s.status === 'completed').length;
  const activeCount = todaySessions.filter(s => s.status === 'draft').length;

  todayTotalEl.textContent = todaySessions.length;
  todayCompletedEl.textContent = completedCount;
  todayActiveEl.textContent = activeCount;

  grid.innerHTML = todaySessions.map(session => createSessionCard(session)).join('');
}

// ==================== TBM 관리 탭 ====================

// 레거시 호환 → api.js의 window alias 사용

// ==================== 날짜별 그룹 TBM 로드 (새 기능) ====================

function isAdminUser() { return window.TbmState.isAdminUser(); }

/**
 * 최근 TBM을 날짜별로 그룹화하여 로드 → TbmAPI 위임
 */
async function loadRecentTbmGroupedByDate() {
  await window.TbmAPI.loadRecentTbmGroupedByDate();
  // TbmState에 dateGroupedSessions, allLoadedSessions가 설정됨
  displayTbmGroupedByDate();
  updateViewModeIndicator();
}
window.loadRecentTbmGroupedByDate = loadRecentTbmGroupedByDate;

/**
 * 뷰 모드 표시 업데이트
 */
function updateViewModeIndicator() {
  const indicator = document.getElementById('viewModeIndicator');
  const text = document.getElementById('viewModeText');

  if (indicator && text) {
    if (isAdminUser()) {
      indicator.style.display = 'none'; // Admin은 표시 안 함 (전체가 기본)
    } else {
      indicator.style.display = 'inline-flex';
      text.textContent = '내 TBM';
    }
  }
}

/**
 * 날짜별 그룹으로 TBM 표시
 */
function displayTbmGroupedByDate() {
  const container = document.getElementById('tbmDateGroupsContainer');
  const emptyState = document.getElementById('emptyState');
  const totalSessionsEl = document.getElementById('totalSessions');
  const completedSessionsEl = document.getElementById('completedSessions');

  if (!container) return;

  // 날짜별로 정렬 (최신순)
  const sortedDates = Object.keys(dateGroupedSessions).sort((a, b) => new Date(b) - new Date(a));

  if (sortedDates.length === 0 || allLoadedSessions.length === 0) {
    container.innerHTML = '';
    if (emptyState) emptyState.style.display = 'flex';
    if (totalSessionsEl) totalSessionsEl.textContent = '0';
    if (completedSessionsEl) completedSessionsEl.textContent = '0';
    return;
  }

  if (emptyState) emptyState.style.display = 'none';

  // 통계 업데이트
  const completedCount = allLoadedSessions.filter(s => s.status === 'completed').length;
  if (totalSessionsEl) totalSessionsEl.textContent = allLoadedSessions.length;
  if (completedSessionsEl) completedSessionsEl.textContent = completedCount;

  // 날짜별 그룹 HTML 생성
  const today = getTodayKST();
  const dayNames = ['일', '월', '화', '수', '목', '금', '토'];

  container.innerHTML = sortedDates.map(date => {
    const sessions = dateGroupedSessions[date];
    const dateObj = new Date(date + 'T00:00:00');
    const dayName = dayNames[dateObj.getDay()];
    const isToday = date === today;

    // 날짜 포맷팅 (YYYY-MM-DD → MM월 DD일)
    const [year, month, day] = date.split('-');
    const displayDate = `${parseInt(month)}월 ${parseInt(day)}일`;

    return `
      <div class="tbm-date-group" data-date="${date}">
        <div class="tbm-date-header ${isToday ? 'today' : ''}" onclick="toggleDateGroup('${date}')">
          <span class="tbm-date-toggle">&#9660;</span>
          <span class="tbm-date-title">${displayDate}</span>
          <span class="tbm-date-day">${dayName}요일</span>
          ${isToday ? '<span class="tbm-today-badge">오늘</span>' : ''}
          <span class="tbm-date-count">${sessions.length}건</span>
        </div>
        <div class="tbm-date-content">
          <div class="tbm-date-grid">
            ${sessions.map(session => createSessionCard(session)).join('')}
          </div>
        </div>
      </div>
    `;
  }).join('');
}

// 날짜 그룹 토글
function toggleDateGroup(date) {
  const group = document.querySelector(`.tbm-date-group[data-date="${date}"]`);
  if (group) {
    group.classList.toggle('collapsed');
  }
}
window.toggleDateGroup = toggleDateGroup;

/**
 * 더 많은 날짜 로드
 */
// loadMoreTbmDays → api.js의 window alias 사용

// 특정 날짜의 TBM 세션 목록 로드 → TbmAPI 위임
async function loadTbmSessionsByDate(date) {
  await window.TbmAPI.loadTbmSessionsByDate(date);
  displayTbmSessions();
}

// TBM 세션 목록 표시 (관리 탭용) - 레거시 호환 (날짜별 그룹 뷰 사용)
function displayTbmSessions() {
  // 새 날짜별 그룹 뷰로 리다이렉트
  if (allSessions.length > 0) {
    // allSessions를 날짜별로 그룹화
    dateGroupedSessions = {};
    allSessions.forEach(session => {
      const date = formatDate(session.session_date);
      if (!dateGroupedSessions[date]) {
        dateGroupedSessions[date] = [];
      }
      dateGroupedSessions[date].push(session);
    });
    allLoadedSessions = allSessions;
  }
  displayTbmGroupedByDate();
}

// TBM 세션 카드 생성 (공통)
function createSessionCard(session) {
  const statusBadge = {
    'draft': '<span class="tbm-card-status draft">진행중</span>',
    'completed': '<span class="tbm-card-status completed">완료</span>',
    'cancelled': '<span class="tbm-card-status cancelled">취소</span>'
  }[session.status] || '';

  const leaderName = escapeHtml(session.leader_name || session.created_by_name || '작업 책임자');
  const leaderRole = escapeHtml(session.leader_name
    ? (session.leader_job_type || '작업자')
    : '관리자');
  const safeSessionId = parseInt(session.session_id) || 0;

  // 카드 클릭 동작: draft → 세부 편집, completed → 상세 보기
  const onClickAction = session.status === 'draft'
    ? `openTeamCompositionModal(${safeSessionId})`
    : `viewTbmSession(${safeSessionId})`;

  return `
    <div class="tbm-session-card" onclick="${onClickAction}">
      <div class="tbm-card-header">
        <div class="tbm-card-header-top">
          <div>
            <h3 class="tbm-card-leader">
              ${leaderName}
              <span class="tbm-card-leader-role">${leaderRole}</span>
            </h3>
          </div>
          ${statusBadge}
        </div>
        <div class="tbm-card-date">
          <span>&#128197;</span>
          ${escapeHtml(formatDate(session.session_date))} ${session.start_time ? '| ' + escapeHtml(session.start_time) : ''}
        </div>
      </div>

      <div class="tbm-card-body">
        <div class="tbm-card-info-grid">
          <div class="tbm-card-info-item">
            <span class="tbm-card-info-label">프로젝트</span>
            <span class="tbm-card-info-value">${escapeHtml(session.project_name || '-')}</span>
          </div>
          <div class="tbm-card-info-item">
            <span class="tbm-card-info-label">공정</span>
            <span class="tbm-card-info-value">${escapeHtml(session.work_type_name || '-')}</span>
          </div>
          <div class="tbm-card-info-item">
            <span class="tbm-card-info-label">작업장</span>
            <span class="tbm-card-info-value">${escapeHtml(session.work_location || '-')}</span>
          </div>
          <div class="tbm-card-info-item">
            <span class="tbm-card-info-label">팀원</span>
            <span class="tbm-card-info-value">${escapeHtml(session.team_member_names || '')}${session.team_member_names ? '' : '없음'}</span>
          </div>
        </div>
      </div>

      ${session.status === 'draft' ? `
        <div class="tbm-card-footer">
          <button class="tbm-btn tbm-btn-primary tbm-btn-sm" onclick="event.stopPropagation(); openTeamCompositionModal(${safeSessionId})">
            &#128101; 세부 편집
          </button>
          <button class="tbm-btn tbm-btn-secondary tbm-btn-sm" onclick="event.stopPropagation(); openSafetyCheckModal(${safeSessionId})">
            &#10003; 안전 체크
          </button>
          <button class="tbm-btn tbm-btn-success tbm-btn-sm" onclick="event.stopPropagation(); openCompleteTbmModal(${safeSessionId})">
            &#9989; 완료
          </button>
          <button class="tbm-btn tbm-btn-danger tbm-btn-sm" onclick="event.stopPropagation(); confirmDeleteTbm(${safeSessionId})">
            &#128465; 삭제
          </button>
        </div>
      ` : ''}
    </div>
  `;
}

// 새 TBM 모달 열기 (간소화: 프로젝트+공정+작업자만)
function openNewTbmModal() {
  if (window.innerWidth <= 768) {
    window.location.href = '/pages/work/tbm-create.html';
    return;
  }
  currentSessionId = null;
  workerTaskList = [];
  selectedWorkersForNewTbm = new Set();
  todayAssignmentsMap = null; // 배정 현황 캐시 초기화

  document.getElementById('modalTitle').innerHTML = '<span>&#128221;</span> 새 TBM 시작';
  document.getElementById('sessionId').value = '';
  document.getElementById('tbmForm').reset();

  const today = getTodayKST();
  document.getElementById('sessionDate').value = today;

  // 날짜 표시 업데이트
  const [year, month, day] = today.split('-');
  const dayNames = ['일', '월', '화', '수', '목', '금', '토'];
  const dateObj = new Date(today);
  const dayName = dayNames[dateObj.getDay()];
  const sessionDateDisplay = document.getElementById('sessionDateDisplay');
  if (sessionDateDisplay) {
    sessionDateDisplay.textContent = `${year}년 ${parseInt(month)}월 ${parseInt(day)}일 (${dayName})`;
  }

  // 입력자 자동 설정
  if (currentUser && currentUser.user_id) {
    const worker = allWorkers.find(w => w.user_id === currentUser.user_id);
    if (worker) {
      document.getElementById('leaderName').textContent = worker.worker_name;
      document.getElementById('leaderId').value = worker.user_id;
    } else {
      // 어드민: 작업자 목록에 없음 → 이름 표시, leaderId 비움
      document.getElementById('leaderName').textContent = currentUser.name || '관리자';
      document.getElementById('leaderId').value = '';
    }
  } else if (currentUser && currentUser.name) {
    document.getElementById('leaderName').textContent = currentUser.name;
    document.getElementById('leaderId').value = '';
  }

  // 프로젝트 드롭다운 채우기
  const projSelect = document.getElementById('newTbmProjectId');
  if (projSelect) {
    projSelect.innerHTML = '<option value="">선택 안함</option>' +
      allProjects.map(p => `<option value="${p.project_id}">${escapeHtml(p.project_name)} (${escapeHtml(p.job_no || '')})</option>`).join('');
  }

  // 공정 드롭다운 채우기
  const wtSelect = document.getElementById('newTbmWorkTypeId');
  if (wtSelect) {
    wtSelect.innerHTML = '<option value="">공정 선택...</option>' +
      allWorkTypes.map(wt => `<option value="${wt.id}">${escapeHtml(wt.name)}</option>`).join('');
  }

  // 작업자 체크박스 그리드 렌더링
  renderNewTbmWorkerGrid();

  document.getElementById('tbmModal').style.display = 'flex';
  lockBodyScroll();
}
window.openNewTbmModal = openNewTbmModal;

// 새 TBM 모달용 작업자 선택 세트
let selectedWorkersForNewTbm = new Set();
let todayAssignmentsMap = null; // 당일 배정 현황

// 작업자 그리드 렌더링
async function renderNewTbmWorkerGrid() {
  const grid = document.getElementById('newTbmWorkerGrid');
  if (!grid) return;

  // 당일 배정 현황 로드
  if (!todayAssignmentsMap) {
    try {
      const today = getTodayKST();
      const assignments = await window.TbmAPI.loadTodayAssignments(today);
      todayAssignmentsMap = {};
      assignments.forEach(a => {
        if (a.sessions && a.sessions.length > 0) {
          todayAssignmentsMap[a.user_id] = a;
        }
      });
    } catch(e) {
      console.error('배정 현황 로드 오류:', e);
      todayAssignmentsMap = {};
    }
  }

  grid.innerHTML = allWorkers.map(w => {
    const checked = selectedWorkersForNewTbm.has(w.user_id) ? 'checked' : '';
    const assignment = todayAssignmentsMap[w.user_id];
    const assigned = assignment && assignment.sessions && assignment.sessions.length > 0;

    let badgeHtml = '';
    let disabledAttr = '';
    let disabledStyle = '';

    if (assigned) {
      const leaderNames = assignment.sessions.map(s => s.leader_name || '').join(', ');
      badgeHtml = `<span style="font-size:0.625rem; color:#ef4444; display:block;">배정됨 - ${escapeHtml(leaderNames)} TBM</span>`;
      disabledAttr = 'disabled';
      disabledStyle = 'opacity:0.5; pointer-events:none;';
    }

    return `
      <label class="tbm-worker-select-item ${checked ? 'selected' : ''}" data-wid="${w.user_id}" style="${disabledStyle}">
        <input type="checkbox" class="new-tbm-worker-cb" data-user-id="${w.user_id}" ${checked} ${disabledAttr}
          onchange="toggleNewTbmWorker(${w.user_id}, this.checked)">
        <span class="tbm-worker-name">${escapeHtml(w.worker_name)}</span>
        <span class="tbm-worker-role">${escapeHtml(w.job_type || '작업자')}</span>
        ${badgeHtml}
      </label>
    `;
  }).join('');

  updateNewTbmWorkerCount();
}

function updateNewTbmWorkerCount() {
  const countEl = document.getElementById('newTbmWorkerCount');
  if (countEl) countEl.textContent = `(${selectedWorkersForNewTbm.size}명)`;
}

function toggleNewTbmWorker(workerId, checked) {
  // 이미 배정된 작업자 선택 방지
  const a = todayAssignmentsMap && todayAssignmentsMap[workerId];
  if (a && a.sessions && a.sessions.length > 0) return;

  if (checked) {
    selectedWorkersForNewTbm.add(workerId);
  } else {
    selectedWorkersForNewTbm.delete(workerId);
  }
  // Update visual state
  const label = document.querySelector(`#newTbmWorkerGrid label[data-wid="${workerId}"]`);
  if (label) label.classList.toggle('selected', checked);
  updateNewTbmWorkerCount();
}
window.toggleNewTbmWorker = toggleNewTbmWorker;

function selectAllNewTbmWorkers() {
  allWorkers.forEach(w => {
    const a = todayAssignmentsMap && todayAssignmentsMap[w.user_id];
    if (a && a.sessions && a.sessions.length > 0) return; // 배정됨 제외
    selectedWorkersForNewTbm.add(w.user_id);
  });
  document.querySelectorAll('.new-tbm-worker-cb').forEach(cb => {
    if (!cb.disabled) cb.checked = true;
  });
  document.querySelectorAll('#newTbmWorkerGrid label').forEach(l => {
    if (l.style.opacity !== '0.5') l.classList.add('selected');
  });
  updateNewTbmWorkerCount();
}
window.selectAllNewTbmWorkers = selectAllNewTbmWorkers;

function deselectAllNewTbmWorkers() {
  selectedWorkersForNewTbm.clear();
  document.querySelectorAll('.new-tbm-worker-cb').forEach(cb => { cb.checked = false; });
  document.querySelectorAll('#newTbmWorkerGrid label').forEach(l => l.classList.remove('selected'));
  updateNewTbmWorkerCount();
}
window.deselectAllNewTbmWorkers = deselectAllNewTbmWorkers;

// 입력자 선택 드롭다운 채우기
function populateLeaderSelect() {
  const leaderSelect = document.getElementById('leaderId');
  if (!leaderSelect) return;

  // 로그인한 사용자가 작업자와 연결되어 있는지 확인
  const isWorker = currentUser && currentUser.user_id && allWorkers.find(w => w.user_id === currentUser.user_id);
  if (isWorker) {
    // 작업자와 연결된 경우: 자동으로 선택하고 비활성화
    const worker = isWorker;
    const jobTypeText = worker.job_type ? ` (${escapeHtml(worker.job_type)})` : '';
    leaderSelect.innerHTML = `<option value="${escapeHtml(worker.user_id)}" selected>${escapeHtml(worker.worker_name)}${jobTypeText}</option>`;
    leaderSelect.disabled = true;
  } else {
    // 관리자 또는 작업자 목록에 없는 계정: 드롭다운으로 선택 가능
    const leaders = allWorkers.filter(w =>
      w.job_type === 'leader' || w.job_type === '그룹장' || w.job_type === 'admin'
    );

    leaderSelect.innerHTML = '<option value="">입력자 선택...</option>' +
      leaders.map(w => {
        const jobTypeText = w.job_type ? ` (${escapeHtml(w.job_type)})` : '';
        return `<option value="${escapeHtml(w.user_id)}">${escapeHtml(w.worker_name)}${jobTypeText}</option>`;
      }).join('');
    leaderSelect.disabled = false;
  }
}

// 프로젝트 선택 드롭다운 채우기
function populateProjectSelect() {
  const projectSelect = document.getElementById('projectId');
  if (!projectSelect) return;

  projectSelect.innerHTML = '<option value="">프로젝트 선택...</option>' +
    allProjects.map(p => `
      <option value="${escapeHtml(p.project_id)}">${escapeHtml(p.project_name)} (${escapeHtml(p.job_no)})</option>
    `).join('');
}

// 공정(Work Type) 선택 드롭다운 채우기
function populateWorkTypeSelect() {
  const workTypeSelect = document.getElementById('workTypeId');
  if (!workTypeSelect) return;

  workTypeSelect.innerHTML = '<option value="">공정 선택...</option>' +
    allWorkTypes.map(wt => `
      <option value="${escapeHtml(wt.id)}">${escapeHtml(wt.name)}${wt.category ? ' (' + escapeHtml(wt.category) + ')' : ''}</option>
    `).join('');
}

// 작업장 선택 드롭다운 채우기
function populateWorkplaceSelect() {
  const workLocationSelect = document.getElementById('workLocation');
  if (!workLocationSelect) return;

  workLocationSelect.innerHTML = '<option value="">작업장 선택...</option>' +
    allWorkplaces.map(wp => `
      <option value="${escapeHtml(wp.workplace_name)}">${escapeHtml(wp.workplace_name)}${wp.location ? ' - ' + escapeHtml(wp.location) : ''}</option>
    `).join('');
}

// 작업(Task) 선택 드롭다운 채우기 (공정 선택 시 호출)
function loadTasksByWorkType() {
  const workTypeId = document.getElementById('workTypeId').value;
  const taskSelect = document.getElementById('taskId');

  if (!taskSelect) return;

  if (!workTypeId) {
    taskSelect.innerHTML = '<option value="">작업 선택...</option>';
    taskSelect.disabled = true;
    return;
  }

  // 선택한 공정에 해당하는 작업만 필터링
  const filteredTasks = allTasks.filter(task =>
    task.work_type_id === parseInt(workTypeId)
  );

  taskSelect.disabled = false;
  taskSelect.innerHTML = '<option value="">작업 선택...</option>' +
    filteredTasks.map(task => `
      <option value="${escapeHtml(String(task.task_id))}">${escapeHtml(task.task_name)}</option>
    `).join('');

  if (filteredTasks.length === 0) {
    taskSelect.innerHTML = '<option value="">등록된 작업이 없습니다</option>';
    taskSelect.disabled = true;
  }
}
window.loadTasksByWorkType = loadTasksByWorkType;

// TBM 모달 닫기
function closeTbmModal() {
  document.getElementById('tbmModal').style.display = 'none';
  unlockBodyScroll();

  // 생성 모드로 복원
  const createSection = document.getElementById('newTbmWorkerGrid')?.closest('.tbm-form-section');
  const editSection = document.getElementById('workerTaskListSection');
  if (createSection) createSection.style.display = '';
  if (editSection) editSection.style.display = 'none';
}
window.closeTbmModal = closeTbmModal;

// TBM 세션 저장 (간소화: 프로젝트+공정+작업자, task/workplace=null)
async function saveTbmSession() {

  let leaderId = parseInt(document.getElementById('leaderId').value);

  if (!leaderId || isNaN(leaderId)) {
    // 어드민이거나 작업자 목록에 없는 사용자: leaderId null로 저장 가능
    leaderId = null;
  }

  const sessionData = {
    session_date: document.getElementById('sessionDate').value,
    leader_user_id: leaderId
  };

  if (!sessionData.session_date) {
    showToast('TBM 날짜를 확인해주세요.', 'error');
    return;
  }

  const editingSessionId = document.getElementById('sessionId').value;

  // 수정 모드일 때는 기존 openTeamCompositionModal의 workerTaskList를 사용
  if (editingSessionId) {
    // 기존 수정 모드 로직 (openTeamCompositionModal 경유)
    if (workerTaskList.length === 0) {
      showToast('최소 1명 이상의 작업자를 추가해주세요.', 'error');
      return;
    }

    const members = [];
    for (const workerData of workerTaskList) {
      for (const taskLine of workerData.tasks) {
        members.push({
          user_id: workerData.user_id,
          project_id: taskLine.project_id || null,
          work_type_id: taskLine.work_type_id,
          task_id: taskLine.task_id,
          workplace_category_id: taskLine.workplace_category_id || null,
          workplace_id: taskLine.workplace_id,
          work_detail: taskLine.work_detail || null,
          is_present: taskLine.is_present !== undefined ? taskLine.is_present : true
        });
      }
    }

    try {
      await window.TbmAPI.clearTeamMembers(editingSessionId);
      const teamResponse = await window.TbmAPI.addTeamMembers(editingSessionId, members);

      if (teamResponse && teamResponse.success) {
        showToast(`TBM이 수정되었습니다 (작업자 ${workerTaskList.length}명)`, 'success');
        closeTbmModal();
        if (currentTab === 'tbm-input') {
          await loadTodayOnlyTbm();
        } else {
          await loadRecentTbmGroupedByDate();
        }
      } else {
        throw new Error(teamResponse.message || '팀원 수정에 실패했습니다.');
      }
    } catch (error) {
      console.error(' TBM 세션 수정 오류:', error);
      showToast('TBM 세션 수정 중 오류가 발생했습니다.', 'error');
    }
    return;
  }

  // 생성 모드: 간소화된 새 TBM
  const workTypeId = parseInt(document.getElementById('newTbmWorkTypeId')?.value);
  const projectId = parseInt(document.getElementById('newTbmProjectId')?.value) || null;

  if (!workTypeId) {
    showToast('공정을 선택해주세요.', 'error');
    return;
  }

  if (selectedWorkersForNewTbm.size === 0) {
    showToast('최소 1명 이상의 작업자를 선택해주세요.', 'error');
    return;
  }

  // 작업자별 members 생성 (task_id, workplace_id = null)
  const members = [];
  selectedWorkersForNewTbm.forEach(workerId => {
    members.push({
      user_id: workerId,
      project_id: projectId,
      work_type_id: workTypeId,
      task_id: null,
      workplace_category_id: null,
      workplace_id: null,
      work_detail: null,
      is_present: true
    });
  });

  let createdSessionId = null;
  try {
    const response = await window.TbmAPI.createTbmSession(sessionData);

    if (response && response.success) {
      createdSessionId = response.data.session_id;

      const teamResponse = await window.TbmAPI.addTeamMembers(createdSessionId, members);

      if (teamResponse && teamResponse.success) {
        showToast(`TBM이 생성되었습니다 (작업자 ${members.length}명)`, 'success');
        closeTbmModal();

        if (currentTab === 'tbm-input') {
          await loadTodayOnlyTbm();
        } else {
          await loadRecentTbmGroupedByDate();
        }
      } else {
        throw new Error(teamResponse.message || '팀원 추가에 실패했습니다.');
      }
    } else {
      throw new Error(response.message || '저장에 실패했습니다.');
    }
  } catch (error) {
    console.error(' TBM 세션 저장 오류:', error);

    // 409 중복 배정 에러 처리
    if (error.duplicates && error.duplicates.length > 0) {
      // 고아 세션 삭제
      if (createdSessionId) {
        try { await window.TbmAPI.deleteSession(createdSessionId); } catch(e) {}
      }
      // 중복 작업자 자동 해제
      const dupIds = new Set(error.duplicates.map(d => d.user_id));
      dupIds.forEach(uid => {
        selectedWorkersForNewTbm.delete(uid);
      });
      // 배정 현황 캐시 갱신 후 그리드 새로고침
      todayAssignmentsMap = null;
      await renderNewTbmWorkerGrid();
      showToast(error.message, 'error');
    } else {
      showToast('TBM 세션 저장 중 오류가 발생했습니다.', 'error');
    }
  }
}
window.saveTbmSession = saveTbmSession;

// ==================== 작업자 관리 ====================

// generateUUID → api-base.js 전역 사용

// 작업자 카드 리스트 렌더링
function renderWorkerTaskList() {
  const listContainer = document.getElementById('workerTaskList');
  const emptyState = document.getElementById('workerListEmpty');

  if (workerTaskList.length === 0) {
    if (emptyState) emptyState.style.display = 'flex';
    listContainer.innerHTML = '';
    return;
  }

  if (emptyState) emptyState.style.display = 'none';

  listContainer.innerHTML = workerTaskList.map((workerData, workerIndex) => {
    return `
      <div style="border: 2px solid #e5e7eb; border-radius: 0.5rem; padding: 1rem; background: white;">
        <!-- 작업자 헤더 -->
        <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; padding-bottom: 0.75rem; border-bottom: 1px solid #e5e7eb;">
          <div style="display: flex; align-items: center; gap: 0.5rem;">
            <span style="font-weight: 600; font-size: 1.1rem; color: #1f2937;">👤 ${escapeHtml(workerData.worker_name)}</span>
            <span style="padding: 0.125rem 0.5rem; background: #dbeafe; color: #1e40af; border-radius: 0.25rem; font-size: 0.75rem;">
              ${escapeHtml(workerData.job_type || '작업자')}
            </span>
          </div>
          <button type="button" onclick="removeWorkerFromList(${parseInt(workerIndex) || 0})" class="btn btn-sm btn-danger">
            <span style="font-size: 1rem;">✕ 작업자 제거</span>
          </button>
        </div>

        <!-- 작업 라인들 -->
        ${workerData.tasks.map((taskLine, taskIndex) => renderTaskLine(workerData, workerIndex, taskLine, taskIndex)).join('')}

        <!-- 작업 추가 버튼 -->
        <div style="margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px dashed #d1d5db;">
          <button type="button" onclick="addTaskLineToWorker(${parseInt(workerIndex) || 0})" class="btn btn-sm btn-secondary" style="width: 100%;">
            <span style="font-size: 1.2rem; margin-right: 0.25rem;">+</span>
            이 작업자의 추가 작업 등록
          </button>
        </div>
      </div>
    `;
  }).join('');
}

// 작업 라인 렌더링
function renderTaskLine(workerData, workerIndex, taskLine, taskIndex) {
  const project = allProjects.find(p => p.project_id === taskLine.project_id);
  const workType = allWorkTypes.find(wt => wt.id === taskLine.work_type_id);
  const task = allTasks.find(t => t.task_id === taskLine.task_id);
  const safeWorkerIndex = parseInt(workerIndex) || 0;
  const safeTaskIndex = parseInt(taskIndex) || 0;

  const projectText = escapeHtml(project ? project.project_name : '프로젝트 선택');
  const workTypeText = escapeHtml(workType ? workType.name : '공정 선택 *');
  const taskText = escapeHtml(task ? task.task_name : '작업 선택 *');
  const workplaceText = taskLine.workplace_name
    ? escapeHtml(`${taskLine.workplace_category_name || ''} → ${taskLine.workplace_name}`)
    : '작업장 선택 *';

  return `
    <div style="padding: 0.75rem; margin-bottom: 0.5rem; background: #f9fafb; border-radius: 0.5rem; border: 1px solid #e5e7eb;">
      <div class="tbm-task-grid" style="margin-bottom: 0.5rem;">
        <!-- 프로젝트 선택 -->
        <button type="button"
          onclick="openItemSelect('project', ${safeWorkerIndex}, ${safeTaskIndex})"
          class="btn btn-sm ${project ? 'btn-primary' : 'btn-secondary'}"
          style="text-align: left; justify-content: flex-start; font-size: 0.875rem;">
          📁 ${projectText}
        </button>

        <!-- 작업장 선택 -->
        <button type="button"
          onclick="openWorkplaceSelect(${safeWorkerIndex}, ${safeTaskIndex})"
          class="btn btn-sm ${taskLine.workplace_id ? 'btn-primary' : 'btn-secondary'}"
          style="text-align: left; justify-content: flex-start; font-size: 0.875rem;">
          📍 ${workplaceText}
        </button>

        <!-- 공정 선택 -->
        <button type="button"
          onclick="openItemSelect('workType', ${safeWorkerIndex}, ${safeTaskIndex})"
          class="btn btn-sm ${workType ? 'btn-primary' : 'btn-secondary'}"
          style="text-align: left; justify-content: flex-start; font-size: 0.875rem;">
          ⚙️ ${workTypeText}
        </button>

        <!-- 작업 선택 -->
        <button type="button"
          onclick="openItemSelect('task', ${safeWorkerIndex}, ${safeTaskIndex})"
          class="btn btn-sm ${task ? 'btn-primary' : 'btn-secondary'}"
          style="text-align: left; justify-content: flex-start; font-size: 0.875rem;"
          ${!taskLine.work_type_id ? 'disabled' : ''}>
          🔧 ${taskText}
        </button>
      </div>

      <!-- 작업 라인 제거 버튼 -->
      ${workerData.tasks.length > 1 ? `
        <button type="button" onclick="removeTaskLine(${safeWorkerIndex}, ${safeTaskIndex})"
          class="btn btn-sm btn-danger" style="width: 100%; font-size: 0.8rem;">
          <span style="margin-right: 0.25rem;">−</span> 이 작업 라인 제거
        </button>
      ` : ''}
    </div>
  `;
}
window.renderWorkerTaskList = renderWorkerTaskList;

// 작업자 선택 모달 열기
function openWorkerSelectionModal() {
  selectedWorkersInModal.clear();

  const workerCardGrid = document.getElementById('workerCardGrid');
  if (!workerCardGrid) return;

  // 이미 추가된 작업자 ID 세트
  const addedWorkerIds = new Set(workerTaskList.map(w => w.user_id));

  workerCardGrid.innerHTML = allWorkers.map(worker => {
    const isAdded = addedWorkerIds.has(worker.user_id);
    const safeWorkerId = parseInt(worker.user_id) || 0;
    return `
      <div id="worker-card-${safeWorkerId}"
        onclick="toggleWorkerSelection(${safeWorkerId})"
        style="padding: 1rem; border: 2px solid ${isAdded ? '#d1d5db' : '#e5e7eb'}; border-radius: 0.5rem; cursor: ${isAdded ? 'not-allowed' : 'pointer'}; background: ${isAdded ? '#f3f4f6' : 'white'}; opacity: ${isAdded ? '0.5' : '1'}; transition: all 0.2s;">
        <div style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem;">
          ${isAdded ? '✓' : '☐'}
          <span style="font-weight: 600; font-size: 0.95rem;">${escapeHtml(worker.worker_name)}</span>
        </div>
        <div style="font-size: 0.8rem; color: #6b7280;">
          ${escapeHtml(worker.job_type || '작업자')}${worker.department ? ' · ' + escapeHtml(worker.department) : ''}
        </div>
        ${isAdded ? '<div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.25rem;">이미 추가됨</div>' : ''}
      </div>
    `;
  }).join('');

  document.getElementById('workerSelectionModal').style.display = 'flex';
  lockBodyScroll();
}
window.openWorkerSelectionModal = openWorkerSelectionModal;

// 작업자 선택 토글
function toggleWorkerSelection(workerId) {
  // 이미 추가된 작업자는 선택 불가
  const alreadyAdded = workerTaskList.some(w => w.user_id === workerId);
  if (alreadyAdded) return;

  const card = document.getElementById(`worker-card-${workerId}`);
  if (!card) return;

  if (selectedWorkersInModal.has(workerId)) {
    selectedWorkersInModal.delete(workerId);
    card.style.borderColor = '#e5e7eb';
    card.style.background = 'white';
    card.innerHTML = card.innerHTML.replace('☑', '☐');
  } else {
    selectedWorkersInModal.add(workerId);
    card.style.borderColor = '#3b82f6';
    card.style.background = '#eff6ff';
    card.innerHTML = card.innerHTML.replace('☐', '☑');
  }
}
window.toggleWorkerSelection = toggleWorkerSelection;

// 전체 선택
function selectAllWorkersInModal() {
  const addedWorkerIds = new Set(workerTaskList.map(w => w.user_id));
  allWorkers.forEach(worker => {
    if (!addedWorkerIds.has(worker.user_id)) {
      selectedWorkersInModal.add(worker.user_id);
      const card = document.getElementById(`worker-card-${worker.user_id}`);
      if (card) {
        card.style.borderColor = '#3b82f6';
        card.style.background = '#eff6ff';
        card.innerHTML = card.innerHTML.replace('☐', '☑');
      }
    }
  });
}
window.selectAllWorkersInModal = selectAllWorkersInModal;

// 전체 해제
function deselectAllWorkersInModal() {
  selectedWorkersInModal.forEach(workerId => {
    const card = document.getElementById(`worker-card-${workerId}`);
    if (card) {
      card.style.borderColor = '#e5e7eb';
      card.style.background = 'white';
      card.innerHTML = card.innerHTML.replace('☑', '☐');
    }
  });
  selectedWorkersInModal.clear();
}
window.deselectAllWorkersInModal = deselectAllWorkersInModal;

// 작업자 선택 확정
function confirmWorkerSelection() {
  if (selectedWorkersInModal.size === 0) {
    showToast('작업자를 선택해주세요.', 'error');
    return;
  }

  selectedWorkersInModal.forEach(workerId => {
    const worker = allWorkers.find(w => w.user_id === workerId);
    if (worker) {
      workerTaskList.push({
        user_id: worker.user_id,
        worker_name: worker.worker_name,
        job_type: worker.job_type,
        tasks: [
          {
            task_line_id: generateUUID(),
            project_id: null,
            work_type_id: null,
            task_id: null,
            workplace_category_id: null,
            workplace_id: null,
            workplace_category_name: '',
            workplace_name: '',
            work_detail: null,
            is_present: true
          }
        ]
      });
    }
  });

  renderWorkerTaskList();
  closeWorkerSelectionModal();
  showToast(`${selectedWorkersInModal.size}명의 작업자가 추가되었습니다.`, 'success');
}
window.confirmWorkerSelection = confirmWorkerSelection;

// 작업자 선택 모달 닫기
function closeWorkerSelectionModal() {
  document.getElementById('workerSelectionModal').style.display = 'none';
  unlockBodyScroll();
  selectedWorkersInModal.clear();
}
window.closeWorkerSelectionModal = closeWorkerSelectionModal;

// 작업자에 작업 라인 추가
function addTaskLineToWorker(workerIndex) {
  workerTaskList[workerIndex].tasks.push({
    task_line_id: generateUUID(),
    project_id: null,
    work_type_id: null,
    task_id: null,
    workplace_category_id: null,
    workplace_id: null,
    workplace_category_name: '',
    workplace_name: '',
    work_detail: null,
    is_present: true
  });
  renderWorkerTaskList();
  showToast('작업 라인이 추가되었습니다.', 'success');
}
window.addTaskLineToWorker = addTaskLineToWorker;

// 작업 라인 제거
function removeTaskLine(workerIndex, taskIndex) {
  workerTaskList[workerIndex].tasks.splice(taskIndex, 1);
  renderWorkerTaskList();
  showToast('작업 라인이 제거되었습니다.', 'info');
}
window.removeTaskLine = removeTaskLine;

// 작업자 제거
function removeWorkerFromList(workerIndex) {
  const workerName = workerTaskList[workerIndex].worker_name;
  workerTaskList.splice(workerIndex, 1);
  renderWorkerTaskList();
  showToast(`${workerName}이(가) 제거되었습니다.`, 'info');
}
window.removeWorkerFromList = removeWorkerFromList;

// ==================== 일괄 설정 ====================

// 일괄 설정 모달 열기
function openBulkSettingModal() {
  if (workerTaskList.length === 0) {
    showToast('먼저 작업자를 선택해주세요.', 'error');
    return;
  }

  // 작업자 선택 영역 초기화
  bulkSelectedWorkers.clear();
  renderBulkWorkerSelection();

  // 작업 정보 초기화
  document.getElementById('bulkProjectId').value = '';
  document.getElementById('bulkWorkTypeId').value = '';
  document.getElementById('bulkTaskId').value = '';
  document.getElementById('bulkWorkplaceCategoryId').value = '';
  document.getElementById('bulkWorkplaceId').value = '';

  document.getElementById('bulkProjectBtn').textContent = '📁 프로젝트 선택';
  document.getElementById('bulkProjectBtn').classList.remove('btn-primary');
  document.getElementById('bulkProjectBtn').classList.add('btn-secondary');

  document.getElementById('bulkWorkTypeBtn').textContent = '⚙️ 공정 선택';
  document.getElementById('bulkWorkTypeBtn').classList.remove('btn-primary');
  document.getElementById('bulkWorkTypeBtn').classList.add('btn-secondary');

  document.getElementById('bulkTaskBtn').textContent = '🔧 작업 선택';
  document.getElementById('bulkTaskBtn').classList.remove('btn-primary');
  document.getElementById('bulkTaskBtn').classList.add('btn-secondary');
  document.getElementById('bulkTaskBtn').disabled = true;

  document.getElementById('bulkWorkplaceBtn').textContent = '📍 작업장 선택';
  document.getElementById('bulkWorkplaceBtn').classList.remove('btn-primary');
  document.getElementById('bulkWorkplaceBtn').classList.add('btn-secondary');

  document.getElementById('bulkSettingModal').style.display = 'flex';
  lockBodyScroll();
}
window.openBulkSettingModal = openBulkSettingModal;

// 일괄 설정용 작업자 선택 영역 렌더링
function renderBulkWorkerSelection() {
  const container = document.getElementById('bulkWorkerSelection');
  if (!container) return;

  container.innerHTML = workerTaskList.map((workerData, index) => {
    const isSelected = bulkSelectedWorkers.has(index);
    return `
      <div onclick="toggleBulkWorkerSelection(${index})"
        style="padding: 0.5rem; border: 2px solid ${isSelected ? '#3b82f6' : '#e5e7eb'}; border-radius: 0.5rem; cursor: pointer; background: ${isSelected ? '#eff6ff' : 'white'}; transition: all 0.2s; display: flex; align-items: center; gap: 0.5rem;">
        <input type="checkbox" ${isSelected ? 'checked' : ''} style="pointer-events: none;">
        <span style="font-size: 0.875rem; font-weight: ${isSelected ? '600' : '400'}; color: ${isSelected ? '#1e40af' : '#374151'};">
          ${workerData.worker_name}
        </span>
      </div>
    `;
  }).join('');
}
window.renderBulkWorkerSelection = renderBulkWorkerSelection;

// 일괄 설정용 작업자 선택 토글
function toggleBulkWorkerSelection(workerIndex) {
  if (bulkSelectedWorkers.has(workerIndex)) {
    bulkSelectedWorkers.delete(workerIndex);
  } else {
    bulkSelectedWorkers.add(workerIndex);
  }
  renderBulkWorkerSelection();
}
window.toggleBulkWorkerSelection = toggleBulkWorkerSelection;

// 일괄 설정용 전체 선택
function selectAllForBulk() {
  workerTaskList.forEach((_, index) => {
    bulkSelectedWorkers.add(index);
  });
  renderBulkWorkerSelection();
}
window.selectAllForBulk = selectAllForBulk;

// 일괄 설정용 전체 해제
function deselectAllForBulk() {
  bulkSelectedWorkers.clear();
  renderBulkWorkerSelection();
}
window.deselectAllForBulk = deselectAllForBulk;

// 일괄 설정 모달 닫기
function closeBulkSettingModal() {
  document.getElementById('bulkSettingModal').style.display = 'none';
  unlockBodyScroll();
  isBulkMode = false;
}
window.closeBulkSettingModal = closeBulkSettingModal;

// 일괄 설정용 항목 선택
function openBulkItemSelect(type) {
  isBulkMode = true;
  const modal = document.getElementById('itemSelectModal');
  const titleEl = document.getElementById('itemSelectModalTitle');
  const listEl = document.getElementById('itemSelectList');

  let title = '';
  let items = [];

  if (type === 'project') {
    title = '프로젝트 선택';
    // 활성 프로젝트만 표시
    const activeProjects = allProjects.filter(p =>
      p.is_active === 1 || p.is_active === true || p.is_active === '1'
    );
    items = activeProjects.map(p => ({
      id: p.project_id,
      name: p.project_name,
      icon: '📁'
    }));
  } else if (type === 'workType') {
    title = '공정 선택';
    items = allWorkTypes.map(wt => ({
      id: wt.id,
      name: wt.name,
      icon: '⚙️'
    }));
  } else if (type === 'task') {
    title = '작업 선택';
    const currentWorkTypeId = parseInt(document.getElementById('bulkWorkTypeId').value);
    if (!currentWorkTypeId) {
      showToast('공정을 먼저 선택해주세요.', 'error');
      return;
    }
    const filteredTasks = allTasks.filter(t => t.work_type_id === currentWorkTypeId);
    items = filteredTasks.map(t => ({
      id: t.task_id,
      name: t.task_name,
      icon: '🔧'
    }));
  }

  titleEl.textContent = title;
  listEl.innerHTML = items.length > 0 ? items.map(item => `
    <button type="button"
      onclick="selectBulkItem('${type}', ${item.id}, '${item.name.replace(/'/g, "\\'")}')"
      class="btn btn-secondary"
      style="text-align: left; justify-content: flex-start; padding: 0.75rem;">
      ${item.icon} ${item.name}
    </button>
  `).join('') : '<div style="text-align: center; padding: 2rem; color: #9ca3af;">선택 가능한 항목이 없습니다</div>';

  modal.style.display = 'flex';
  lockBodyScroll();
}
window.openBulkItemSelect = openBulkItemSelect;

// 일괄 설정용 항목 선택 처리
function selectBulkItem(type, itemId, itemName) {
  if (type === 'project') {
    document.getElementById('bulkProjectId').value = itemId;
    document.getElementById('bulkProjectBtn').textContent = `📁 ${itemName}`;
    document.getElementById('bulkProjectBtn').classList.remove('btn-secondary');
    document.getElementById('bulkProjectBtn').classList.add('btn-primary');
  } else if (type === 'workType') {
    document.getElementById('bulkWorkTypeId').value = itemId;
    document.getElementById('bulkWorkTypeBtn').textContent = `⚙️ ${itemName}`;
    document.getElementById('bulkWorkTypeBtn').classList.remove('btn-secondary');
    document.getElementById('bulkWorkTypeBtn').classList.add('btn-primary');

    // 공정 변경 시 작업 초기화
    document.getElementById('bulkTaskId').value = '';
    document.getElementById('bulkTaskBtn').textContent = '🔧 작업 선택';
    document.getElementById('bulkTaskBtn').classList.remove('btn-primary');
    document.getElementById('bulkTaskBtn').classList.add('btn-secondary');
    document.getElementById('bulkTaskBtn').disabled = false;
  } else if (type === 'task') {
    document.getElementById('bulkTaskId').value = itemId;
    document.getElementById('bulkTaskBtn').textContent = `🔧 ${itemName}`;
    document.getElementById('bulkTaskBtn').classList.remove('btn-secondary');
    document.getElementById('bulkTaskBtn').classList.add('btn-primary');
  }

  closeItemSelectModal();
  isBulkMode = false;
}
window.selectBulkItem = selectBulkItem;

// 일괄 설정용 작업장 선택
function openBulkWorkplaceSelect() {
  isBulkMode = true;
  loadWorkplaceCategories();
  document.getElementById('workplaceSelectModal').style.display = 'flex';
  lockBodyScroll();
}
window.openBulkWorkplaceSelect = openBulkWorkplaceSelect;

// 일괄 설정 적용
function applyBulkSettings() {
  if (bulkSelectedWorkers.size === 0) {
    showToast('작업자를 선택해주세요.', 'error');
    return;
  }

  const projectId = document.getElementById('bulkProjectId').value;
  const workTypeId = document.getElementById('bulkWorkTypeId').value;
  const taskId = document.getElementById('bulkTaskId').value;
  const workplaceCategoryId = document.getElementById('bulkWorkplaceCategoryId').value;
  const workplaceId = document.getElementById('bulkWorkplaceId').value;

  if (!workTypeId || !taskId || !workplaceId) {
    showToast('공정, 작업, 작업장은 필수 항목입니다.', 'error');
    return;
  }

  // 선택된 작업자들의 첫 번째 작업 라인에 적용
  let appliedCount = 0;
  bulkSelectedWorkers.forEach(workerIndex => {
    const workerData = workerTaskList[workerIndex];
    if (workerData && workerData.tasks.length > 0) {
      workerData.tasks[0].project_id = projectId ? parseInt(projectId) : null;
      workerData.tasks[0].work_type_id = parseInt(workTypeId);
      workerData.tasks[0].task_id = parseInt(taskId);
      workerData.tasks[0].workplace_category_id = workplaceCategoryId ? parseInt(workplaceCategoryId) : null;
      workerData.tasks[0].workplace_id = parseInt(workplaceId);
      workerData.tasks[0].workplace_category_name = selectedCategoryName;
      workerData.tasks[0].workplace_name = selectedWorkplaceName;
      appliedCount++;
    }
  });

  renderWorkerTaskList();
  closeBulkSettingModal();
  showToast(`${appliedCount}명의 작업자에게 일괄 설정이 적용되었습니다.`, 'success');
}
window.applyBulkSettings = applyBulkSettings;

// ==================== 항목 선택 (프로젝트/공정/작업) ====================

// 항목 선택 모달 열기
function openItemSelect(type, workerIndex, taskIndex) {
  currentEditingTaskLine = { workerIndex, taskIndex };

  const modal = document.getElementById('itemSelectModal');
  const titleEl = document.getElementById('itemSelectModalTitle');
  const listEl = document.getElementById('itemSelectList');

  let title = '';
  let items = [];

  if (type === 'project') {
    title = '프로젝트 선택';
    // 활성 프로젝트만 표시
    const activeProjects = allProjects.filter(p =>
      p.is_active === 1 || p.is_active === true || p.is_active === '1'
    );
    items = activeProjects.map(p => ({
      id: p.project_id,
      name: p.project_name,
      icon: '📁'
    }));
  } else if (type === 'workType') {
    title = '공정 선택';
    items = allWorkTypes.map(wt => ({
      id: wt.id,
      name: wt.name,
      icon: '⚙️'
    }));
  } else if (type === 'task') {
    title = '작업 선택';
    const currentWorkTypeId = workerTaskList[workerIndex].tasks[taskIndex].work_type_id;
    if (!currentWorkTypeId) {
      showToast('공정을 먼저 선택해주세요.', 'error');
      return;
    }
    const filteredTasks = allTasks.filter(t => t.work_type_id === currentWorkTypeId);
    items = filteredTasks.map(t => ({
      id: t.task_id,
      name: t.task_name,
      icon: '🔧'
    }));
  }

  titleEl.textContent = title;
  listEl.innerHTML = items.length > 0 ? items.map(item => `
    <button type="button"
      onclick="selectItem('${type}', ${item.id})"
      class="btn btn-secondary"
      style="text-align: left; justify-content: flex-start; padding: 0.75rem;">
      ${item.icon} ${item.name}
    </button>
  `).join('') : '<div style="text-align: center; padding: 2rem; color: #9ca3af;">선택 가능한 항목이 없습니다</div>';

  modal.style.display = 'flex';
  lockBodyScroll();
}
window.openItemSelect = openItemSelect;

// 항목 선택
function selectItem(type, itemId) {
  // 일괄 모드면 여기서 처리하지 않음
  if (isBulkMode) return;

  if (!currentEditingTaskLine) return;

  const { workerIndex, taskIndex } = currentEditingTaskLine;
  const taskLine = workerTaskList[workerIndex].tasks[taskIndex];

  if (type === 'project') {
    taskLine.project_id = itemId;
  } else if (type === 'workType') {
    taskLine.work_type_id = itemId;
    // 공정 변경 시 작업 초기화
    taskLine.task_id = null;
  } else if (type === 'task') {
    taskLine.task_id = itemId;
  }

  renderWorkerTaskList();
  closeItemSelectModal();
}
window.selectItem = selectItem;

// 항목 선택 모달 닫기
function closeItemSelectModal() {
  document.getElementById('itemSelectModal').style.display = 'none';
  unlockBodyScroll();
  currentEditingTaskLine = null;
}
window.closeItemSelectModal = closeItemSelectModal;

// ==================== 작업장 2단계 선택 ====================

// 작업장 선택 모달 열기 (작업 라인용)
async function openWorkplaceSelect(workerIndex, taskIndex) {
  currentEditingTaskLine = { workerIndex, taskIndex };
  await loadWorkplaceCategories();
  document.getElementById('workplaceSelectModal').style.display = 'flex';
  lockBodyScroll();
}
window.openWorkplaceSelect = openWorkplaceSelect;

// 작업장 선택 모달 닫기
function closeWorkplaceSelectModal() {
  // 가로모드 오버레이도 닫기
  const landscapeOverlay = document.getElementById('landscapeOverlay');
  if (landscapeOverlay && landscapeOverlay.style.display !== 'none') {
    closeLandscapeMap();
  }
  document.getElementById('workplaceSelectModal').style.display = 'none';
  unlockBodyScroll();
  document.getElementById('workplaceSelectionArea').style.display = 'none';
  document.getElementById('layoutMapArea').style.display = 'none';
  document.getElementById('workplaceList').style.display = 'none';
  currentEditingTaskLine = null;
  selectedCategory = null;
  selectedWorkplace = null;
  selectedCategoryName = '';
  selectedWorkplaceName = '';
  mapCanvas = null;
  mapCtx = null;
  mapImage = null;
  mapRegions = [];
}
window.closeWorkplaceSelectModal = closeWorkplaceSelectModal;

// 공장 카테고리 로드
async function loadWorkplaceCategories() {
  const categoryList = document.getElementById('categoryList');
  if (!categoryList) return;

  if (allWorkplaceCategories.length === 0) {
    categoryList.innerHTML = '<div style="color: #9ca3af; text-align: center; padding: 2rem;">등록된 공장이 없습니다</div>';
    return;
  }

  categoryList.innerHTML = allWorkplaceCategories.map(category => `
    <button type="button"
      onclick="selectCategory(${category.category_id}, '${category.category_name}')"
      class="btn btn-secondary"
      id="category-${category.category_id}"
      style="text-align: left; justify-content: flex-start;">
      🏭 ${category.category_name}
    </button>
  `).join('');
}
window.loadWorkplaceCategories = loadWorkplaceCategories;

// 공장 카테고리 선택
async function selectCategory(categoryId, categoryName) {
  selectedCategory = categoryId;
  selectedCategoryName = categoryName;
  selectedWorkplace = null;
  selectedWorkplaceName = '';

  // 카테고리 버튼 스타일 업데이트
  document.querySelectorAll('[id^="category-"]').forEach(btn => {
    btn.classList.remove('btn-primary');
    btn.classList.add('btn-secondary');
  });
  const selectedBtn = document.getElementById(`category-${categoryId}`);
  if (selectedBtn) {
    selectedBtn.classList.remove('btn-secondary');
    selectedBtn.classList.add('btn-primary');
  }

  // 작업장 선택 영역 표시
  document.getElementById('workplaceSelectionArea').style.display = 'block';

  // 해당 카테고리 정보 가져오기
  const category = allWorkplaceCategories.find(c => c.category_id === categoryId);

  const isMobile = window.innerWidth <= 768;

  // 지도 또는 리스트 로드
  if (category && category.layout_image) {
    // 지도가 있는 경우 - 지도를 기본 표시
    await loadWorkplaceMap(categoryId, category.layout_image);
    document.getElementById('layoutMapArea').style.display = 'block';

    if (isMobile) {
      // 모바일: 리스트 숨기고 "리스트로 선택" 토글 표시
      document.getElementById('workplaceListSection').style.display = 'none';
      document.getElementById('toggleListBtn').style.display = 'inline-flex';
      document.getElementById('toggleListBtn').textContent = '리스트로 선택';
      // 전체화면 지도 버튼 표시
      const triggerBtn = document.getElementById('landscapeTriggerBtn');
      if (triggerBtn) triggerBtn.style.display = 'inline-flex';
    } else {
      // 데스크톱: 리스트도 함께 표시
      document.getElementById('workplaceList').style.display = 'flex';
      document.getElementById('workplaceListSection').style.display = 'block';
      document.getElementById('toggleListBtn').style.display = 'none';
    }
  } else {
    // 지도가 없는 경우 - 리스트만 표시
    document.getElementById('layoutMapArea').style.display = 'none';
    document.getElementById('toggleListBtn').style.display = 'none';
    document.getElementById('workplaceList').style.display = 'flex';
    document.getElementById('workplaceListSection').style.display = 'block';
  }

  // 해당 카테고리의 작업장 리스트 로드
  await loadWorkplacesByCategory(categoryId);

  // 선택 완료 버튼 비활성화 (작업장 선택 필요)
  document.getElementById('confirmWorkplaceBtn').disabled = true;
}
window.selectCategory = selectCategory;

// 카테고리별 작업장 로드
async function loadWorkplacesByCategory(categoryId) {
  const workplaceList = document.getElementById('workplaceList');
  if (!workplaceList) return;

  try {
    const workplaces = await window.TbmAPI.loadWorkplacesByCategory(categoryId);
    if (!workplaces || workplaces.length === 0) {
      workplaceList.innerHTML = '<div style="color: #9ca3af; text-align: center; padding: 2rem;">등록된 작업장이 없습니다</div>';
      return;
    }
    workplaceList.innerHTML = workplaces.map(workplace => `
      <button type="button"
        onclick="selectWorkplace(${workplace.workplace_id}, '${workplace.workplace_name}')"
        class="btn btn-secondary"
        id="workplace-${workplace.workplace_id}"
        style="text-align: left; justify-content: flex-start;">
        📍 ${workplace.workplace_name}
      </button>
    `).join('');
  } catch (error) {
    console.error(' 작업장 로드 오류:', error);
    workplaceList.innerHTML = '<div style="color: #ef4444; text-align: center; padding: 2rem;">작업장을 불러오는 중 오류가 발생했습니다</div>';
  }
}
window.loadWorkplacesByCategory = loadWorkplacesByCategory;

// 작업장 선택
function selectWorkplace(workplaceId, workplaceName) {
  selectedWorkplace = workplaceId;
  selectedWorkplaceName = workplaceName;

  // 작업장 버튼 스타일 업데이트 (리스트)
  document.querySelectorAll('[id^="workplace-"]').forEach(btn => {
    btn.classList.remove('btn-primary');
    btn.classList.add('btn-secondary');
  });
  const selectedBtn = document.getElementById(`workplace-${workplaceId}`);
  if (selectedBtn) {
    selectedBtn.classList.remove('btn-secondary');
    selectedBtn.classList.add('btn-primary');
  }

  // 지도 업데이트 (지도가 로드되어 있는 경우)
  if (mapCanvas && mapCtx && mapImage) {
    drawWorkplaceMap();
  }

  // 선택 완료 버튼 활성화
  document.getElementById('confirmWorkplaceBtn').disabled = false;
}
window.selectWorkplace = selectWorkplace;

// 작업장 선택 확정
function confirmWorkplaceSelection() {
  if (!selectedCategory || !selectedWorkplace) {
    showToast('공장과 작업장을 모두 선택해주세요.', 'error');
    return;
  }

  // 일괄 모드인 경우
  if (isBulkMode) {
    document.getElementById('bulkWorkplaceCategoryId').value = selectedCategory;
    document.getElementById('bulkWorkplaceId').value = selectedWorkplace;
    document.getElementById('bulkWorkplaceBtn').textContent = `📍 ${selectedCategoryName} → ${selectedWorkplaceName}`;
    document.getElementById('bulkWorkplaceBtn').classList.remove('btn-secondary');
    document.getElementById('bulkWorkplaceBtn').classList.add('btn-primary');
    closeWorkplaceSelectModal();
    isBulkMode = false;
    showToast('작업장이 선택되었습니다.', 'success');
    return;
  }

  // 현재 편집 중인 작업 라인에 저장
  if (currentEditingTaskLine) {
    const { workerIndex, taskIndex } = currentEditingTaskLine;
    const taskLine = workerTaskList[workerIndex].tasks[taskIndex];
    taskLine.workplace_category_id = selectedCategory;
    taskLine.workplace_id = selectedWorkplace;
    taskLine.workplace_category_name = selectedCategoryName;
    taskLine.workplace_name = selectedWorkplaceName;
    renderWorkerTaskList();
  }

  closeWorkplaceSelectModal();
  showToast('작업장이 선택되었습니다.', 'success');
}
window.confirmWorkplaceSelection = confirmWorkplaceSelection;

// 리스트 토글 함수 (레거시 호환)
// 리스트 토글 함수
function toggleWorkplaceList() {
  const listSection = document.getElementById('workplaceListSection');
  const btn = document.getElementById('toggleListBtn');
  if (listSection.style.display === 'none') {
    listSection.style.display = 'block';
    document.getElementById('workplaceList').style.display = 'flex';
    btn.textContent = '리스트 숨기기';
  } else {
    listSection.style.display = 'none';
    btn.textContent = '리스트로 선택';
  }
}
window.toggleWorkplaceList = toggleWorkplaceList;

// 작업장 지도 로드 및 렌더링
// mapRegions, mapCanvas, mapCtx, mapImage → TbmState 프록시 사용 (state.js)

async function loadWorkplaceMap(categoryId, layoutImagePath) {
  try {
    mapCanvas = document.getElementById('workplaceMapCanvas');
    if (!mapCanvas) return;

    mapCtx = mapCanvas.getContext('2d');

    // 이미지 URL 생성
    const baseUrl = window.API_BASE_URL || 'http://localhost:30005';
    const apiBaseUrl = baseUrl.replace('/api', ''); // /api 제거
    const fullImageUrl = layoutImagePath.startsWith('http')
      ? layoutImagePath
      : `${apiBaseUrl}${layoutImagePath}`;


    // 지도 영역 데이터 로드
    mapRegions = await window.TbmAPI.loadMapRegions(categoryId);

    // 이미지 로드
    mapImage = new Image();
    mapImage.crossOrigin = 'anonymous';

    mapImage.onload = function() {
      // 캔버스 크기 설정 (모바일 대응)
      const maxWidth = window.innerWidth <= 768
        ? Math.min(window.innerWidth - 32, 600)
        : 800;
      const scale = mapImage.width > maxWidth ? maxWidth / mapImage.width : 1;

      mapCanvas.width = mapImage.width * scale;
      mapCanvas.height = mapImage.height * scale;

      // 이미지와 영역 그리기
      drawWorkplaceMap();

      // 클릭 이벤트 리스너 추가
      mapCanvas.onclick = handleMapClick;

    };

    mapImage.onerror = function() {
      console.error(' 지도 이미지 로드 실패');
      document.getElementById('layoutMapArea').style.display = 'none';
      document.getElementById('workplaceListSection').style.display = 'block';
      document.getElementById('workplaceList').style.display = 'flex';
      document.getElementById('toggleListBtn').style.display = 'none';
      showToast('지도를 불러올 수 없어 리스트로 표시합니다.', 'warning');
    };

    mapImage.src = fullImageUrl;

  } catch (error) {
    console.error(' 작업장 지도 로드 오류:', error);
    document.getElementById('layoutMapArea').style.display = 'none';
    document.getElementById('workplaceList').style.display = 'flex';
  }
}
window.loadWorkplaceMap = loadWorkplaceMap;

// 지도 그리기 (이미지 + 영역 + 라벨)
function drawWorkplaceMap() {
  if (!mapCanvas || !mapCtx || !mapImage) return;

  // 이미지 그리기
  mapCtx.drawImage(mapImage, 0, 0, mapCanvas.width, mapCanvas.height);

  // 각 영역 그리기
  mapRegions.forEach((region, index) => {
    // 퍼센트를 픽셀로 변환
    const x1 = (region.x_start / 100) * mapCanvas.width;
    const y1 = (region.y_start / 100) * mapCanvas.height;
    const x2 = (region.x_end / 100) * mapCanvas.width;
    const y2 = (region.y_end / 100) * mapCanvas.height;

    const width = x2 - x1;
    const height = y2 - y1;

    // 선택된 영역인지 확인
    const isSelected = region.workplace_id === selectedWorkplace;

    // 영역 테두리
    mapCtx.strokeStyle = isSelected ? '#3b82f6' : '#10b981';
    mapCtx.lineWidth = isSelected ? 4 : 2;
    mapCtx.strokeRect(x1, y1, width, height);

    // 영역 배경 (반투명)
    mapCtx.fillStyle = isSelected ? 'rgba(59, 130, 246, 0.25)' : 'rgba(16, 185, 129, 0.15)';
    mapCtx.fillRect(x1, y1, width, height);

    // 작업장 이름 표시
    if (region.workplace_name) {
      mapCtx.font = 'bold 14px sans-serif';

      // 텍스트 배경
      const textMetrics = mapCtx.measureText(region.workplace_name);
      const textPadding = 6;
      mapCtx.fillStyle = isSelected ? 'rgba(59, 130, 246, 0.95)' : 'rgba(16, 185, 129, 0.95)';
      mapCtx.fillRect(x1 + 5, y1 + 5, textMetrics.width + textPadding * 2, 24);

      // 텍스트
      mapCtx.fillStyle = '#ffffff';
      mapCtx.fillText(region.workplace_name, x1 + 5 + textPadding, y1 + 22);
    }
  });
}

// 지도 클릭 이벤트 처리
function handleMapClick(event) {
  if (!mapCanvas || mapRegions.length === 0) return;

  const rect = mapCanvas.getBoundingClientRect();

  // CSS 스케일 보정: 캔버스의 논리적 크기와 화면 표시 크기가 다를 수 있음
  const scaleX = mapCanvas.width / rect.width;
  const scaleY = mapCanvas.height / rect.height;
  const x = (event.clientX - rect.left) * scaleX;
  const y = (event.clientY - rect.top) * scaleY;

  // 클릭한 위치에 있는 영역 찾기
  for (let i = mapRegions.length - 1; i >= 0; i--) {
    const region = mapRegions[i];
    const x1 = (region.x_start / 100) * mapCanvas.width;
    const y1 = (region.y_start / 100) * mapCanvas.height;
    const x2 = (region.x_end / 100) * mapCanvas.width;
    const y2 = (region.y_end / 100) * mapCanvas.height;

    if (x >= x1 && x <= x2 && y >= y1 && y <= y2) {
      // 영역 클릭됨
      selectWorkplace(region.workplace_id, region.workplace_name);

      // 지도 다시 그리기 (선택 효과 표시)
      drawWorkplaceMap();

      // 리스트에서도 동기화
      syncWorkplaceListSelection(region.workplace_id);

      return;
    }
  }
}

// 리스트 선택 동기화
function syncWorkplaceListSelection(workplaceId) {
  // 리스트의 버튼들도 업데이트
  document.querySelectorAll('[id^="workplace-"]').forEach(btn => {
    if (btn.id === `workplace-${workplaceId}`) {
      btn.classList.remove('btn-secondary');
      btn.classList.add('btn-primary');
    } else {
      btn.classList.remove('btn-primary');
      btn.classList.add('btn-secondary');
    }
  });
}
window.syncWorkplaceListSelection = syncWorkplaceListSelection;

// ==================== 가로모드 전체화면 지도 ====================

function openLandscapeMap() {
  if (!mapImage || !mapImage.complete || mapRegions.length === 0) return;

  const overlay = document.getElementById('landscapeOverlay');
  const inner = document.getElementById('landscapeInner');
  const lCanvas = document.getElementById('landscapeCanvas');
  if (!overlay || !lCanvas) return;

  overlay.style.display = 'flex';
  lockBodyScroll();

  // 물리적 가로모드 여부 판단
  const isPhysicalLandscape = window.innerWidth > window.innerHeight;
  inner.className = 'landscape-inner ' + (isPhysicalLandscape ? 'no-rotate' : 'rotated');

  // 가용 영역 계산 (헤더 52px, 패딩 여유)
  const headerH = 52;
  const pad = 16;
  let availW, availH;
  if (isPhysicalLandscape) {
    availW = window.innerWidth - pad * 2;
    availH = window.innerHeight - headerH - pad * 2;
  } else {
    // 회전: 가로↔세로 스왑
    availW = window.innerHeight - pad * 2;
    availH = window.innerWidth - headerH - pad * 2;
  }

  // 이미지 비율 유지 캔버스 크기
  const imgRatio = mapImage.naturalWidth / mapImage.naturalHeight;
  let cw, ch;
  if (availW / availH > imgRatio) {
    ch = availH;
    cw = ch * imgRatio;
  } else {
    cw = availW;
    ch = cw / imgRatio;
  }
  lCanvas.width = Math.round(cw);
  lCanvas.height = Math.round(ch);

  drawLandscapeMap();

  // 이벤트 리스너
  lCanvas.ontouchstart = handleLandscapeTouchStart;
  lCanvas.onclick = handleLandscapeClick;
}
window.openLandscapeMap = openLandscapeMap;

function drawLandscapeMap() {
  const lCanvas = document.getElementById('landscapeCanvas');
  if (!lCanvas || !mapImage) return;
  const lCtx = lCanvas.getContext('2d');

  lCtx.drawImage(mapImage, 0, 0, lCanvas.width, lCanvas.height);

  mapRegions.forEach(region => {
    const x1 = (region.x_start / 100) * lCanvas.width;
    const y1 = (region.y_start / 100) * lCanvas.height;
    const x2 = (region.x_end / 100) * lCanvas.width;
    const y2 = (region.y_end / 100) * lCanvas.height;
    const w = x2 - x1;
    const h = y2 - y1;
    const isSelected = region.workplace_id === selectedWorkplace;

    lCtx.strokeStyle = isSelected ? '#3b82f6' : '#10b981';
    lCtx.lineWidth = isSelected ? 4 : 2;
    lCtx.strokeRect(x1, y1, w, h);

    lCtx.fillStyle = isSelected ? 'rgba(59, 130, 246, 0.25)' : 'rgba(16, 185, 129, 0.15)';
    lCtx.fillRect(x1, y1, w, h);

    if (region.workplace_name) {
      lCtx.font = 'bold 14px sans-serif';
      const tm = lCtx.measureText(region.workplace_name);
      const tp = 6;
      lCtx.fillStyle = isSelected ? 'rgba(59, 130, 246, 0.95)' : 'rgba(16, 185, 129, 0.95)';
      lCtx.fillRect(x1 + 5, y1 + 5, tm.width + tp * 2, 24);
      lCtx.fillStyle = '#ffffff';
      lCtx.textAlign = 'left';
      lCtx.textBaseline = 'alphabetic';
      lCtx.fillText(region.workplace_name, x1 + 5 + tp, y1 + 22);
    }
  });
}

function getLandscapeCoords(clientX, clientY) {
  const lCanvas = document.getElementById('landscapeCanvas');
  if (!lCanvas) return null;
  const rect = lCanvas.getBoundingClientRect();
  const inner = document.getElementById('landscapeInner');
  const isRotated = inner.classList.contains('rotated');

  if (!isRotated) {
    // 회전 없음 - 일반 좌표
    const scaleX = lCanvas.width / rect.width;
    const scaleY = lCanvas.height / rect.height;
    return {
      x: (clientX - rect.left) * scaleX,
      y: (clientY - rect.top) * scaleY
    };
  }

  // 90° 시계방향 회전의 역변환
  const centerX = rect.left + rect.width / 2;
  const centerY = rect.top + rect.height / 2;
  const dx = clientX - centerX;
  const dy = clientY - centerY;
  // 역회전 (반시계 90°)
  const inverseDx = dy;
  const inverseDy = -dx;

  // 회전 전 실제 크기: rect가 회전된 후이므로 width↔height 스왑
  const unrotatedW = rect.height;
  const unrotatedH = rect.width;

  const canvasX = (inverseDx + unrotatedW / 2) / unrotatedW * lCanvas.width;
  const canvasY = (inverseDy + unrotatedH / 2) / unrotatedH * lCanvas.height;

  return { x: canvasX, y: canvasY };
}

function handleLandscapeTouchStart(e) {
  e.preventDefault(); // 고스트 클릭 방지
  const touch = e.touches[0];
  const coords = getLandscapeCoords(touch.clientX, touch.clientY);
  if (coords) doLandscapeHitTest(coords.x, coords.y);
}

function handleLandscapeClick(e) {
  const coords = getLandscapeCoords(e.clientX, e.clientY);
  if (coords) doLandscapeHitTest(coords.x, coords.y);
}

function doLandscapeHitTest(cx, cy) {
  const lCanvas = document.getElementById('landscapeCanvas');
  if (!lCanvas) return;

  for (let i = mapRegions.length - 1; i >= 0; i--) {
    const region = mapRegions[i];
    const x1 = (region.x_start / 100) * lCanvas.width;
    const y1 = (region.y_start / 100) * lCanvas.height;
    const x2 = (region.x_end / 100) * lCanvas.width;
    const y2 = (region.y_end / 100) * lCanvas.height;

    if (cx >= x1 && cx <= x2 && cy >= y1 && cy <= y2) {
      selectWorkplace(region.workplace_id, region.workplace_name);
      drawWorkplaceMap();
      syncWorkplaceListSelection(region.workplace_id);

      // 하이라이트 후 자동 닫기
      drawLandscapeMap();
      setTimeout(() => closeLandscapeMap(), 300);
      return;
    }
  }
}

function closeLandscapeMap() {
  const overlay = document.getElementById('landscapeOverlay');
  if (overlay) overlay.style.display = 'none';
  const lCanvas = document.getElementById('landscapeCanvas');
  if (lCanvas) {
    lCanvas.ontouchstart = null;
    lCanvas.onclick = null;
  }
  unlockBodyScroll();
}
window.closeLandscapeMap = closeLandscapeMap;

// ==================== 기존 팀 구성 모달 (백업) ====================

// 팀 구성 모달 열기
// 팀 구성 수정 (TBM 수정 모달 열기)
async function openTeamCompositionModal(sessionId) {
  currentSessionId = sessionId;

  try {
    // 세션 정보 로드
    const session = await window.TbmAPI.getSession(sessionId);
    if (!session) {
      showToast('TBM 정보를 불러올 수 없습니다.', 'error');
      return;
    }

    // 팀원 정보 로드
    const teamMembers = await window.TbmAPI.getTeamMembers(sessionId);
    if (!teamMembers) {
      showToast('팀원 정보를 불러올 수 없습니다.', 'error');
      return;
    }

    // workerTaskList 구성
    workerTaskList = [];
    const workerMap = new Map();

    // 팀원별로 작업 그룹화
    teamMembers.forEach(member => {
      if (!workerMap.has(member.user_id)) {
        workerMap.set(member.user_id, {
          user_id: member.user_id,
          worker_name: member.worker_name,
          job_type: member.job_type,
          tasks: []
        });
      }

      workerMap.get(member.user_id).tasks.push({
        task_line_id: generateUUID(),
        project_id: member.project_id,
        work_type_id: member.work_type_id,
        task_id: member.task_id,
        workplace_category_id: member.workplace_category_id,
        workplace_id: member.workplace_id,
        workplace_category_name: member.workplace_category_name,
        workplace_name: member.workplace_name,
        work_detail: member.work_detail,
        is_present: member.is_present !== undefined ? member.is_present : true
      });
    });

    workerTaskList = Array.from(workerMap.values());

    // 모달 열기
    document.getElementById('modalTitle').textContent = '팀 구성 수정';
    document.getElementById('sessionId').value = sessionId;

    // 1. TBM 날짜 표시
    const dateStr = formatDate(session.session_date);
    document.getElementById('sessionDate').value = dateStr;
    const [year, month, day] = dateStr.split('-');
    const dayNames = ['일', '월', '화', '수', '목', '금', '토'];
    const dayName = dayNames[new Date(dateStr).getDay()];
    const sessionDateDisplay = document.getElementById('sessionDateDisplay');
    if (sessionDateDisplay) {
      sessionDateDisplay.textContent = `${year}년 ${parseInt(month)}월 ${parseInt(day)}일 (${dayName})`;
    }

    // 2. 입력자 표시 (.textContent 사용)
    if (session.leader_name) {
      document.getElementById('leaderName').textContent = `${session.leader_name} (${session.leader_job_type || ''})`;
      document.getElementById('leaderId').value = session.leader_user_id;
    } else if (session.created_by_name) {
      document.getElementById('leaderName').textContent = `${session.created_by_name} (관리자)`;
      document.getElementById('leaderId').value = '';
    }

    // 3. 프로젝트 드롭다운 채우기 + 기존 값 선택
    const projSelect = document.getElementById('newTbmProjectId');
    if (projSelect) {
      projSelect.innerHTML = '<option value="">선택 안함</option>' +
        allProjects.map(p => `<option value="${p.project_id}">${escapeHtml(p.project_name)} (${escapeHtml(p.job_no || '')})</option>`).join('');
      if (session.project_id) projSelect.value = session.project_id;
    }

    // 4. 공정 드롭다운 채우기 + 기존 값 선택
    const wtSelect = document.getElementById('newTbmWorkTypeId');
    if (wtSelect) {
      wtSelect.innerHTML = '<option value="">공정 선택...</option>' +
        allWorkTypes.map(wt => `<option value="${wt.id}">${escapeHtml(wt.name)}</option>`).join('');
      if (session.work_type_id) wtSelect.value = session.work_type_id;
    }

    // 생성 모드 섹션 숨기고 편집 모드 섹션 표시
    const createSection = document.getElementById('newTbmWorkerGrid')?.closest('.tbm-form-section');
    const editSection = document.getElementById('workerTaskListSection');
    if (createSection) createSection.style.display = 'none';
    if (editSection) editSection.style.display = 'block';

    renderWorkerTaskList();

    document.getElementById('tbmModal').style.display = 'flex';
    lockBodyScroll();

  } catch (error) {
    console.error(' 팀 구성 로드 오류:', error);
    showToast('팀 구성을 불러오는 중 오류가 발생했습니다.', 'error');
  }
}
window.openTeamCompositionModal = openTeamCompositionModal;

// 선택된 작업자 업데이트
function updateSelectedWorkers() {
  selectedWorkers.clear();

  document.querySelectorAll('.worker-checkbox:checked').forEach(cb => {
    selectedWorkers.add(parseInt(cb.dataset.userId));
  });

  const selectedCount = document.getElementById('selectedCount');
  const selectedList = document.getElementById('selectedWorkersList');

  selectedCount.textContent = selectedWorkers.size;

  if (selectedWorkers.size === 0) {
    selectedList.innerHTML = '<p style="margin: 0; color: #9ca3af; font-size: 0.875rem;">작업자를 선택해주세요</p>';
  } else {
    const selectedWorkersArray = Array.from(selectedWorkers).map(id => {
      const worker = allWorkers.find(w => w.user_id === id);
      return worker ? `
        <span style="display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.25rem 0.75rem; background: #3b82f6; color: white; border-radius: 9999px; font-size: 0.875rem;">
          ${worker.worker_name}
          <button onclick="removeWorker(${id})" style="background: none; border: none; color: white; cursor: pointer; padding: 0; margin-left: 0.25rem; font-size: 1rem; line-height: 1;">×</button>
        </span>
      ` : '';
    });
    selectedList.innerHTML = selectedWorkersArray.join('');
  }
}
window.updateSelectedWorkers = updateSelectedWorkers;

// 작업자 제거
function removeWorker(workerId) {
  const checkbox = document.querySelector(`.worker-checkbox[data-user-id="${workerId}"]`);
  if (checkbox) {
    checkbox.checked = false;
    updateSelectedWorkers();
  }
}
window.removeWorker = removeWorker;

// 전체 선택
function selectAllWorkers() {
  document.querySelectorAll('.worker-checkbox').forEach(cb => {
    cb.checked = true;
  });
  updateSelectedWorkers();
}
window.selectAllWorkers = selectAllWorkers;

// 전체 해제
function deselectAllWorkers() {
  document.querySelectorAll('.worker-checkbox').forEach(cb => {
    cb.checked = false;
  });
  updateSelectedWorkers();
}
window.deselectAllWorkers = deselectAllWorkers;

// 팀 구성 모달 닫기
function closeTeamModal() {
  document.getElementById('teamModal').style.display = 'none';
  unlockBodyScroll();
}
window.closeTeamModal = closeTeamModal;

// 팀 구성 저장
async function saveTeamComposition() {
  if (selectedWorkers.size === 0) {
    showToast('최소 1명 이상의 작업자를 선택해주세요.', 'error');
    return;
  }

  const members = Array.from(selectedWorkers).map(workerId => ({
    user_id: workerId
  }));

  try {
    const response = await window.TbmAPI.addTeamMembers(currentSessionId, members);

    if (response && response.success) {
      showToast(`${selectedWorkers.size}명의 팀원이 추가되었습니다.`, 'success');
      closeTeamModal();

      // 목록 새로고침
      if (currentTab === 'tbm-input') {
        await loadTodayOnlyTbm();
      } else {
        const date = document.getElementById('tbmDate').value;
        await loadTbmSessionsByDate(date);
      }
    } else {
      throw new Error(response.message || '저장에 실패했습니다.');
    }
  } catch (error) {
    console.error(' 팀 구성 저장 오류:', error);
    showToast('팀 구성 저장 중 오류가 발생했습니다.', 'error');
  }
}
window.saveTeamComposition = saveTeamComposition;

// 안전 체크 모달 열기 (기본 + 날씨별 + 작업별)
async function openSafetyCheckModal(sessionId) {
  currentSessionId = sessionId;

  try {
    // 필터링된 체크리스트 조회 (기본 + 날씨 + 작업별)
    const filteredData = await window.TbmAPI.getFilteredSafetyChecks(sessionId);

    const { basic, weather, task, weatherInfo } = filteredData;

    const categoryNames = {
      'PPE': '개인 보호 장비',
      'EQUIPMENT': '장비 점검',
      'ENVIRONMENT': '작업 환경',
      'EMERGENCY': '비상 대응',
      'WEATHER': '날씨',
      'TASK': '작업'
    };

    const weatherIcons = {
      clear: '☀️', rain: '🌧️', snow: '❄️', heat: '🔥',
      cold: '🥶', wind: '💨', fog: '🌫️', dust: '😷'
    };

    const container = document.getElementById('safetyChecklistContainer');
    let html = '';

    // 1. 기본 사항 섹션
    if (basic && basic.length > 0) {
      const basicGrouped = groupChecksByCategory(basic);
      html += `
        <div class="safety-section" style="margin-bottom: 1.5rem;">
          <div style="font-weight: 700; font-size: 1rem; color: #1f2937; padding: 0.75rem 1rem; background: linear-gradient(135deg, #3b82f6, #2563eb); color: white; border-radius: 0.5rem; margin-bottom: 0.75rem; display: flex; align-items: center; gap: 0.5rem;">
            <span>📋</span> 기본 안전 사항 (${basic.length}개)
          </div>
          ${renderCategoryGroups(basicGrouped, categoryNames)}
        </div>
      `;
    }

    // 2. 날씨별 섹션
    if (weather && weather.length > 0) {
      const weatherConditions = weatherInfo?.weather_conditions || [];
      const conditionNames = weatherConditions.map(c => {
        const icon = weatherIcons[c] || '🌤️';
        return `${icon} ${getWeatherConditionName(c)}`;
      }).join(', ') || '맑음';

      html += `
        <div class="safety-section" style="margin-bottom: 1.5rem;">
          <div style="font-weight: 700; font-size: 1rem; color: #1f2937; padding: 0.75rem 1rem; background: linear-gradient(135deg, #f59e0b, #d97706); color: white; border-radius: 0.5rem; margin-bottom: 0.75rem; display: flex; align-items: center; gap: 0.5rem;">
            <span>🌤️</span> 오늘 날씨 관련 (${conditionNames}) - ${weather.length}개
          </div>
          ${renderCheckItems(weather)}
        </div>
      `;
    }

    // 3. 작업별 섹션
    if (task && task.length > 0) {
      const taskGrouped = groupChecksByTask(task);
      html += `
        <div class="safety-section" style="margin-bottom: 1.5rem;">
          <div style="font-weight: 700; font-size: 1rem; color: #1f2937; padding: 0.75rem 1rem; background: linear-gradient(135deg, #10b981, #059669); color: white; border-radius: 0.5rem; margin-bottom: 0.75rem; display: flex; align-items: center; gap: 0.5rem;">
            <span>🔧</span> 작업별 안전 사항 - ${task.length}개
          </div>
          ${renderTaskGroups(taskGrouped)}
        </div>
      `;
    }

    // 체크리스트가 없는 경우
    if ((!basic || basic.length === 0) && (!weather || weather.length === 0) && (!task || task.length === 0)) {
      html = `
        <div style="text-align: center; padding: 2rem; color: #6b7280;">
          <div style="font-size: 2rem; margin-bottom: 0.5rem;">📋</div>
          <p>등록된 안전 체크 항목이 없습니다.</p>
        </div>
      `;
    }

    container.innerHTML = html;
    document.getElementById('safetyModal').style.display = 'flex';
    lockBodyScroll();

  } catch (error) {
    console.error(' 안전 체크 조회 오류:', error);
    showToast('안전 체크 정보를 불러오는 중 오류가 발생했습니다.', 'error');
  }
}
window.openSafetyCheckModal = openSafetyCheckModal;

// 카테고리별 그룹화
function groupChecksByCategory(checks) {
  return checks.reduce((acc, check) => {
    const category = check.check_category || 'OTHER';
    if (!acc[category]) acc[category] = [];
    acc[category].push(check);
    return acc;
  }, {});
}

// 작업별 그룹화
function groupChecksByTask(checks) {
  return checks.reduce((acc, check) => {
    const taskId = check.task_id || 0;
    const taskName = check.task_name || '기타 작업';
    if (!acc[taskId]) acc[taskId] = { name: taskName, items: [] };
    acc[taskId].items.push(check);
    return acc;
  }, {});
}

// 날씨 조건명 반환
function getWeatherConditionName(code) {
  const names = {
    clear: '맑음', rain: '비', snow: '눈', heat: '폭염',
    cold: '한파', wind: '강풍', fog: '안개', dust: '미세먼지'
  };
  return names[code] || code;
}

// 카테고리 그룹 렌더링
function renderCategoryGroups(grouped, categoryNames) {
  return Object.keys(grouped).map(category => `
    <div style="margin-bottom: 1rem; background: white; border-radius: 0.5rem; border: 1px solid #e5e7eb; overflow: hidden;">
      <div style="font-weight: 600; font-size: 0.875rem; color: #374151; padding: 0.625rem 0.875rem; background: #f9fafb; border-bottom: 1px solid #e5e7eb;">
        ${categoryNames[category] || category}
      </div>
      ${renderCheckItems(grouped[category])}
    </div>
  `).join('');
}

// 작업 그룹 렌더링
function renderTaskGroups(grouped) {
  return Object.values(grouped).map(group => `
    <div style="margin-bottom: 1rem; background: white; border-radius: 0.5rem; border: 1px solid #e5e7eb; overflow: hidden;">
      <div style="font-weight: 600; font-size: 0.875rem; color: #374151; padding: 0.625rem 0.875rem; background: #f9fafb; border-bottom: 1px solid #e5e7eb;">
        📋 ${group.name}
      </div>
      ${renderCheckItems(group.items)}
    </div>
  `).join('');
}

// 체크 항목 렌더링
function renderCheckItems(items) {
  return items.map(check => `
    <div style="padding: 0.75rem; border-bottom: 1px solid #f3f4f6;">
      <label style="display: flex; align-items: start; gap: 0.75rem; cursor: pointer;">
        <input type="checkbox"
               class="safety-check"
               data-check-id="${check.check_id}"
               ${check.is_checked ? 'checked' : ''}
               ${check.is_required ? 'required' : ''}
               style="width: 18px; height: 18px; margin-top: 0.125rem; cursor: pointer;">
        <div style="flex: 1;">
          <div style="font-weight: 500; color: #111827;">
            ${check.check_item}
            ${check.is_required ? '<span style="color: #ef4444;">*</span>' : ''}
          </div>
          ${check.description ? `<div style="font-size: 0.75rem; color: #6b7280; margin-top: 0.25rem;">${check.description}</div>` : ''}
        </div>
      </label>
    </div>
  `).join('');
}

// 안전 체크 모달 닫기
function closeSafetyModal() {
  document.getElementById('safetyModal').style.display = 'none';
  unlockBodyScroll();
}
window.closeSafetyModal = closeSafetyModal;

// 안전 체크리스트 저장
async function saveSafetyChecklist() {
  const records = [];

  document.querySelectorAll('.safety-check').forEach(cb => {
    records.push({
      check_id: parseInt(cb.dataset.checkId),
      is_checked: cb.checked
    });
  });

  try {
    await window.TbmAPI.saveSafetyChecks(currentSessionId, records);
    showToast('안전 체크가 완료되었습니다.', 'success');
    closeSafetyModal();
  } catch (error) {
    console.error(' 안전 체크 저장 오류:', error);
    showToast('안전 체크 저장 중 오류가 발생했습니다.', 'error');
  }
}
window.saveSafetyChecklist = saveSafetyChecklist;

// TBM 완료 모달용 팀원 데이터
let completeModalTeam = [];

// TBM 완료 모달 열기
async function openCompleteTbmModal(sessionId) {
  currentSessionId = sessionId;
  const now = new Date();
  const timeString = now.toTimeString().slice(0, 5);
  document.getElementById('endTime').value = timeString;

  document.getElementById('completeModal').style.display = 'flex';
  lockBodyScroll();

  // 팀원 조회 → 근태 선택 렌더링
  try {
    completeModalTeam = await window.TbmAPI.getTeamMembers(sessionId);
    renderCompleteAttendanceList();
  } catch (e) {
    console.error('팀원 조회 오류:', e);
    document.getElementById('completeAttendanceList').innerHTML =
      '<div style="color:#ef4444; padding:0.5rem;">팀원 목록을 불러올 수 없습니다.</div>';
  }
}
window.openCompleteTbmModal = openCompleteTbmModal;

function renderCompleteAttendanceList() {
  const container = document.getElementById('completeAttendanceList');
  if (completeModalTeam.length === 0) {
    container.innerHTML = '<div style="color:#9ca3af; padding:0.5rem; text-align:center;">팀원이 없습니다.</div>';
    return;
  }
  let html = '<table style="width:100%; border-collapse:collapse; font-size:0.8125rem;">' +
    '<tr style="background:#f9fafb;"><th style="padding:0.5rem; text-align:left;">작업자</th><th style="padding:0.5rem; text-align:left;">직종</th><th style="padding:0.5rem; text-align:left;">근태</th><th style="padding:0.5rem; text-align:center;">추가</th></tr>';
  completeModalTeam.forEach((m, i) => {
    html += `<tr style="border-top:1px solid #f3f4f6;">
      <td style="padding:0.5rem; font-weight:600;">${m.worker_name || ''}</td>
      <td style="padding:0.5rem; color:#6b7280;">${m.job_type || '-'}</td>
      <td style="padding:0.5rem;">
        <select id="catt_type_${i}" onchange="onCompleteAttChange(${i})" style="padding:0.375rem; border:1px solid #d1d5db; border-radius:0.25rem; font-size:0.8125rem; background:white;">
          <option value="regular">정시근로 (8h)</option>
          <option value="overtime">연장근무 (8h+)</option>
          <option value="annual">연차 (휴무)</option>
          <option value="half">반차 (4h)</option>
          <option value="quarter">반반차 (6h)</option>
          <option value="early">조퇴</option>
        </select>
      </td>
      <td style="padding:0.5rem; text-align:center;">
        <input type="number" id="catt_hours_${i}" step="0.5" min="0" max="8" style="display:none; width:60px; padding:0.375rem; border:1px solid #d1d5db; border-radius:0.25rem; font-size:0.8125rem; text-align:center;">
        <span id="catt_hint_${i}" style="font-size:0.75rem; color:#6b7280;"></span>
      </td>
    </tr>`;
  });
  html += '</table>';
  container.innerHTML = html;
}

window.onCompleteAttChange = function(idx) {
  const sel = document.getElementById('catt_type_' + idx);
  const inp = document.getElementById('catt_hours_' + idx);
  const hint = document.getElementById('catt_hint_' + idx);
  const val = sel.value;
  if (val === 'overtime') {
    inp.style.display = 'inline-block';
    inp.placeholder = '+h';
    inp.value = '';
    hint.textContent = '';
  } else if (val === 'early') {
    inp.style.display = 'inline-block';
    inp.placeholder = '시간';
    inp.value = '';
    hint.textContent = '';
  } else {
    inp.style.display = 'none';
    inp.value = '';
    const labels = { regular: '8h', annual: '자동처리', half: '4h', quarter: '6h' };
    hint.textContent = labels[val] || '';
  }
};

// 완료 모달 닫기
function closeCompleteModal() {
  document.getElementById('completeModal').style.display = 'none';
  unlockBodyScroll();
}
window.closeCompleteModal = closeCompleteModal;

// TBM 세션 완료
async function completeTbmSession() {
  const endTime = document.getElementById('endTime').value;

  // 근태 데이터 수집
  const attendanceData = [];
  for (let i = 0; i < completeModalTeam.length; i++) {
    const type = document.getElementById('catt_type_' + i).value;
    const hoursVal = document.getElementById('catt_hours_' + i).value;
    const hours = hoursVal ? parseFloat(hoursVal) : null;

    if (type === 'overtime' && (!hours || hours <= 0)) {
      showToast(`${completeModalTeam[i].worker_name}의 추가 시간을 입력해주세요.`, 'error');
      return;
    }
    if (type === 'early' && (!hours || hours <= 0)) {
      showToast(`${completeModalTeam[i].worker_name}의 근무 시간을 입력해주세요.`, 'error');
      return;
    }

    attendanceData.push({
      user_id: completeModalTeam[i].user_id,
      attendance_type: type,
      attendance_hours: hours
    });
  }

  const btn = document.getElementById('completeModalBtn');
  if (btn) { btn.disabled = true; btn.textContent = '처리 중...'; }

  try {
    const response = await window.apiCall(
      `/tbm/sessions/${currentSessionId}/complete`,
      'POST',
      { end_time: endTime, attendance_data: attendanceData }
    );

    if (response && response.success) {
      showToast('TBM이 완료되었습니다.', 'success');
      closeCompleteModal();

      // 목록 새로고침
      if (currentTab === 'tbm-input') {
        await loadTodayOnlyTbm();
      } else {
        const date = document.getElementById('tbmDate').value;
        await loadTbmSessionsByDate(date);
      }
    } else {
      throw new Error(response.message || '완료 처리에 실패했습니다.');
    }
  } catch (error) {
    console.error(' TBM 완료 처리 오류:', error);
    showToast('TBM 완료 처리 중 오류가 발생했습니다.', 'error');
  } finally {
    if (btn) { btn.disabled = false; btn.innerHTML = '<span class="tbm-btn-icon">&#10003;</span> 완료'; }
  }
}
window.completeTbmSession = completeTbmSession;

// TBM 세션 상세 보기
async function viewTbmSession(sessionId) {
  try {
    // 세션 정보, 팀 구성, 안전 체크 동시 조회
    const [session, team, safety] = await Promise.all([
      window.TbmAPI.getSession(sessionId),
      window.TbmAPI.getTeamMembers(sessionId),
      window.TbmAPI.getSafetyChecks(sessionId)
    ]);

    if (!session) {
      showToast('세션 정보를 불러올 수 없습니다.', 'error');
      return;
    }

    // 기본 정보 표시
    const leaderDisplay = session.leader_name || session.created_by_name || '-';
    const dateDisplay = formatDate(session.session_date) || '-';
    const statusMap = { draft: '진행중', completed: '완료', cancelled: '취소' };
    const statusText = statusMap[session.status] || session.status;

    const basicInfo = document.getElementById('detailBasicInfo');
    basicInfo.innerHTML = `
      <div style="padding: 0.75rem; background: #f9fafb; border-radius: 0.375rem;">
        <div style="font-size: 0.75rem; color: #6b7280; margin-bottom: 0.25rem;">입력자</div>
        <div style="font-weight: 600; color: #111827;">${escapeHtml(leaderDisplay)}</div>
      </div>
      <div style="padding: 0.75rem; background: #f9fafb; border-radius: 0.375rem;">
        <div style="font-size: 0.75rem; color: #6b7280; margin-bottom: 0.25rem;">날짜</div>
        <div style="font-weight: 600; color: #111827;">${escapeHtml(dateDisplay)}</div>
      </div>
      <div style="padding: 0.75rem; background: #f9fafb; border-radius: 0.375rem;">
        <div style="font-size: 0.75rem; color: #6b7280; margin-bottom: 0.25rem;">상태</div>
        <div style="font-weight: 600; color: #111827;">${escapeHtml(statusText)}</div>
      </div>
      <div style="padding: 0.75rem; background: #f9fafb; border-radius: 0.375rem;">
        <div style="font-size: 0.75rem; color: #6b7280; margin-bottom: 0.25rem;">팀원 (${parseInt(session.team_member_count) || team.length}명)</div>
        <div style="font-weight: 600; color: #111827;">${escapeHtml(session.team_member_names || team.map(t => t.worker_name).join(', ') || '없음')}</div>
      </div>
      ${session.project_name ? `
        <div style="padding: 0.75rem; background: #f9fafb; border-radius: 0.375rem;">
          <div style="font-size: 0.75rem; color: #6b7280; margin-bottom: 0.25rem;">프로젝트</div>
          <div style="font-weight: 600; color: #111827;">${escapeHtml(session.project_name)}</div>
        </div>
      ` : ''}
      ${session.work_location ? `
        <div style="padding: 0.75rem; background: #f9fafb; border-radius: 0.375rem;">
          <div style="font-size: 0.75rem; color: #6b7280; margin-bottom: 0.25rem;">작업장</div>
          <div style="font-weight: 600; color: #111827;">${escapeHtml(session.work_location)}</div>
        </div>
      ` : ''}
    `;

    // 팀 구성 표시 (작업자별 작업 정보 포함)
    const teamContainer = document.getElementById('detailTeamMembers');
    if (team.length === 0) {
      teamContainer.innerHTML = '<p style="color: #6b7280; font-size: 0.875rem;">등록된 팀원이 없습니다.</p>';
    } else {
      // 작업자별로 그룹화
      const workerMap = new Map();
      team.forEach(member => {
        if (!workerMap.has(member.user_id)) {
          workerMap.set(member.user_id, {
            worker_name: member.worker_name,
            job_type: member.job_type,
            is_present: member.is_present,
            tasks: []
          });
        }
        workerMap.get(member.user_id).tasks.push(member);
      });

      teamContainer.style.display = 'flex';
      teamContainer.style.flexDirection = 'column';
      teamContainer.style.gap = '0.75rem';
      teamContainer.style.gridTemplateColumns = '';

      teamContainer.innerHTML = Array.from(workerMap.values()).map(worker => `
        <div style="border: 1px solid #e5e7eb; border-radius: 0.5rem; overflow: hidden;">
          <div style="padding: 0.625rem 0.875rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; display: flex; align-items: center; justify-content: space-between;">
            <div>
              <span style="font-weight: 600;">${escapeHtml(worker.worker_name)}</span>
              <span style="font-size: 0.75rem; opacity: 0.85; margin-left: 0.25rem;">${escapeHtml(worker.job_type || '')}</span>
            </div>
            ${!worker.is_present ? '<span style="font-size: 0.75rem; background: rgba(239,68,68,0.8); padding: 0.125rem 0.5rem; border-radius: 4px;">결석</span>' : ''}
          </div>
          <div style="padding: 0.625rem 0.875rem;">
            ${worker.tasks.map(t => `
              <div style="display: flex; flex-wrap: wrap; gap: 0.375rem; margin-bottom: 0.375rem;">
                ${t.project_name ? `<span style="font-size: 0.75rem; padding: 0.125rem 0.5rem; background: #dbeafe; color: #1e40af; border-radius: 4px;">${escapeHtml(t.project_name)}</span>` : ''}
                ${t.work_type_name ? `<span style="font-size: 0.75rem; padding: 0.125rem 0.5rem; background: #fef3c7; color: #92400e; border-radius: 4px;">${escapeHtml(t.work_type_name)}</span>` : ''}
                ${t.task_name ? `<span style="font-size: 0.75rem; padding: 0.125rem 0.5rem; background: #dcfce7; color: #166534; border-radius: 4px;">${escapeHtml(t.task_name)}</span>` : ''}
                ${t.workplace_name ? `<span style="font-size: 0.75rem; padding: 0.125rem 0.5rem; background: #f1f5f9; color: #475569; border-radius: 4px;">${escapeHtml((t.workplace_category_name ? t.workplace_category_name + ' > ' : '') + t.workplace_name)}</span>` : ''}
              </div>
            `).join('')}
          </div>
        </div>
      `).join('');
    }

    // 안전 체크 표시
    const safetyChecks = document.getElementById('detailSafetyChecks');
    if (safety.length === 0) {
      safetyChecks.innerHTML = '<p style="color: #6b7280; font-size: 0.875rem;">안전 체크 기록이 없습니다.</p>';
    } else {
      // 카테고리별 그룹화
      const grouped = {};
      safety.forEach(check => {
        if (!grouped[check.check_category]) {
          grouped[check.check_category] = [];
        }
        grouped[check.check_category].push(check);
      });

      const categoryNames = {
        'PPE': '개인 보호 장비',
        'EQUIPMENT': '장비 점검',
        'ENVIRONMENT': '작업 환경',
        'EMERGENCY': '비상 대응'
      };

      safetyChecks.innerHTML = Object.keys(grouped).map(category => `
        <div style="margin-bottom: 1rem;">
          <div style="font-weight: 600; font-size: 0.875rem; color: #374151; margin-bottom: 0.5rem; padding: 0.5rem; background: #f3f4f6; border-radius: 0.25rem;">
            ${categoryNames[category] || category}
          </div>
          <div style="display: grid; gap: 0.5rem;">
            ${grouped[category].map(check => `
              <div style="display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem; border-radius: 0.25rem; ${check.is_checked ? 'background: #f0fdf4;' : 'background: #fef2f2;'}">
                <span style="font-size: 1.25rem;">${check.is_checked ? '✅' : '❌'}</span>
                <span style="flex: 1; font-size: 0.875rem; color: #374151;">${check.check_item}</span>
              </div>
            `).join('')}
          </div>
        </div>
      `).join('');
    }

    // 푸터 버튼 동적 생성
    const footer = document.getElementById('detailModalFooter');
    const safeId = parseInt(session.session_id) || 0;
    if (session.status === 'draft') {
      footer.innerHTML = `
        <button type="button" class="tbm-btn tbm-btn-danger" onclick="confirmDeleteTbm(${safeId})">
          삭제
        </button>
        <button type="button" class="tbm-btn tbm-btn-primary" onclick="closeDetailModal(); openTeamCompositionModal(${safeId})">
          수정
        </button>
        <button type="button" class="tbm-btn" style="background:#8b5cf6; color:white;" onclick="closeDetailModal(); openDesktopSplitModal(${safeId})">
          분할
        </button>
        <button type="button" class="tbm-btn" style="background:#f59e0b; color:white;" onclick="closeDetailModal(); openDesktopPullModal(${safeId})">
          빼오기
        </button>
        <button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeDetailModal()">닫기</button>
      `;
    } else {
      footer.innerHTML = `
        <button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeDetailModal()">닫기</button>
      `;
    }

    document.getElementById('detailModal').style.display = 'flex';
    lockBodyScroll();

  } catch (error) {
    console.error(' TBM 상세 조회 오류:', error);
    showToast('상세 정보를 불러오는 중 오류가 발생했습니다.', 'error');
  }
}
window.viewTbmSession = viewTbmSession;

// TBM 삭제 확인
function confirmDeleteTbm(sessionId) {
  if (!confirm('이 TBM을 삭제하시겠습니까?\n삭제 후 복구할 수 없습니다.')) return;
  deleteTbmSession(sessionId);
}
window.confirmDeleteTbm = confirmDeleteTbm;

// TBM 세션 삭제 → TbmAPI 위임
async function deleteTbmSession(sessionId) {
  try {
    await window.TbmAPI.deleteSession(sessionId);
    showToast('TBM이 삭제되었습니다.', 'success');
    closeDetailModal();
    if (currentTab === 'tbm-input') {
      await loadTodayOnlyTbm();
    } else {
      await loadRecentTbmGroupedByDate();
    }
  } catch (error) {
    console.error(' TBM 삭제 오류:', error);
    showToast(error?.message || 'TBM 삭제 중 오류가 발생했습니다.', 'error');
  }
}
window.deleteTbmSession = deleteTbmSession;

// 상세보기 모달 닫기
function closeDetailModal() {
  document.getElementById('detailModal').style.display = 'none';
  unlockBodyScroll();
}
window.closeDetailModal = closeDetailModal;

// 작업 인계 모달 열기
async function openHandoverModal(sessionId) {
  currentSessionId = sessionId;

  // 세션 정보와 팀 구성 조회
  try {
    const [session, team] = await Promise.all([
      window.TbmAPI.getSession(sessionId),
      window.TbmAPI.getTeamMembers(sessionId)
    ]);

    if (!session) {
      showToast('세션 정보를 불러올 수 없습니다.', 'error');
      return;
    }

    // 현재 세션의 팀장을 제외한 리더 목록
    const toLeaderSelect = document.getElementById('toLeaderId');
    const otherLeaders = allWorkers.filter(w =>
      (w.job_type === 'leader' || w.job_type === '그룹장' || w.job_type === 'admin') &&
      w.user_id !== session.leader_user_id
    );

    toLeaderSelect.innerHTML = '<option value="">인수자 선택...</option>' +
      otherLeaders.map(w => `
        <option value="${w.user_id}">${w.worker_name} (${w.job_type || ''})</option>
      `).join('');

    // 인계할 팀원 목록
    const handoverTeamList = document.getElementById('handoverTeamList');
    if (team.length === 0) {
      handoverTeamList.innerHTML = '<p style="padding: 1rem; color: #6b7280; text-align: center;">팀 구성이 없습니다.</p>';
    } else {
      handoverTeamList.innerHTML = team.map(member => `
        <label style="display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem; cursor: pointer; border-radius: 0.25rem; transition: background 0.2s;"
               onmouseover="this.style.background='#f9fafb'" onmouseout="this.style.background='white'">
          <input type="checkbox"
                 class="handover-worker-checkbox"
                 value="${member.user_id}"
                 checked
                 style="width: 16px; height: 16px; cursor: pointer;">
          <span style="font-weight: 500; font-size: 0.875rem;">${member.worker_name}</span>
          <span style="font-size: 0.75rem; color: #6b7280; margin-left: auto;">${member.job_type || ''}</span>
        </label>
      `).join('');
    }

    // 기본값 설정
    document.getElementById('handoverSessionId').value = sessionId;
    const today = getTodayKST();
    const now = new Date().toTimeString().slice(0, 5);
    document.getElementById('handoverDate').value = today;
    document.getElementById('handoverTime').value = now;
    document.getElementById('handoverReason').value = '';
    document.getElementById('handoverNotes').value = '';

    document.getElementById('handoverModal').style.display = 'flex';
    lockBodyScroll();

  } catch (error) {
    console.error(' 인계 모달 열기 오류:', error);
    showToast('인계 정보를 불러오는 중 오류가 발생했습니다.', 'error');
  }
}
window.openHandoverModal = openHandoverModal;

// 인계 모달 닫기
function closeHandoverModal() {
  document.getElementById('handoverModal').style.display = 'none';
  unlockBodyScroll();
}
window.closeHandoverModal = closeHandoverModal;

// 작업 인계 저장
async function saveHandover() {
  const sessionId = currentSessionId;
  const toLeaderId = parseInt(document.getElementById('toLeaderId').value);
  const reason = document.getElementById('handoverReason').value;
  const handoverDate = document.getElementById('handoverDate').value;
  const handoverTime = document.getElementById('handoverTime').value;
  const handoverNotes = document.getElementById('handoverNotes').value;

  if (!toLeaderId || !reason || !handoverDate) {
    showToast('필수 항목을 입력해주세요.', 'error');
    return;
  }

  // 인계할 작업자 목록
  const workerIds = [];
  document.querySelectorAll('.handover-worker-checkbox:checked').forEach(cb => {
    workerIds.push(parseInt(cb.value));
  });

  if (workerIds.length === 0) {
    showToast('인계할 팀원을 최소 1명 이상 선택해주세요.', 'error');
    return;
  }

  try {
    // 세션 정보 조회 (from_leader_user_id 가져오기)
    const sessionData = await window.TbmAPI.getSession(sessionId);
    const fromLeaderId = sessionData?.leader_user_id;

    if (!fromLeaderId) {
      showToast('세션 정보를 찾을 수 없습니다.', 'error');
      return;
    }

    const handoverData = {
      session_id: sessionId,
      from_leader_user_id: fromLeaderId,
      to_leader_user_id: toLeaderId,
      handover_date: handoverDate,
      handover_time: handoverTime,
      reason: reason,
      handover_notes: handoverNotes,
      user_ids: workerIds
    };

    const response = await window.TbmAPI.saveHandover(handoverData);

    if (response && response.success) {
      showToast('작업 인계가 요청되었습니다.', 'success');
      closeHandoverModal();
    } else {
      throw new Error(response.message || '인계 요청에 실패했습니다.');
    }
  } catch (error) {
    console.error(' 작업 인계 저장 오류:', error);
    showToast('작업 인계 중 오류가 발생했습니다.', 'error');
  }
}
window.saveHandover = saveHandover;

// ==================== 데스크탑 분할 기능 ====================

let splitModalSessionId = null;
let splitModalTeam = [];

async function openDesktopSplitModal(sessionId) {
  splitModalSessionId = sessionId;
  try {
    splitModalTeam = await window.TbmAPI.getTeamMembers(sessionId);
    if (splitModalTeam.length === 0) {
      showToast('팀원이 없습니다.', 'error'); return;
    }
    const modal = document.getElementById('splitModal');
    if (!modal) { showToast('분할 모달을 찾을 수 없습니다.', 'error'); return; }

    const list = document.getElementById('splitMemberList');
    list.innerHTML = splitModalTeam.map((m, i) => {
      const hours = m.work_hours != null ? parseFloat(m.work_hours) : 8;
      return `
        <div style="display:flex; align-items:center; justify-content:space-between; padding:0.5rem; border:1px solid #e5e7eb; border-radius:0.375rem;">
          <div>
            <strong>${escapeHtml(m.worker_name)}</strong>
            <span style="font-size:0.75rem; color:#6b7280;">(${hours}h)</span>
          </div>
          <div style="display:flex; gap:0.25rem; align-items:center;">
            <input type="number" id="split_hours_${i}" step="0.5" min="0.5" max="${hours - 0.5}" placeholder="분할시간" style="width:80px; padding:0.25rem; border:1px solid #d1d5db; border-radius:0.25rem; font-size:0.8125rem;">
            <button type="button" class="tbm-btn tbm-btn-primary" style="padding:0.25rem 0.5rem; font-size:0.75rem;" onclick="executeSplit(${i})">분할</button>
          </div>
        </div>`;
    }).join('');

    modal.style.display = 'flex';
    lockBodyScroll();
  } catch(e) {
    console.error('분할 모달 오류:', e);
    showToast('팀원 조회 오류', 'error');
  }
}
window.openDesktopSplitModal = openDesktopSplitModal;

async function executeSplit(memberIdx) {
  const m = splitModalTeam[memberIdx];
  const currentHours = m.work_hours != null ? parseFloat(m.work_hours) : 8;
  const splitHours = parseFloat(document.getElementById(`split_hours_${memberIdx}`).value);
  if (!splitHours || splitHours <= 0 || splitHours >= currentHours) {
    showToast(`올바른 시간 입력 (0 < 시간 < ${currentHours})`, 'error'); return;
  }
  try {
    await window.TbmAPI.updateTeamMember(splitModalSessionId, {
      user_id: m.user_id, project_id: m.project_id, work_type_id: m.work_type_id,
      task_id: m.task_id, workplace_category_id: m.workplace_category_id, workplace_id: m.workplace_id,
      work_detail: m.work_detail, is_present: true, work_hours: splitHours
    });
    await window.TbmAPI.splitAssignment(splitModalSessionId, {
      user_id: m.user_id, work_hours: currentHours - splitHours,
      project_id: m.project_id, work_type_id: m.work_type_id
    });
    showToast(`${escapeHtml(m.worker_name)} 분할 완료: ${splitHours}h + ${currentHours - splitHours}h`, 'success');
    closeSplitModal();
    if (currentTab === 'tbm-input') await loadTodayOnlyTbm(); else await loadRecentTbmGroupedByDate();
  } catch(e) {
    console.error('분할 오류:', e);
    showToast('분할 처리 중 오류', 'error');
  }
}
window.executeSplit = executeSplit;

function closeSplitModal() {
  const modal = document.getElementById('splitModal');
  if (modal) modal.style.display = 'none';
  unlockBodyScroll();
}
window.closeSplitModal = closeSplitModal;

// ==================== 데스크탑 빼오기 기능 ====================

let pullModalSessionId = null;

async function openDesktopPullModal(targetSessionId) {
  pullModalSessionId = targetSessionId;
  try {
    const todayStr = getTodayKST();
    const sessions = await window.TbmAPI.fetchSessionsByDate(todayStr);
    const otherSessions = sessions.filter(s => s.session_id !== targetSessionId && s.status === 'draft');

    const modal = document.getElementById('pullModal');
    if (!modal) { showToast('빼오기 모달을 찾을 수 없습니다.', 'error'); return; }

    const list = document.getElementById('pullSessionList');
    if (otherSessions.length === 0) {
      list.innerHTML = '<div style="padding:1rem; text-align:center; color:#9ca3af;">빼올 수 있는 다른 TBM이 없습니다.</div>';
    } else {
      list.innerHTML = otherSessions.map(s => {
        const leader = escapeHtml(s.leader_name || s.created_by_name || '미지정');
        const count = parseInt(s.team_member_count) || 0;
        return `
          <div style="border:1px solid #e5e7eb; border-radius:0.375rem; margin-bottom:0.5rem;">
            <div style="padding:0.5rem 0.75rem; cursor:pointer; display:flex; justify-content:space-between; align-items:center;" onclick="togglePullSessionMembers(${s.session_id}, this)">
              <div><strong>${leader}</strong> <span style="font-size:0.75rem; color:#6b7280;">(${count}명)</span></div>
              <span style="font-size:0.75rem; color:#6b7280;">▼</span>
            </div>
            <div id="pullMembers_${s.session_id}" style="display:none; padding:0.5rem; border-top:1px solid #f3f4f6;"></div>
          </div>`;
      }).join('');
    }

    modal.style.display = 'flex';
    lockBodyScroll();
  } catch(e) {
    console.error('빼오기 모달 오류:', e);
    showToast('빼오기 데이터 로드 오류', 'error');
  }
}
window.openDesktopPullModal = openDesktopPullModal;

async function togglePullSessionMembers(sessionId, el) {
  const container = document.getElementById(`pullMembers_${sessionId}`);
  if (container.style.display !== 'none') {
    container.style.display = 'none'; return;
  }
  try {
    const members = await window.TbmAPI.getTeamMembers(sessionId);
    container.innerHTML = members.map(m => {
      const hours = m.work_hours != null ? parseFloat(m.work_hours) : 8;
      return `
        <div style="display:flex; align-items:center; justify-content:space-between; padding:0.375rem 0; border-bottom:1px solid #f9fafb;">
          <span>${escapeHtml(m.worker_name)} <span style="font-size:0.75rem; color:#6b7280;">(${hours}h)</span></span>
          <div style="display:flex; gap:0.25rem; align-items:center;">
            <input type="number" id="pull_h_${sessionId}_${m.user_id}" step="0.5" min="0.5" max="${hours}" value="${hours}" style="width:60px; padding:0.25rem; border:1px solid #d1d5db; border-radius:0.25rem; font-size:0.75rem;">
            <button type="button" class="tbm-btn tbm-btn-primary" style="padding:0.25rem 0.5rem; font-size:0.75rem;" onclick="executePull(${sessionId}, ${m.user_id}, '${escapeHtml(m.worker_name)}')">빼오기</button>
          </div>
        </div>`;
    }).join('') || '<div style="color:#9ca3af; padding:0.25rem;">팀원 없음</div>';
    container.style.display = 'block';
  } catch(e) {
    container.innerHTML = '<div style="color:#ef4444; padding:0.25rem;">로드 오류</div>';
    container.style.display = 'block';
  }
}
window.togglePullSessionMembers = togglePullSessionMembers;

async function executePull(sourceSessionId, workerId, workerName) {
  const hoursInput = document.getElementById(`pull_h_${sourceSessionId}_${workerId}`);
  const hours = parseFloat(hoursInput?.value);
  if (!hours || hours <= 0) { showToast('시간을 입력하세요', 'error'); return; }
  try {
    const res = await window.TbmAPI.transfer({
      transfer_type: 'pull',
      user_id: workerId,
      source_session_id: sourceSessionId,
      dest_session_id: pullModalSessionId,
      hours: hours
    });
    showToast(`${workerName} ${hours}h 빼오기 완료` + (res.data?.warning ? ` (${res.data.warning})` : ''), 'success');
    closePullModal();
    if (currentTab === 'tbm-input') await loadTodayOnlyTbm(); else await loadRecentTbmGroupedByDate();
  } catch(e) {
    console.error('빼오기 오류:', e);
    showToast(e.message || '빼오기 처리 오류', 'error');
  }
}
window.executePull = executePull;

function closePullModal() {
  const modal = document.getElementById('pullModal');
  if (modal) modal.style.display = 'none';
  unlockBodyScroll();
}
window.closePullModal = closePullModal;

// showToast → api-base.js 전역 사용
