/**
 * Daily Work Report - Mobile UI Logic
 * 모바일 전용 작업보고서 UI 로직
 *
 * 재사용 모듈: state.js, api.js, utils.js, api-base.js
 */

const MobileReport = (function() {
  'use strict';

  // ===== 내부 상태 =====
  let currentTab = 'tbm';
  let manualCounter = 0;
  let manualCards = {}; // { id: { data } }

  // 시간 선택 상태
  let timePickerCallback = null;
  let timePickerValue = 0;

  // 부적합 시트 상태
  let defectSheetIndex = null;
  let defectSheetType = null; // 'tbm' | 'manual'
  let defectSheetTempData = []; // 현재 편집중인 부적합 데이터

  // 작업장소 시트 상태
  let wpSheetManualId = null;
  let wpSheetStep = 'category'; // 'category' | 'list'
  let wpSelectedCategory = null;
  let wpSelectedCategoryName = null;
  let wpSelectedId = null;
  let wpSelectedName = null;

  // 수정 시트 상태
  let editReportId = null;

  // ===== 초기화 =====
  async function init() {
    console.log('[Mobile] 초기화 시작');
    showMessage('데이터를 불러오는 중...', 'loading');

    try {
      const api = window.DailyWorkReportAPI;
      const state = window.DailyWorkReportState;

      await api.loadAllData();

      // 부적합 카테고리/아이템 로드 확인
      console.log('[Mobile] issueCategories:', (state.issueCategories || []).length, '개');
      console.log('[Mobile] issueItems:', (state.issueItems || []).length, '개');

      // TBM 데이터 로드
      await api.loadIncompleteTbms();
      await api.loadDailyIssuesForTbms();

      console.log('[Mobile] incompleteTbms:', (state.incompleteTbms || []).length, '개');
      console.log('[Mobile] dailyIssuesCache:', Object.keys(state.dailyIssuesCache || {}).length, '날짜');

      hideMessage();
      renderTbmCards();

      // 완료 탭 날짜 초기화
      const today = getKoreaToday();
      const dateInput = document.getElementById('completedDate');
      if (dateInput) dateInput.value = today;

      console.log('[Mobile] 초기화 완료');
    } catch (error) {
      console.error('[Mobile] 초기화 오류:', error);
      showMessage('데이터 로드 중 오류가 발생했습니다.', 'error');
    }
  }

  // ===== 유틸리티 (CommonUtils 위임) =====
  var CU = window.CommonUtils;
  function getKoreaToday() { return CU.getTodayKST(); }
  function formatDateForApi(date) { return CU.formatDate(date) || null; }

  function formatDate(dateString) {
    if (!dateString) return '';
    const d = new Date(dateString);
    return `${d.getMonth() + 1}/${d.getDate()}`;
  }

  function getDayOfWeek(dateString) { return CU.getDayOfWeek(dateString); }

  function formatHours(val) {
    if (!val || val <= 0) return '선택';
    if (val === Math.floor(val)) return val + '시간';
    const hours = Math.floor(val);
    const mins = Math.round((val - hours) * 60);
    if (hours === 0) return mins + '분';
    return hours + '시간 ' + mins + '분';
  }

  function esc(str) {
    return window.escapeHtml ? window.escapeHtml(String(str || '')) : String(str || '').replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]));
  }

  // ===== 메시지 / 토스트 =====
  function showMessage(msg, type) {
    const el = document.getElementById('mMessage');
    if (!el) return;
    el.textContent = msg;
    el.className = 'm-message show ' + (type || 'info');
    if (type === 'success') setTimeout(hideMessage, 3000);
  }

  function hideMessage() {
    const el = document.getElementById('mMessage');
    if (el) el.className = 'm-message';
  }

  function showToast(msg, type, duration) {
    const el = document.getElementById('mToast');
    if (!el) return;
    el.textContent = msg;
    el.className = 'm-toast show ' + (type || '');
    clearTimeout(el._timer);
    el._timer = setTimeout(() => { el.className = 'm-toast'; }, duration || 2500);
  }

  function showResult(type, title, message, details) {
    const overlay = document.getElementById('mResultOverlay');
    const icons = { success: '✅', error: '❌', warning: '⚠️' };
    document.getElementById('mResultIcon').textContent = icons[type] || 'ℹ️';
    document.getElementById('mResultTitle').textContent = title;
    document.getElementById('mResultMessage').textContent = message;

    const detailsEl = document.getElementById('mResultDetails');
    if (details && Array.isArray(details) && details.length > 0) {
      detailsEl.innerHTML = '<ul>' + details.map(d => '<li>' + esc(d) + '</li>').join('') + '</ul>';
      detailsEl.style.display = 'block';
    } else if (typeof details === 'string' && details) {
      detailsEl.innerHTML = '<p>' + esc(details) + '</p>';
      detailsEl.style.display = 'block';
    } else {
      detailsEl.style.display = 'none';
    }

    overlay.classList.add('show');
  }

  function closeResult() {
    document.getElementById('mResultOverlay').classList.remove('show');
  }

  function showConfirm(message, onConfirm, isDanger) {
    const overlay = document.createElement('div');
    overlay.className = 'm-confirm-overlay';
    overlay.innerHTML = `
      <div class="m-confirm-box">
        <div class="m-confirm-message">${esc(message)}</div>
        <div class="m-confirm-actions">
          <button class="m-confirm-cancel" id="mConfirmCancel">취소</button>
          <button class="m-confirm-ok ${isDanger ? 'danger' : ''}" id="mConfirmOk">확인</button>
        </div>
      </div>
    `;
    document.body.appendChild(overlay);

    overlay.querySelector('#mConfirmCancel').onclick = () => { overlay.remove(); };
    overlay.querySelector('#mConfirmOk').onclick = () => { overlay.remove(); onConfirm(); };
  }

  // ===== 탭 관리 =====
  function switchTab(tab) {
    currentTab = tab;

    // 탭 버튼 상태
    document.querySelectorAll('.m-tab-btn').forEach(btn => {
      btn.classList.toggle('active', btn.dataset.tab === tab);
    });

    // 탭 콘텐츠
    document.querySelectorAll('.m-tab-content').forEach(el => {
      el.classList.remove('active');
    });

    const tabMap = { tbm: 'tabTbm', manual: 'tabManual', completed: 'tabCompleted' };
    const targetEl = document.getElementById(tabMap[tab]);
    if (targetEl) targetEl.classList.add('active');

    // 수동추가 버튼 표시/숨기기
    const addBtn = document.getElementById('btnAddManual');
    if (addBtn) addBtn.style.display = (tab === 'manual') ? 'block' : 'none';

    // 완료 탭 진입 시 자동 조회
    if (tab === 'completed') {
      loadCompletedReports();
    }
  }

  // ===== TBM 카드 렌더링 =====
  function renderTbmCards() {
    const state = window.DailyWorkReportState;
    const container = document.getElementById('tbmCardList');
    const tbms = state.incompleteTbms || [];

    // 탭 카운트 업데이트
    const countEl = document.getElementById('tbmCount');
    if (countEl) countEl.textContent = tbms.length;

    if (tbms.length === 0) {
      container.innerHTML = '<div class="m-empty"><div class="m-empty-icon">✅</div><div>미완료 TBM 작업이 없습니다</div></div>';
      return;
    }

    // 날짜별 그룹화
    const byDate = {};
    tbms.forEach((tbm, index) => {
      const dateStr = formatDateForApi(tbm.session_date);
      if (!byDate[dateStr]) {
        byDate[dateStr] = { date: tbm.session_date, sessions: {} };
      }
      const sessionKey = `${tbm.session_id}_${dateStr}`;
      if (!byDate[dateStr].sessions[sessionKey]) {
        byDate[dateStr].sessions[sessionKey] = {
          session_id: tbm.session_id,
          created_by_name: tbm.created_by_name,
          items: []
        };
      }
      byDate[dateStr].sessions[sessionKey].items.push({ ...tbm, originalIndex: index });
    });

    const sortedDates = Object.keys(byDate).sort((a, b) => new Date(b) - new Date(a));
    const today = getKoreaToday();
    let html = '';

    sortedDates.forEach((dateStr, dateIndex) => {
      const dateData = byDate[dateStr];
      const sessions = Object.values(dateData.sessions);
      const totalWorkers = sessions.reduce((sum, s) => sum + s.items.length, 0);
      const isToday = dateStr === today;
      const isExpanded = isToday || dateIndex === 0;
      const dayOfWeek = getDayOfWeek(dateStr);

      // 당일 신고
      const issues = state.dailyIssuesCache[dateStr] || [];
      const nonconfCount = issues.filter(i => i.category_type === 'nonconformity').length;

      html += `
        <div class="m-date-group ${isExpanded ? 'expanded' : ''}" data-date="${dateStr}">
          <div class="m-date-header" onclick="MobileReport.toggleDateGroup('${dateStr}')">
            <div class="m-date-left">
              <span class="m-date-toggle">▶</span>
              <span class="m-date-title">${formatDate(dateData.date)} (${dayOfWeek})</span>
              ${isToday ? '<span class="m-today-badge">오늘</span>' : ''}
            </div>
            <div class="m-date-right">
              ${nonconfCount > 0 ? '<span class="m-issue-type-badge nonconformity">부적합 ' + nonconfCount + '</span>' : ''}
              <span>세션${sessions.length} · ${totalWorkers}명</span>
            </div>
          </div>
          <div class="m-date-content">
      `;

      // 이슈 리마인더
      if (issues.length > 0) {
        html += `
          <div class="m-issue-reminder">
            <div class="m-issue-reminder-header">
              <span>⚠️</span>
              <span>당일 신고 ${issues.length}건</span>
            </div>
            ${issues.slice(0, 3).map(issue => {
              const itemText = issue.issue_item_name || '';
              const desc = issue.additional_description ? (itemText ? itemText + ' - ' + issue.additional_description : issue.additional_description) : itemText;
              return `
                <div class="m-issue-reminder-item">
                  <span class="m-issue-type-badge ${issue.category_type === 'safety' ? 'safety' : 'nonconformity'}">${issue.category_type === 'safety' ? '안전' : '부적합'}</span>
                  <span>${esc(issue.issue_category_name || '')} ${esc(desc || '-')}</span>
                </div>
              `;
            }).join('')}
            ${issues.length > 3 ? '<div style="font-size:0.6875rem;color:#92400e;padding-top:0.25rem;">외 ' + (issues.length - 3) + '건</div>' : ''}
          </div>
        `;
      }

      // 세션별 카드
      sessions.forEach(group => {
        const sessionKey = `${group.session_id}_${dateStr}`;

        html += `
          <div class="m-session-header">
            <span class="m-session-badge">TBM</span>
            <span class="m-session-info">작성자: ${esc(group.created_by_name)} · ${group.items.length}명</span>
          </div>
        `;

        group.items.forEach(tbm => {
          const idx = tbm.originalIndex;
          const defects = state.tempDefects[idx] || [];
          const totalDefectHours = defects.reduce((s, d) => s + (parseFloat(d.defect_hours) || 0), 0);
          const totalHoursVal = document.getElementById('m_totalHours_' + idx)?.value || '';
          const hasRelatedIssue = issues.some(i => {
            if (i.category_type !== 'nonconformity') return false;
            if (tbm.workplace_id && i.workplace_id) return tbm.workplace_id === i.workplace_id;
            return false;
          });

          html += renderWorkerCard(tbm, idx, totalHoursVal, defects, totalDefectHours, hasRelatedIssue);
        });

        // 일괄 제출 버튼
        if (group.items.length > 1) {
          html += `
            <button class="m-batch-btn" onclick="MobileReport.batchSubmitSession('${sessionKey}')">
              이 세션 일괄 제출 (${group.items.length}건)
            </button>
          `;
        }
      });

      html += '</div></div>';
    });

    container.innerHTML = html;
  }

  function getDefaultHours(tbm) {
    // work_hours가 있으면 (분할 배정) 해당 값 우선 사용
    if (tbm.work_hours != null && parseFloat(tbm.work_hours) > 0) {
      return parseFloat(tbm.work_hours);
    }
    switch (tbm.attendance_type) {
      case 'overtime': return 8 + (parseFloat(tbm.attendance_hours) || 0);
      case 'regular':  return 8;
      case 'half':     return 4;
      case 'quarter':  return 6;
      case 'early':    return parseFloat(tbm.attendance_hours) || 0;
      default:         return 0;
    }
  }

  function getAttendanceLabel(type) {
    const labels = { overtime: '연장근무', regular: '정시근로', annual: '연차', half: '반차', quarter: '반반차', early: '조퇴' };
    return labels[type] || '';
  }

  function getAttendanceBadgeColor(type) {
    const colors = { overtime: '#7c3aed', regular: '#2563eb', annual: '#ef4444', half: '#f59e0b', quarter: '#f97316', early: '#6b7280' };
    return colors[type] || '#6b7280';
  }

  function renderWorkerCard(tbm, idx, totalHoursVal, defects, totalDefectHours, hasRelatedIssue) {
    const state = window.DailyWorkReportState;
    const defectCount = defects.filter(d => d.defect_hours > 0).length;
    const defectText = defectCount > 0 ? totalDefectHours + 'h / ' + defectCount + '건' : '없음';

    // 근태 기반 자동 시간 채움
    const defaultHours = tbm.attendance_type ? getDefaultHours(tbm) : 0;
    const effectiveHours = totalHoursVal || (defaultHours > 0 ? String(defaultHours) : '');
    const timeDisplay = effectiveHours ? formatHours(parseFloat(effectiveHours)) : '선택';
    const attendanceBadge = tbm.attendance_type ?
      `<span style="display:inline-block; padding:0.125rem 0.375rem; border-radius:0.25rem; font-size:0.625rem; font-weight:700; color:white; background:${getAttendanceBadgeColor(tbm.attendance_type)}; margin-left:0.375rem;">${getAttendanceLabel(tbm.attendance_type)}</span>` : '';

    return `
      <div class="m-worker-card" data-index="${idx}" data-type="tbm">
        <input type="hidden" id="m_totalHours_${idx}" value="${esc(effectiveHours)}">
        <div class="m-card-top">
          <div>
            <div class="m-worker-name">${esc(tbm.worker_name || '작업자')}${attendanceBadge}</div>
            <div class="m-worker-job">${esc(tbm.job_type || '-')}</div>
          </div>
        </div>
        <div class="m-card-info">
          <div class="m-info-row"><span class="m-info-label">프로젝트</span><span class="m-info-value">${esc(tbm.project_name || '-')}</span></div>
          <div class="m-info-row"><span class="m-info-label">공정/작업</span><span class="m-info-value">${esc(tbm.work_type_name || '-')} / ${esc(tbm.task_name || '-')}</span></div>
          <div class="m-info-row"><span class="m-info-label">작업장소</span><span class="m-info-value">${esc(tbm.category_name || '')} > ${esc(tbm.workplace_name || '-')}</span></div>
        </div>
        <div class="m-card-actions">
          <div class="m-action-btn ${effectiveHours ? 'has-value' : ''}" onclick="MobileReport.openTimePicker(${idx}, 'tbm')">
            <span class="m-action-label">작업시간</span>
            <span class="m-action-value" id="m_timeDisplay_${idx}">${timeDisplay}</span>
          </div>
          <div class="m-action-btn ${defectCount > 0 ? 'has-value' : ''} ${hasRelatedIssue ? 'has-related-issue' : ''}" onclick="MobileReport.openDefectSheet(${idx}, 'tbm')">
            <span class="m-action-label">부적합</span>
            <span class="m-action-value" id="m_defectDisplay_${idx}">${defectText}</span>
          </div>
        </div>
        <button class="m-submit-btn primary" onclick="MobileReport.submitTbmReport(${idx})">제출</button>
      </div>
    `;
  }

  function toggleDateGroup(dateStr) {
    const group = document.querySelector(`.m-date-group[data-date="${dateStr}"]`);
    if (!group) return;
    group.classList.toggle('expanded');
  }

  // ===== 시간 선택 =====
  function openTimePicker(index, type) {
    timePickerValue = 0;
    const overlay = document.getElementById('mTimeOverlay');

    if (type === 'tbm') {
      const existing = document.getElementById('m_totalHours_' + index);
      if (existing && existing.value) timePickerValue = parseFloat(existing.value) || 0;
      document.getElementById('mTimeTitle').textContent = '작업시간 선택';
      timePickerCallback = function(val) {
        const inp = document.getElementById('m_totalHours_' + index);
        if (inp) inp.value = val;
        const disp = document.getElementById('m_timeDisplay_' + index);
        if (disp) {
          disp.textContent = formatHours(val);
          disp.closest('.m-action-btn').classList.toggle('has-value', val > 0);
        }
      };
    } else if (type === 'manual') {
      const existing = document.getElementById('m_manual_hours_' + index);
      if (existing && existing.value) timePickerValue = parseFloat(existing.value) || 0;
      document.getElementById('mTimeTitle').textContent = '작업시간 선택';
      timePickerCallback = function(val) {
        const inp = document.getElementById('m_manual_hours_' + index);
        if (inp) inp.value = val;
        const disp = document.getElementById('m_manual_timeDisplay_' + index);
        if (disp) {
          disp.textContent = formatHours(val);
          disp.closest('.m-action-btn').classList.toggle('has-value', val > 0);
        }
      };
    } else if (type === 'defect') {
      // 부적합 시트 내 시간 선택
      timePickerValue = 0;
      document.getElementById('mTimeTitle').textContent = '부적합 시간 선택';
      timePickerCallback = function(val) {
        // index is defect index within defectSheetTempData
        if (defectSheetTempData[index]) {
          defectSheetTempData[index].defect_hours = val;
          const timeEl = document.getElementById('m_defect_time_' + index);
          if (timeEl) timeEl.textContent = formatHours(val);
        }
      };
    }

    updateTimeDisplay();
    highlightTimeButtons();
    overlay.classList.add('show');
  }

  function setTime(val) {
    timePickerValue = val;
    updateTimeDisplay();
    highlightTimeButtons();
  }

  function adjustTime(delta) {
    timePickerValue = Math.max(0, Math.round((timePickerValue + delta) * 10) / 10);
    updateTimeDisplay();
    highlightTimeButtons();
  }

  function updateTimeDisplay() {
    document.getElementById('mTimeCurrent').textContent = formatHours(timePickerValue) || '0시간';
  }

  function highlightTimeButtons() {
    document.querySelectorAll('.m-time-btn').forEach(btn => {
      btn.classList.remove('selected');
    });
    const quickValues = [0.5, 1, 2, 4, 8];
    const btns = document.querySelectorAll('.m-quick-time-grid .m-time-btn');
    quickValues.forEach((v, i) => {
      if (btns[i] && timePickerValue === v) btns[i].classList.add('selected');
    });
  }

  function confirmTime() {
    if (timePickerCallback) {
      timePickerCallback(timePickerValue);
    }
    closeTimePicker();
  }

  function closeTimePicker() {
    document.getElementById('mTimeOverlay').classList.remove('show');
    timePickerCallback = null;
  }

  // ===== 부적합 바텀시트 =====
  function openDefectSheet(index, type) {
    console.log('[Mobile] openDefectSheet:', index, type);
    defectSheetIndex = index;
    defectSheetType = type;
    const state = window.DailyWorkReportState;

    // 기존 부적합 데이터 복사
    if (type === 'tbm') {
      if (!state.tempDefects[index]) {
        state.tempDefects[index] = [];
      }
      defectSheetTempData = JSON.parse(JSON.stringify(state.tempDefects[index]));
    } else {
      const mcData = manualCards[index];
      if (mcData && mcData.defects) {
        defectSheetTempData = JSON.parse(JSON.stringify(mcData.defects));
      } else {
        defectSheetTempData = [];
      }
    }

    console.log('[Mobile] defectSheetTempData:', defectSheetTempData);
    renderDefectSheetContent();
    showBottomSheet('defect');
  }

  function renderDefectSheetContent() {
    const state = window.DailyWorkReportState;
    const body = document.getElementById('defectSheetBody');
    console.log('[Mobile] renderDefectSheetContent, body:', !!body);
    console.log('[Mobile] issueCategories:', (state.issueCategories || []).length);
    console.log('[Mobile] issueItems:', (state.issueItems || []).length);

    // 당일 신고된 이슈 가져오기
    let relatedIssues = [];
    if (defectSheetType === 'tbm') {
      const tbm = state.incompleteTbms[defectSheetIndex];
      console.log('[Mobile] tbm:', tbm?.worker_name, 'session_date:', tbm?.session_date, 'workplace_id:', tbm?.workplace_id);
      if (tbm) {
        const dateStr = formatDateForApi(tbm.session_date);
        const allIssues = state.dailyIssuesCache[dateStr] || [];
        console.log('[Mobile] allIssues for', dateStr, ':', allIssues.length);
        relatedIssues = allIssues.filter(i => {
          if (i.category_type !== 'nonconformity') return false;
          if (tbm.workplace_id && i.workplace_id) return tbm.workplace_id === i.workplace_id;
          if (tbm.workplace_name && (i.workplace_name || i.custom_location)) {
            const loc = i.workplace_name || i.custom_location || '';
            return loc.includes(tbm.workplace_name) || tbm.workplace_name.includes(loc);
          }
          return false;
        });
      }
    }

    console.log('[Mobile] relatedIssues:', relatedIssues.length);

    let html = '';

    // 신고 기반 이슈 체크
    if (relatedIssues.length > 0) {
      html += '<div style="font-size:0.8125rem;font-weight:600;color:#374151;margin-bottom:0.5rem;">📋 관련 신고</div>';
      relatedIssues.forEach(issue => {
        const existingIdx = defectSheetTempData.findIndex(d => d.issue_report_id == issue.report_id);
        const isSelected = existingIdx >= 0;
        const defectHours = isSelected ? defectSheetTempData[existingIdx].defect_hours : 0;
        const itemText = issue.issue_item_name || '';
        const desc = issue.additional_description ? (itemText ? itemText + ' - ' + issue.additional_description : issue.additional_description) : itemText;

        html += `
          <div class="m-defect-issue-item ${isSelected ? 'selected' : ''}" data-report-id="${issue.report_id}" onclick="MobileReport.toggleDefectIssue(${issue.report_id})">
            <div class="m-defect-checkbox"></div>
            <div class="m-defect-issue-info">
              <div class="m-defect-issue-name">${esc(issue.issue_category_name || '부적합')}</div>
              <div class="m-defect-issue-detail">${esc(desc || '-')} · ${esc(issue.workplace_name || issue.custom_location || '')}</div>
              ${isSelected ? `
                <div class="m-defect-time-input" onclick="event.stopPropagation()">
                  <label>시간:</label>
                  <span id="m_defect_issue_time_${issue.report_id}" style="font-weight:600;color:#2563eb;cursor:pointer;" onclick="MobileReport.openDefectTimePicker(${issue.report_id}, 'issue')">${formatHours(defectHours) || '선택'}</span>
                </div>
              ` : ''}
            </div>
          </div>
        `;
      });
    }

    // 수동 부적합 추가 섹션
    html += '<div class="m-defect-manual-section">';
    html += '<div class="m-defect-manual-title">수동 부적합 추가</div>';

    // 기존 수동 부적합 항목 렌더링
    const manualDefects = defectSheetTempData.filter(d => !d.issue_report_id);
    manualDefects.forEach((defect, i) => {
      const realIdx = defectSheetTempData.indexOf(defect);
      html += renderManualDefectRow(defect, realIdx);
    });

    html += `
      <button class="m-btn-add" style="width:100%;margin-top:0.5rem;background:#f3f4f6;color:#374151;border:1.5px dashed #d1d5db;" onclick="MobileReport.addManualDefect()">+ 부적합 추가</button>
    </div>`;

    body.innerHTML = html;
    console.log('[Mobile] defectSheet rendered, html length:', html.length);
  }

  function renderManualDefectRow(defect, idx) {
    const state = window.DailyWorkReportState;
    const categories = state.issueCategories || [];
    const items = state.issueItems || [];
    const filteredItems = defect.category_id ? items.filter(it => it.category_id == defect.category_id) : [];

    return `
      <div style="border:1.5px solid #e5e7eb;border-radius:10px;padding:0.625rem;margin-bottom:0.5rem;position:relative;">
        <button style="position:absolute;top:0.25rem;right:0.5rem;background:none;border:none;color:#9ca3af;font-size:1.25rem;cursor:pointer;" onclick="MobileReport.removeManualDefect(${idx})">×</button>
        <div class="m-form-group" style="margin-bottom:0.5rem;">
          <label class="m-form-label">카테고리</label>
          <select class="m-form-select" onchange="MobileReport.updateDefectCategory(${idx}, this.value)" style="font-size:16px;">
            <option value="">선택</option>
            ${categories.map(c => `<option value="${c.category_id}" ${defect.category_id == c.category_id ? 'selected' : ''}>${esc(c.category_name)}</option>`).join('')}
          </select>
        </div>
        <div class="m-form-group" style="margin-bottom:0.5rem;">
          <label class="m-form-label">항목</label>
          <select class="m-form-select" id="m_defectItem_${idx}" onchange="MobileReport.updateDefectItem(${idx}, this.value)" style="font-size:16px;">
            <option value="">선택</option>
            ${filteredItems.map(it => `<option value="${it.item_id}" ${defect.item_id == it.item_id ? 'selected' : ''}>${esc(it.item_name)}</option>`).join('')}
          </select>
        </div>
        <div style="display:flex;gap:0.5rem;align-items:center;">
          <span style="font-size:0.75rem;color:#6b7280;">시간:</span>
          <span id="m_defect_time_${idx}" style="font-weight:600;color:#2563eb;cursor:pointer;font-size:0.875rem;" onclick="MobileReport.openDefectTimePicker(${idx}, 'manual')">${formatHours(defect.defect_hours) || '선택'}</span>
        </div>
        <div class="m-form-group" style="margin-top:0.5rem;margin-bottom:0;">
          <input class="m-form-input" placeholder="비고 (선택)" value="${esc(defect.note || '')}" onchange="MobileReport.updateDefectNote(${idx}, this.value)" style="font-size:16px;">
        </div>
      </div>
    `;
  }

  function toggleDefectIssue(reportId) {
    const existingIdx = defectSheetTempData.findIndex(d => d.issue_report_id == reportId);

    if (existingIdx >= 0) {
      // 이미 선택됨 → 해제
      defectSheetTempData.splice(existingIdx, 1);
    } else {
      // 선택 → 추가 (데스크탑과 동일한 구조: 이슈 기반이므로 error_type_id는 null)
      defectSheetTempData.push({
        issue_report_id: reportId,
        error_type_id: null,
        defect_hours: 0,
        note: ''
      });
    }
    renderDefectSheetContent();
  }

  function addManualDefect() {
    defectSheetTempData.push({
      issue_report_id: null,
      category_id: null,
      item_id: null,
      error_type_id: '', // 레거시 호환 (데스크탑과 동일)
      defect_hours: 0,
      note: ''
    });
    renderDefectSheetContent();
  }

  function removeManualDefect(idx) {
    defectSheetTempData.splice(idx, 1);
    renderDefectSheetContent();
  }

  function updateDefectCategory(idx, categoryId) {
    if (defectSheetTempData[idx]) {
      defectSheetTempData[idx].category_id = categoryId ? parseInt(categoryId) : null;
      defectSheetTempData[idx].item_id = null;
      defectSheetTempData[idx].error_type_id = null;
      // 항목 드롭다운 재렌더링
      renderDefectSheetContent();
    }
  }

  function updateDefectItem(idx, itemId) {
    if (defectSheetTempData[idx]) {
      defectSheetTempData[idx].item_id = itemId ? parseInt(itemId) : null;
      defectSheetTempData[idx].error_type_id = itemId ? parseInt(itemId) : null;
    }
  }

  function updateDefectNote(idx, note) {
    if (defectSheetTempData[idx]) {
      defectSheetTempData[idx].note = note;
    }
  }

  function openDefectTimePicker(id, type) {
    if (type === 'issue') {
      // issue_report_id 기반
      const idx = defectSheetTempData.findIndex(d => d.issue_report_id == id);
      if (idx < 0) return;
      timePickerValue = defectSheetTempData[idx].defect_hours || 0;
      timePickerCallback = function(val) {
        defectSheetTempData[idx].defect_hours = val;
        const el = document.getElementById('m_defect_issue_time_' + id);
        if (el) el.textContent = formatHours(val);
      };
    } else {
      // manual index
      timePickerValue = defectSheetTempData[id]?.defect_hours || 0;
      timePickerCallback = function(val) {
        if (defectSheetTempData[id]) {
          defectSheetTempData[id].defect_hours = val;
          const el = document.getElementById('m_defect_time_' + id);
          if (el) el.textContent = formatHours(val);
        }
      };
    }
    updateTimeDisplay();
    highlightTimeButtons();
    document.getElementById('mTimeTitle').textContent = '부적합 시간 선택';
    document.getElementById('mTimeOverlay').classList.add('show');
  }

  function saveDefects() {
    const state = window.DailyWorkReportState;

    // 수동 부적합 유효성 검사: category_id 또는 item_id가 있어야 저장
    const manualDefects = defectSheetTempData.filter(d => !d.issue_report_id);
    const invalidManual = manualDefects.filter(d => d.defect_hours > 0 && !d.category_id && !d.item_id);
    if (invalidManual.length > 0) {
      showToast('부적합 카테고리/항목을 선택해주세요', 'error');
      return;
    }

    // _saved 플래그 설정 (데스크탑 호환)
    defectSheetTempData.forEach(d => { d._saved = true; });

    if (defectSheetType === 'tbm') {
      state.tempDefects[defectSheetIndex] = defectSheetTempData;
      // 카드 UI 업데이트
      const defects = defectSheetTempData;
      const totalDefectHours = defects.reduce((s, d) => s + (parseFloat(d.defect_hours) || 0), 0);
      const defectCount = defects.filter(d => d.defect_hours > 0).length;
      const defectText = defectCount > 0 ? totalDefectHours + 'h / ' + defectCount + '건' : '없음';
      const disp = document.getElementById('m_defectDisplay_' + defectSheetIndex);
      if (disp) {
        disp.textContent = defectText;
        disp.closest('.m-action-btn').classList.toggle('has-value', defectCount > 0);
      }
    } else if (defectSheetType === 'manual') {
      if (manualCards[defectSheetIndex]) {
        manualCards[defectSheetIndex].defects = defectSheetTempData;
        // UI 업데이트
        const defects = defectSheetTempData;
        const totalDefectHours = defects.reduce((s, d) => s + (parseFloat(d.defect_hours) || 0), 0);
        const defectCount = defects.filter(d => d.defect_hours > 0).length;
        const defectText = defectCount > 0 ? totalDefectHours + 'h / ' + defectCount + '건' : '없음';
        const disp = document.getElementById('m_manual_defectDisplay_' + defectSheetIndex);
        if (disp) {
          disp.textContent = defectText;
          disp.closest('.m-action-btn').classList.toggle('has-value', defectCount > 0);
        }
      }
    }

    hideDefectSheet();
    showToast('부적합 정보가 저장되었습니다', 'success');
  }

  function hideDefectSheet() {
    hideBottomSheet('defect');
    defectSheetIndex = null;
    defectSheetType = null;
  }

  // ===== 제출 =====
  async function submitTbmReport(index) {
    const state = window.DailyWorkReportState;
    const tbm = state.incompleteTbms[index];
    if (!tbm) return;

    const totalHours = parseFloat(document.getElementById('m_totalHours_' + index)?.value);
    const defects = state.tempDefects[index] || [];
    const errorHours = defects.reduce((sum, d) => sum + (parseFloat(d.defect_hours) || 0), 0);
    const errorTypeId = defects.length > 0 ? (defects[0].error_type_id || defects[0].item_id || null) : null;

    // 검증
    if (!totalHours || totalHours <= 0) {
      showToast('작업시간을 선택해주세요', 'error');
      return;
    }
    if (errorHours > totalHours) {
      showToast('부적합 시간이 총 작업시간을 초과합니다', 'error');
      return;
    }

    const invalidDefects = defects.filter(d => d.defect_hours > 0 && !d.error_type_id && !d.issue_report_id && !d.category_id && !d.item_id);
    if (invalidDefects.length > 0) {
      showToast('부적합 원인을 선택해주세요', 'error');
      return;
    }

    const reportDate = typeof tbm.session_date === 'string' && tbm.session_date.includes('T')
      ? tbm.session_date.split('T')[0]
      : (tbm.session_date instanceof Date ? formatDateForApi(tbm.session_date) : tbm.session_date);

    const reportData = {
      tbm_assignment_id: tbm.assignment_id,
      tbm_session_id: tbm.session_id,
      user_id: tbm.user_id,
      project_id: tbm.project_id,
      work_type_id: tbm.task_id,
      report_date: reportDate,
      start_time: null,
      end_time: null,
      total_hours: totalHours,
      error_hours: errorHours,
      error_type_id: errorTypeId,
      work_status_id: errorHours > 0 ? 2 : 1
    };

    // 제출 버튼 비활성화
    const card = document.querySelector(`.m-worker-card[data-index="${index}"]`);
    const btn = card?.querySelector('.m-submit-btn');
    if (btn) { btn.disabled = true; btn.textContent = '제출 중...'; }

    try {
      const response = await window.apiCall('/daily-work-reports/from-tbm', 'POST', reportData);
      if (!response.success) throw new Error(response.message || '제출 실패');

      // 부적합 원인 저장
      if (defects.length > 0 && response.data?.report_id) {
        const validDefects = defects.filter(d => (d.issue_report_id || d.category_id || d.item_id || d.error_type_id) && d.defect_hours > 0);
        if (validDefects.length > 0) {
          const defectsToSend = validDefects.map(d => ({
            issue_report_id: d.issue_report_id || null,
            category_id: d.category_id || null,
            item_id: d.item_id || null,
            error_type_id: d.error_type_id || null,
            defect_hours: d.defect_hours,
            note: d.note || ''
          }));
          await window.apiCall(`/daily-work-reports/${response.data.report_id}/defects`, 'PUT', { defects: defectsToSend });
        }
      }

      // 임시 데이터 삭제
      delete state.tempDefects[index];

      showResult('success', '제출 완료', `${tbm.worker_name}의 작업보고서가 제출되었습니다.`,
        response.data.tbm_completed ? '모든 팀원의 작업보고서가 제출되어 TBM이 완료되었습니다.' : response.data.completion_status
      );

      // 목록 새로고침
      await refreshTbmList();
    } catch (error) {
      console.error('[Mobile] TBM 제출 오류:', error);
      showResult('error', '제출 실패', error.message);
      if (btn) { btn.disabled = false; btn.textContent = '제출'; }
    }
  }

  async function batchSubmitSession(sessionKey) {
    const state = window.DailyWorkReportState;
    const cards = document.querySelectorAll(`.m-worker-card[data-type="tbm"]`);

    // 세션에 해당하는 카드 찾기
    const tbms = state.incompleteTbms || [];
    const byDate = {};
    tbms.forEach((tbm, index) => {
      const dateStr = formatDateForApi(tbm.session_date);
      const key = `${tbm.session_id}_${dateStr}`;
      if (!byDate[key]) byDate[key] = [];
      byDate[key].push({ tbm, index });
    });

    const sessionItems = byDate[sessionKey];
    if (!sessionItems || sessionItems.length === 0) {
      showToast('제출할 항목이 없습니다', 'error');
      return;
    }

    // 검증
    const errors = [];
    const itemsToSubmit = [];

    sessionItems.forEach(({ tbm, index }) => {
      const totalHours = parseFloat(document.getElementById('m_totalHours_' + index)?.value);
      const defects = state.tempDefects[index] || [];
      const errorHours = defects.reduce((s, d) => s + (parseFloat(d.defect_hours) || 0), 0);
      const errorTypeId = defects.length > 0 ? (defects[0].error_type_id || defects[0].item_id || null) : null;

      if (!totalHours || totalHours <= 0) {
        errors.push(`${tbm.worker_name}: 작업시간 미입력`);
        return;
      }
      if (errorHours > totalHours) {
        errors.push(`${tbm.worker_name}: 부적합 시간 초과`);
        return;
      }

      const reportDate = typeof tbm.session_date === 'string' && tbm.session_date.includes('T')
        ? tbm.session_date.split('T')[0]
        : (tbm.session_date instanceof Date ? formatDateForApi(tbm.session_date) : tbm.session_date);

      itemsToSubmit.push({
        index,
        tbm,
        defects,
        data: {
          tbm_assignment_id: tbm.assignment_id,
          tbm_session_id: tbm.session_id,
          user_id: tbm.user_id,
          project_id: tbm.project_id,
          work_type_id: tbm.task_id,
          report_date: reportDate,
          start_time: null,
          end_time: null,
          total_hours: totalHours,
          error_hours: errorHours,
          error_type_id: errorTypeId,
          work_status_id: errorHours > 0 ? 2 : 1
        }
      });
    });

    if (errors.length > 0) {
      showResult('error', '일괄제출 검증 실패', '모든 항목이 유효해야 제출할 수 있습니다.', errors);
      return;
    }

    showMessage('일괄 제출 중...', 'loading');
    const results = { success: [], failed: [] };

    for (const item of itemsToSubmit) {
      try {
        const response = await window.apiCall('/daily-work-reports/from-tbm', 'POST', item.data);
        if (response.success) {
          // 부적합 저장
          if (item.defects.length > 0 && response.data?.report_id) {
            const validDefects = item.defects.filter(d => (d.issue_report_id || d.category_id || d.item_id || d.error_type_id) && d.defect_hours > 0);
            if (validDefects.length > 0) {
              const defectsToSend = validDefects.map(d => ({
                issue_report_id: d.issue_report_id || null,
                category_id: d.category_id || null,
                item_id: d.item_id || null,
                error_type_id: d.error_type_id || null,
                defect_hours: d.defect_hours,
                note: d.note || ''
              }));
              await window.apiCall(`/daily-work-reports/${response.data.report_id}/defects`, 'PUT', { defects: defectsToSend });
            }
          }
          delete state.tempDefects[item.index];
          results.success.push(item.tbm.worker_name);
        } else {
          results.failed.push(`${item.tbm.worker_name}: ${response.message}`);
        }
      } catch (error) {
        results.failed.push(`${item.tbm.worker_name}: ${error.message}`);
      }
    }

    hideMessage();

    if (results.failed.length === 0) {
      showResult('success', '일괄제출 완료', `${itemsToSubmit.length}건 모두 성공`, results.success.map(n => '✓ ' + n));
    } else if (results.success.length === 0) {
      showResult('error', '일괄제출 실패', `${itemsToSubmit.length}건 모두 실패`, results.failed);
    } else {
      showResult('warning', '일괄제출 부분 완료', `성공 ${results.success.length}건 / 실패 ${results.failed.length}건`,
        [...results.success.map(n => '✓ ' + n), ...results.failed.map(m => '✗ ' + m)]
      );
    }

    await refreshTbmList();
  }

  async function refreshTbmList() {
    const api = window.DailyWorkReportAPI;
    await api.loadIncompleteTbms();
    await api.loadDailyIssuesForTbms();
    renderTbmCards();
  }

  // ===== 수동 입력 =====
  function addManualCard() {
    const id = 'mc_' + (manualCounter++);
    const state = window.DailyWorkReportState;

    manualCards[id] = {
      user_id: null,
      report_date: getKoreaToday(),
      project_id: null,
      work_type_id: null,
      task_id: null,
      workplace_category_id: null,
      workplace_id: null,
      workplace_name: null,
      workplace_category_name: null,
      total_hours: 0,
      defects: []
    };

    const container = document.getElementById('manualCardList');
    // 빈 상태 메시지 제거
    const empty = container.querySelector('.m-empty');
    if (empty) empty.remove();

    const cardEl = document.createElement('div');
    cardEl.className = 'm-manual-card';
    cardEl.id = 'm_manual_card_' + id;
    cardEl.setAttribute('data-manual-id', id);
    cardEl.style.position = 'relative';

    const workers = state.workers || [];
    const projects = state.projects || [];
    const workTypes = state.workTypes || [];

    cardEl.innerHTML = `
      <button class="m-manual-delete" onclick="MobileReport.removeManualCard('${id}')">&times;</button>
      <div class="m-form-group">
        <label class="m-form-label">작업자</label>
        <select class="m-form-select" id="m_manual_worker_${id}" onchange="MobileReport.updateManualField('${id}','user_id',this.value)">
          <option value="">작업자 선택</option>
          ${workers.map(w => `<option value="${w.user_id}">${esc(w.worker_name)} (${esc(w.job_type || '-')})</option>`).join('')}
        </select>
      </div>
      <div class="m-form-row">
        <div class="m-form-group">
          <label class="m-form-label">날짜</label>
          <input type="date" class="m-form-input" id="m_manual_date_${id}" value="${getKoreaToday()}" onchange="MobileReport.updateManualField('${id}','report_date',this.value)">
        </div>
        <div class="m-form-group">
          <label class="m-form-label">프로젝트</label>
          <select class="m-form-select" id="m_manual_project_${id}" onchange="MobileReport.updateManualField('${id}','project_id',this.value)">
            <option value="">선택</option>
            ${projects.map(p => `<option value="${p.project_id}">${esc(p.project_name)}</option>`).join('')}
          </select>
        </div>
      </div>
      <div class="m-form-row">
        <div class="m-form-group">
          <label class="m-form-label">공정</label>
          <select class="m-form-select" id="m_manual_workType_${id}" onchange="MobileReport.onWorkTypeChange('${id}', this.value)">
            <option value="">선택</option>
            ${workTypes.map(wt => `<option value="${wt.id}">${esc(wt.name)}</option>`).join('')}
          </select>
        </div>
        <div class="m-form-group">
          <label class="m-form-label">작업</label>
          <select class="m-form-select" id="m_manual_task_${id}" disabled>
            <option value="">공정 먼저 선택</option>
          </select>
        </div>
      </div>
      <div class="m-form-group">
        <label class="m-form-label">작업장소</label>
        <div class="m-workplace-box" id="m_manual_wpBox_${id}" onclick="MobileReport.openWorkplaceSheet('${id}')">
          <span class="m-wp-icon">📍</span>
          <span class="m-wp-text" id="m_manual_wpText_${id}">클릭하여 선택</span>
        </div>
      </div>
      <div class="m-card-actions">
        <div class="m-action-btn" onclick="MobileReport.openTimePicker('${id}', 'manual')">
          <span class="m-action-label">작업시간</span>
          <span class="m-action-value" id="m_manual_timeDisplay_${id}">선택</span>
          <input type="hidden" id="m_manual_hours_${id}" value="">
        </div>
        <div class="m-action-btn" onclick="MobileReport.openDefectSheet('${id}', 'manual')">
          <span class="m-action-label">부적합</span>
          <span class="m-action-value" id="m_manual_defectDisplay_${id}">없음</span>
        </div>
      </div>
      <button class="m-submit-btn primary" onclick="MobileReport.submitManualReport('${id}')">제출</button>
    `;

    container.appendChild(cardEl);

    // 수동 입력 탭으로 이동
    if (currentTab !== 'manual') {
      switchTab('manual');
    }
  }

  function removeManualCard(id) {
    const card = document.getElementById('m_manual_card_' + id);
    if (card) card.remove();
    delete manualCards[id];

    // 카드가 모두 없으면 빈 상태 표시
    if (Object.keys(manualCards).length === 0) {
      document.getElementById('manualCardList').innerHTML = `
        <div class="m-empty">
          <div class="m-empty-icon">📝</div>
          <div>수동으로 작업보고서를 추가하세요</div>
          <button class="m-btn-add" style="margin-top:0.75rem;" onclick="MobileReport.addManualCard()">+ 수동추가</button>
        </div>
      `;
    }
  }

  function updateManualField(id, field, value) {
    if (manualCards[id]) {
      manualCards[id][field] = value;
    }
  }

  async function onWorkTypeChange(id, workTypeId) {
    updateManualField(id, 'work_type_id', workTypeId);
    updateManualField(id, 'task_id', null);

    const taskSelect = document.getElementById('m_manual_task_' + id);
    if (!workTypeId) {
      taskSelect.disabled = true;
      taskSelect.innerHTML = '<option value="">공정 먼저 선택</option>';
      return;
    }

    try {
      const response = await window.apiCall(`/tasks?work_type_id=${workTypeId}`);
      const tasks = response.success ? response.data : (Array.isArray(response) ? response : []);

      if (tasks && tasks.length > 0) {
        taskSelect.disabled = false;
        taskSelect.innerHTML = '<option value="">선택</option>' +
          tasks.map(t => `<option value="${t.task_id}">${esc(t.task_name)}</option>`).join('');
        taskSelect.onchange = function() {
          updateManualField(id, 'task_id', this.value);
        };
      } else {
        taskSelect.disabled = true;
        taskSelect.innerHTML = '<option value="">등록된 작업 없음</option>';
      }
    } catch (error) {
      taskSelect.disabled = true;
      taskSelect.innerHTML = '<option value="">로드 실패</option>';
    }
  }

  async function submitManualReport(id) {
    const mc = manualCards[id];
    if (!mc) return;

    const workerId = mc.user_id || document.getElementById('m_manual_worker_' + id)?.value;
    const reportDate = mc.report_date || document.getElementById('m_manual_date_' + id)?.value;
    const projectId = mc.project_id || document.getElementById('m_manual_project_' + id)?.value;
    const taskId = mc.task_id || document.getElementById('m_manual_task_' + id)?.value;
    const totalHours = parseFloat(document.getElementById('m_manual_hours_' + id)?.value);
    const workplaceId = mc.workplace_id;
    const defects = mc.defects || [];
    const errorHours = defects.reduce((s, d) => s + (parseFloat(d.defect_hours) || 0), 0);
    const errorTypeId = defects.length > 0 ? (defects[0].error_type_id || defects[0].item_id || null) : null;

    // 검증
    if (!workerId) { showToast('작업자를 선택해주세요', 'error'); return; }
    if (!reportDate) { showToast('날짜를 입력해주세요', 'error'); return; }
    if (!projectId) { showToast('프로젝트를 선택해주세요', 'error'); return; }
    if (!taskId) { showToast('작업을 선택해주세요', 'error'); return; }
    if (workplaceId === null || workplaceId === undefined) { showToast('작업장소를 선택해주세요', 'error'); return; }
    if (!totalHours || totalHours <= 0) { showToast('작업시간을 선택해주세요', 'error'); return; }
    if (errorHours > totalHours) { showToast('부적합 시간이 초과합니다', 'error'); return; }

    const reportData = {
      report_date: reportDate,
      user_id: parseInt(workerId),
      work_entries: [{
        project_id: parseInt(projectId),
        task_id: parseInt(taskId),
        work_hours: totalHours,
        work_status_id: errorHours > 0 ? 2 : 1,
        error_type_id: errorTypeId ? parseInt(errorTypeId) : null
      }]
    };

    const btn = document.querySelector(`#m_manual_card_${id} .m-submit-btn`);
    if (btn) { btn.disabled = true; btn.textContent = '제출 중...'; }

    try {
      let response;
      let retries = 3;
      for (let i = 0; i < retries; i++) {
        try {
          response = await window.apiCall('/daily-work-reports', 'POST', reportData);
          break;
        } catch (err) {
          if ((err.message?.includes('429') || err.message?.includes('너무 많은 요청')) && i < retries - 1) {
            await new Promise(r => setTimeout(r, (i + 1) * 2000));
            continue;
          }
          throw err;
        }
      }

      if (!response.success) throw new Error(response.message || '제출 실패');

      // 부적합 저장
      const reportId = response.data?.inserted_ids?.[0] || response.data?.workReport_ids?.[0];
      if (defects.length > 0 && reportId) {
        const validDefects = defects.filter(d => (d.issue_report_id || d.category_id || d.item_id || d.error_type_id) && d.defect_hours > 0);
        if (validDefects.length > 0) {
          await window.apiCall(`/daily-work-reports/${reportId}/defects`, 'PUT', { defects: validDefects });
        }
      }

      removeManualCard(id);
      showToast('작업보고서가 제출되었습니다', 'success');
    } catch (error) {
      console.error('[Mobile] 수동 제출 오류:', error);
      showToast('제출 실패: ' + error.message, 'error');
      if (btn) { btn.disabled = false; btn.textContent = '제출'; }
    }
  }

  // ===== 작업장소 바텀시트 =====
  function openWorkplaceSheet(manualId) {
    wpSheetManualId = manualId;
    wpSheetStep = 'category';
    wpSelectedCategory = null;
    wpSelectedCategoryName = null;
    wpSelectedId = null;
    wpSelectedName = null;

    renderWorkplaceCategories();
    showBottomSheet('wp');
  }

  async function renderWorkplaceCategories() {
    const body = document.getElementById('wpSheetBody');
    document.getElementById('wpSheetTitle').textContent = '작업장소 선택';
    body.innerHTML = '<div class="m-loading"></div>';

    try {
      const response = await window.apiCall('/workplaces/categories');
      const categories = response.success ? response.data : response;

      let html = '<div class="m-wp-category-grid">';
      categories.forEach(cat => {
        html += `<button class="m-wp-category-btn" onclick="MobileReport.selectWpCategory(${cat.category_id}, '${esc(cat.category_name)}')">🏭 ${esc(cat.category_name)}</button>`;
      });
      html += `<button class="m-wp-category-btn" onclick="MobileReport.selectExternalWp()" style="border-color:#0ea5e9;background:#f0f9ff;">🌐 외부</button>`;
      html += '</div>';

      body.innerHTML = html;
    } catch (error) {
      body.innerHTML = '<div class="m-empty">작업장소 로드 실패</div>';
    }
  }

  async function selectWpCategory(categoryId, categoryName) {
    wpSelectedCategory = categoryId;
    wpSelectedCategoryName = categoryName;
    wpSheetStep = 'list';

    document.getElementById('wpSheetTitle').textContent = categoryName;
    const body = document.getElementById('wpSheetBody');
    body.innerHTML = '<div class="m-loading"></div>';

    try {
      const response = await window.apiCall(`/workplaces?category_id=${categoryId}`);
      const workplaces = response.success ? response.data : response;

      let html = `<button style="display:flex;align-items:center;gap:0.375rem;font-size:0.8125rem;color:#6b7280;background:none;border:none;cursor:pointer;padding:0.375rem 0;margin-bottom:0.5rem;" onclick="MobileReport.renderWorkplaceCategories()">← 뒤로</button>`;
      html += '<div class="m-wp-list">';
      workplaces.forEach(wp => {
        html += `
          <div class="m-wp-item" onclick="MobileReport.selectWpItem(${wp.workplace_id}, '${esc(wp.workplace_name)}')">
            <span class="m-wp-item-icon">📍</span>
            <span class="m-wp-item-name">${esc(wp.workplace_name)}</span>
          </div>
        `;
      });
      html += '</div>';

      body.innerHTML = html;
    } catch (error) {
      body.innerHTML = '<div class="m-empty">작업장소 로드 실패</div>';
    }
  }

  function selectWpItem(workplaceId, workplaceName) {
    wpSelectedId = workplaceId;
    wpSelectedName = workplaceName;

    // 수동 카드에 반영
    if (manualCards[wpSheetManualId]) {
      manualCards[wpSheetManualId].workplace_id = workplaceId;
      manualCards[wpSheetManualId].workplace_name = workplaceName;
      manualCards[wpSheetManualId].workplace_category_id = wpSelectedCategory;
      manualCards[wpSheetManualId].workplace_category_name = wpSelectedCategoryName;
    }

    const textEl = document.getElementById('m_manual_wpText_' + wpSheetManualId);
    const boxEl = document.getElementById('m_manual_wpBox_' + wpSheetManualId);
    if (textEl) textEl.textContent = `${wpSelectedCategoryName} > ${workplaceName}`;
    if (boxEl) boxEl.classList.add('selected');

    hideWorkplaceSheet();
    showToast('작업장소 선택됨', 'success');
  }

  function selectExternalWp() {
    if (manualCards[wpSheetManualId]) {
      manualCards[wpSheetManualId].workplace_id = 0;
      manualCards[wpSheetManualId].workplace_name = '외부 (외근/연차/휴무)';
      manualCards[wpSheetManualId].workplace_category_id = 0;
      manualCards[wpSheetManualId].workplace_category_name = '외부';
    }

    const textEl = document.getElementById('m_manual_wpText_' + wpSheetManualId);
    const boxEl = document.getElementById('m_manual_wpBox_' + wpSheetManualId);
    if (textEl) textEl.textContent = '🌐 외부 (외근/연차/휴무)';
    if (boxEl) boxEl.classList.add('selected');

    hideWorkplaceSheet();
    showToast('외부 작업장소 선택됨', 'success');
  }

  function hideWorkplaceSheet() {
    hideBottomSheet('wp');
  }

  // ===== 완료 보고서 =====
  async function loadCompletedReports() {
    const dateInput = document.getElementById('completedDate');
    const selectedDate = dateInput?.value;
    if (!selectedDate) return;

    const container = document.getElementById('completedCardList');
    container.innerHTML = '<div class="m-loading"></div>';

    try {
      const response = await window.apiCall(`/daily-work-reports?date=${selectedDate}`);
      let reports = [];
      if (Array.isArray(response)) {
        reports = response;
      } else if (response.success && response.data) {
        reports = Array.isArray(response.data) ? response.data : [];
      } else if (response.data) {
        reports = Array.isArray(response.data) ? response.data : [];
      }

      renderCompletedCards(reports);
    } catch (error) {
      console.error('[Mobile] 완료 보고서 로드 오류:', error);
      container.innerHTML = '<div class="m-empty"><div class="m-empty-icon">⚠️</div><div>보고서를 불러올 수 없습니다</div></div>';
    }
  }

  function renderCompletedCards(reports) {
    const container = document.getElementById('completedCardList');

    if (!reports || reports.length === 0) {
      container.innerHTML = '<div class="m-empty"><div class="m-empty-icon">📋</div><div>작성된 보고서가 없습니다</div></div>';
      return;
    }

    let html = '';
    reports.forEach(report => {
      const totalHours = parseFloat(report.total_hours || report.work_hours || 0);
      const errorHours = parseFloat(report.error_hours || 0);

      html += `
        <div class="m-completed-card">
          <div class="m-completed-top">
            <div>
              <div class="m-completed-worker">${esc(report.worker_name || '작업자')}</div>
              <span class="m-completed-badge ${report.tbm_session_id ? 'tbm' : 'manual'}">${report.tbm_session_id ? 'TBM' : '수동'}</span>
            </div>
          </div>
          <div class="m-completed-info">
            <div class="m-info-row"><span class="m-info-label">프로젝트</span><span class="m-info-value">${esc(report.project_name || '-')}</span></div>
            <div class="m-info-row"><span class="m-info-label">공정/작업</span><span class="m-info-value">${esc(report.work_type_name || '-')} / ${esc(report.task_name || '-')}</span></div>
            <div class="m-info-row"><span class="m-info-label">작업시간</span><span class="m-info-value">${totalHours}시간</span></div>
            ${errorHours > 0 ? `<div class="m-info-row"><span class="m-info-label">부적합</span><span class="m-info-value" style="color:#dc2626;">${errorHours}시간 (${esc(report.error_type_name || '-')})</span></div>` : ''}
            <div class="m-info-row"><span class="m-info-label">작성자</span><span class="m-info-value">${esc(report.created_by_name || '-')}</span></div>
          </div>
          <div class="m-completed-actions">
            <button class="m-btn-edit" onclick='MobileReport.openEditSheet(${JSON.stringify(report).replace(/'/g, "&#39;")})'>수정</button>
            <button class="m-btn-delete" onclick="MobileReport.deleteReport(${report.id})">삭제</button>
          </div>
        </div>
      `;
    });

    container.innerHTML = html;
  }

  // ===== 수정 바텀시트 =====
  function openEditSheet(report) {
    editReportId = report.id;
    const state = window.DailyWorkReportState;
    const projects = state.projects || [];
    const workTypes = state.workTypes || [];
    const workStatusTypes = state.workStatusTypes || [];

    const body = document.getElementById('editSheetBody');
    body.innerHTML = `
      <div class="m-form-group">
        <label class="m-form-label">작업자</label>
        <input class="m-form-input" value="${esc(report.worker_name || '작업자')}" readonly style="background:#f3f4f6;">
      </div>
      <div class="m-form-group">
        <label class="m-form-label">프로젝트</label>
        <select class="m-form-select" id="m_edit_project">
          ${projects.map(p => `<option value="${p.project_id}" ${p.project_id == report.project_id ? 'selected' : ''}>${esc(p.project_name)}</option>`).join('')}
        </select>
      </div>
      <div class="m-form-group">
        <label class="m-form-label">공정</label>
        <select class="m-form-select" id="m_edit_workType" onchange="MobileReport.loadEditTasks()">
          ${workTypes.map(wt => `<option value="${wt.id}">${esc(wt.name)}</option>`).join('')}
        </select>
      </div>
      <div class="m-form-group">
        <label class="m-form-label">작업</label>
        <select class="m-form-select" id="m_edit_task">
          <option value="">로딩중...</option>
        </select>
      </div>
      <div class="m-form-group">
        <label class="m-form-label">작업시간 (시간)</label>
        <input type="number" class="m-form-input" id="m_edit_hours" step="0.5" min="0" max="24" value="${parseFloat(report.work_hours || report.total_hours || 0)}">
      </div>
      <div class="m-form-group">
        <label class="m-form-label">작업상태</label>
        <select class="m-form-select" id="m_edit_status">
          ${workStatusTypes.map(ws => `<option value="${ws.id}" ${ws.id == report.work_status_id ? 'selected' : ''}>${esc(ws.name)}</option>`).join('')}
        </select>
      </div>
    `;

    // 작업 목록 로드 후 현재 값 설정
    loadEditTasks().then(() => {
      const taskSelect = document.getElementById('m_edit_task');
      if (report.work_type_id && taskSelect) {
        taskSelect.value = report.work_type_id;
      }
    });

    showBottomSheet('edit');
  }

  async function loadEditTasks() {
    const workTypeId = document.getElementById('m_edit_workType')?.value;
    const taskSelect = document.getElementById('m_edit_task');
    if (!workTypeId || !taskSelect) return;

    try {
      const response = await window.apiCall(`/tasks?work_type_id=${workTypeId}`);
      const tasks = response.data || response || [];
      taskSelect.innerHTML = '<option value="">선택</option>' +
        tasks.map(t => `<option value="${t.task_id}">${esc(t.task_name)}</option>`).join('');
    } catch (error) {
      taskSelect.innerHTML = '<option value="">로드 실패</option>';
    }
  }

  async function saveEditedReport() {
    const projectId = document.getElementById('m_edit_project')?.value;
    const taskId = document.getElementById('m_edit_task')?.value;
    const workHours = parseFloat(document.getElementById('m_edit_hours')?.value);
    const workStatusId = document.getElementById('m_edit_status')?.value;

    if (!projectId || !taskId || !workHours) {
      showToast('필수 항목을 입력해주세요', 'error');
      return;
    }

    try {
      const response = await window.apiCall(`/daily-work-reports/${editReportId}`, 'PUT', {
        project_id: parseInt(projectId),
        work_type_id: parseInt(taskId),
        work_hours: workHours,
        work_status_id: parseInt(workStatusId)
      });

      if (response.success) {
        hideEditSheet();
        showToast('수정 완료', 'success');
        loadCompletedReports();
      } else {
        throw new Error(response.message || '수정 실패');
      }
    } catch (error) {
      showToast('수정 실패: ' + error.message, 'error');
    }
  }

  function hideEditSheet() {
    hideBottomSheet('edit');
    editReportId = null;
  }

  // ===== 삭제 =====
  function deleteReport(reportId) {
    showConfirm('이 작업보고서를 삭제하시겠습니까?', async () => {
      try {
        const response = await window.apiCall(`/daily-work-reports/${reportId}`, 'DELETE');
        if (response.success) {
          showToast('삭제 완료', 'success');
          loadCompletedReports();
        } else {
          throw new Error(response.message || '삭제 실패');
        }
      } catch (error) {
        showToast('삭제 실패: ' + error.message, 'error');
      }
    }, true);
  }

  // ===== 바텀시트 공통 =====
  function showBottomSheet(id) {
    const sheetMap = { defect: 'defectSheet', wp: 'wpSheet', edit: 'editSheet' };
    const overlayMap = { defect: 'defectOverlay', wp: 'wpOverlay', edit: 'editOverlay' };

    const sheet = document.getElementById(sheetMap[id]);
    const overlay = document.getElementById(overlayMap[id]);

    if (overlay) overlay.classList.add('show');
    if (sheet) {
      sheet.classList.add('show');
      // body 스크롤 방지
      document.body.style.overflow = 'hidden';
    }
  }

  function hideBottomSheet(id) {
    const sheetMap = { defect: 'defectSheet', wp: 'wpSheet', edit: 'editSheet' };
    const overlayMap = { defect: 'defectOverlay', wp: 'wpOverlay', edit: 'editOverlay' };

    const sheet = document.getElementById(sheetMap[id]);
    const overlay = document.getElementById(overlayMap[id]);

    if (overlay) overlay.classList.remove('show');
    if (sheet) sheet.classList.remove('show');
    document.body.style.overflow = '';
  }

  // ===== DOM Ready =====
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => { setTimeout(init, 100); });
  } else {
    setTimeout(init, 100);
  }

  // ===== Public API =====
  return {
    switchTab,
    toggleDateGroup,
    openTimePicker,
    setTime,
    adjustTime,
    confirmTime,
    closeTimePicker,
    openDefectSheet,
    toggleDefectIssue,
    addManualDefect,
    removeManualDefect,
    updateDefectCategory,
    updateDefectItem,
    updateDefectNote,
    openDefectTimePicker,
    saveDefects,
    hideDefectSheet,
    submitTbmReport,
    batchSubmitSession,
    addManualCard,
    removeManualCard,
    updateManualField,
    onWorkTypeChange,
    submitManualReport,
    openWorkplaceSheet,
    renderWorkplaceCategories,
    selectWpCategory,
    selectWpItem,
    selectExternalWp,
    hideWorkplaceSheet,
    loadCompletedReports,
    openEditSheet,
    loadEditTasks,
    saveEditedReport,
    hideEditSheet,
    deleteReport,
    closeResult,
    showToast
  };

})();
