@extends('layouts.app')

@section('title', $isCreate ? '문서양식 등록' : '문서양식 편집')

@push('styles')
<style>
    /* number input 스피너 숨김 */
    input[type=number]::-webkit-inner-spin-button,
    input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
    input[type=number] { -moz-appearance: textfield; }
</style>
@endpush

@section('content')
<div class="max-w-7xl mx-auto">
    <!-- 헤더 -->
    <div class="flex flex-col lg:flex-row lg:justify-between lg:items-center gap-4 mb-6">
        <div>
            <h1 class="text-2xl font-bold text-gray-800">
                {{ $isCreate ? '문서양식 등록' : '문서양식 편집' }}
            </h1>
            <p class="text-sm text-gray-500 mt-1">
                검사 성적서, 작업지시서 등의 문서 양식을 설정합니다.
            </p>
        </div>
        <div class="flex items-center gap-2">
            <button type="button" onclick="openPreviewModal()" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg transition flex items-center gap-2">
                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
                </svg>
                미리보기
            </button>
            <a href="{{ route('document-templates.index') }}" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg transition">
                목록
            </a>
            <button type="button" onclick="saveTemplate()" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition flex items-center gap-2">
                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
                </svg>
                저장
            </button>
        </div>
    </div>

    <!-- 탭 네비게이션 -->
    <div class="mb-6 border-b border-gray-200 bg-white rounded-t-lg">
        <nav class="-mb-px flex">
            <button onclick="switchTab('basic')" id="tab-basic"
                    class="tab-btn px-6 py-4 text-sm font-medium border-b-2 border-blue-500 text-blue-600">
                기본정보
            </button>
            <button onclick="switchTab('basic-fields')" id="tab-basic-fields"
                    class="tab-btn px-6 py-4 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-700">
                기본필드
            </button>
            <button onclick="switchTab('sections')" id="tab-sections"
                    class="tab-btn px-6 py-4 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-700">
                검사 기준서
            </button>
            <button onclick="switchTab('columns')" id="tab-columns"
                    class="tab-btn px-6 py-4 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-700">
                테이블 컬럼
            </button>
        </nav>
    </div>

    <!-- 기본정보 + 결재라인 탭 -->
    <div id="content-basic" class="tab-content bg-white rounded-lg shadow-sm p-6">
        <!-- Row 1: 양식명 + 문서제목 + 분류 + 회사명 (4:4:1:1) -->
        <div class="grid gap-3 mb-4 items-end" style="grid-template-columns:4fr 4fr 1fr 1fr">
            <div>
                <label class="block text-xs font-medium text-gray-500 mb-1">양식명 <span class="text-red-500">*</span></label>
                <input type="text" id="name" placeholder="예: 최종검사 성적서"
                       class="w-full px-3 py-1.5 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
            </div>
            <div>
                <label class="block text-xs font-medium text-gray-500 mb-1">문서 제목</label>
                <input type="text" id="title" placeholder="예: 최종 검사 성적서"
                       class="w-full px-3 py-1.5 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
            </div>
            <div>
                <label class="block text-xs font-medium text-gray-500 mb-1">분류</label>
                <select id="category" onchange="onCategoryChange(this.value)"
                        class="w-full px-2 py-1.5 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
                    <option value="">선택</option>
                    @foreach($categories as $cat)
                        <option value="{{ $cat['name'] }}" data-code="{{ $cat['code'] }}">{{ $cat['name'] }}</option>
                    @endforeach
                    <option value="__custom__">직접 입력</option>
                </select>
                <input type="text" id="category-custom" placeholder="분류명"
                       class="w-full px-2 py-1.5 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 mt-1 hidden"
                       oninput="templateState.category = this.value">
            </div>
            <div>
                <div class="flex items-center justify-between mb-1">
                    <label class="text-xs font-medium text-gray-500">회사명</label>
                    <label class="flex items-center gap-1 cursor-pointer">
                        <input type="checkbox" id="is_active" checked class="w-3.5 h-3.5 text-blue-600 rounded focus:ring-blue-500">
                        <span class="text-xs text-gray-500">활성</span>
                    </label>
                </div>
                <input type="text" id="company_name" placeholder="케이디산업"
                       class="w-full px-2 py-1.5 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
            </div>
        </div>

        <!-- Row 2: 연결 설정 (소스테이블 1개 + 체크박스 다건 검색) -->
        <div id="dynamic-links-section" class="mb-4">
            <div class="flex items-center gap-3 mb-2">
                <label class="text-xs font-medium text-gray-500 whitespace-nowrap">연결 설정</label>
                <select id="link-source-table" onchange="onLinkSourceTableChange(this.value)"
                        class="w-48 px-2 py-1 border border-gray-300 rounded text-xs focus:outline-none focus:ring-2 focus:ring-blue-500">
                    <option value="">소스 테이블 선택</option>
                </select>
                <span class="text-xs text-gray-400">또는</span>
                <input type="text" id="link-source-table-custom" placeholder="테이블명 직접 입력"
                       onchange="onLinkSourceTableCustom(this.value)"
                       class="w-36 px-2 py-1 border border-gray-300 rounded text-xs focus:outline-none focus:ring-2 focus:ring-blue-500">
                <select id="link-type" onchange="onLinkTypeChange(this.value)"
                        class="w-20 px-1 py-1 border border-gray-300 rounded text-xs">
                    <option value="multiple">다중</option>
                    <option value="single">단일</option>
                </select>
            </div>
            <!-- 검색 + 체크박스 결과 패널 -->
            <div id="link-search-panel" class="hidden">
                <div class="flex gap-2 mb-2">
                    <input type="text" id="link-search-input" placeholder="검색어 입력..."
                           oninput="searchLinkValues('__main__', this.value)"
                           class="flex-1 px-2 py-1.5 border border-gray-300 rounded text-xs focus:outline-none focus:ring-2 focus:ring-blue-500">
                    <button type="button" onclick="addCheckedLinkValues()" id="btn-add-checked"
                            class="px-3 py-1.5 bg-blue-600 text-white rounded text-xs hover:bg-blue-700 hidden">
                        선택 추가
                    </button>
                </div>
                <!-- 검색 결과 체크박스 리스트 -->
                <div id="link-search-results" class="border border-gray-200 rounded max-h-48 overflow-y-auto hidden"></div>
                <!-- 연결된 항목 태그 -->
                <div class="mt-2 flex flex-wrap gap-1" id="link-value-tags"></div>
            </div>
        </div>

        <!-- Row 3: Footer - 비고라벨 + 판정라벨 -->
        <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
            <div>
                <label class="block text-xs font-medium text-gray-500 mb-1">비고 라벨</label>
                <input type="text" id="footer_remark_label" placeholder="예: 부적합 내용"
                       class="w-full px-3 py-1.5 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
            </div>
            <div>
                <label class="block text-xs font-medium text-gray-500 mb-1">종합판정 라벨</label>
                <input type="text" id="footer_judgement_label" placeholder="예: 종합판정"
                       class="w-full px-3 py-1.5 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
            </div>
        </div>

        <!-- Row 4: 종합판정 옵션 -->
        <div class="mb-6">
            <label class="block text-xs font-medium text-gray-500 mb-1">종합판정 옵션</label>
            <div class="flex items-center gap-2">
                <div id="judgement-options-container" class="flex flex-wrap gap-2 flex-1">
                    <!-- 동적으로 렌더링 -->
                </div>
                <button type="button" onclick="addJudgementOption()" class="bg-gray-100 hover:bg-gray-200 text-gray-600 px-3 py-1.5 rounded-lg text-xs flex-shrink-0">
                    + 옵션 추가
                </button>
            </div>
        </div>

        <!-- 구분선 + 결재라인 -->
        <hr class="my-5 border-gray-200">
        <div class="flex justify-between items-center mb-3">
            <h3 class="text-sm font-semibold text-gray-700">결재라인</h3>
            <button type="button" onclick="addApprovalLine()" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded-lg text-xs flex items-center gap-1">
                <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
                </svg>
                추가
            </button>
        </div>
        <div id="approval-lines" class="space-y-2">
            <!-- 동적으로 추가됨 -->
        </div>
        <p id="approval-empty" class="text-gray-400 text-center py-4 text-sm hidden">결재라인이 없습니다. 추가 버튼을 클릭하세요.</p>
    </div>

    <!-- 기본필드 탭 -->
    <div id="content-basic-fields" class="tab-content bg-white rounded-lg shadow-sm p-6 hidden">
        <div class="flex justify-between items-center mb-4">
            <div>
                <h3 class="text-lg font-medium text-gray-800">기본필드 설정</h3>
                <p class="text-xs text-gray-500 mt-1">문서 상단에 표시되는 필드입니다 (예: 품명, LOT NO, 검사일자)</p>
            </div>
            <button type="button" onclick="addBasicField()" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1.5 rounded-lg text-sm flex items-center gap-1">
                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
                </svg>
                추가
            </button>
        </div>
        <div id="basic-fields-container" class="space-y-3">
            <!-- 동적으로 추가됨 -->
        </div>
        <p id="basic-fields-empty" class="text-gray-400 text-center py-8 hidden">기본필드가 없습니다. 추가 버튼을 클릭하세요.</p>
    </div>

    <!-- 검사 기준서 탭 -->
    <div id="content-sections" class="tab-content bg-white rounded-lg shadow-sm p-6 hidden">
        <!-- 필드 설정 접이식 영역 -->
        <div class="mb-6 border border-blue-200 rounded-lg">
            <button type="button" onclick="toggleFieldSettings()" class="w-full px-4 py-3 bg-blue-50 text-left flex justify-between items-center rounded-t-lg hover:bg-blue-100">
                <span class="text-sm font-medium text-blue-700" id="field-settings-label">필드 설정</span>
                <svg id="field-settings-arrow" class="w-4 h-4 text-blue-500 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
                </svg>
            </button>
            <div id="field-settings-body" class="hidden p-4 space-y-3">
                <div class="flex justify-between items-center">
                    <p class="text-xs text-gray-500">검사 기준서에 포함될 필드를 설정합니다.</p>
                    <div class="flex gap-2">
                        <select id="preset-select" class="px-2 py-1 border border-gray-300 rounded text-xs">
                            <option value="">프리셋에서 가져오기...</option>
                        </select>
                        <button type="button" onclick="applyPreset()" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-2 py-1 rounded text-xs">적용</button>
                        <button type="button" onclick="addSectionField()" class="bg-blue-600 hover:bg-blue-700 text-white px-2 py-1 rounded text-xs">+ 필드 추가</button>
                    </div>
                </div>
                <div id="section-fields-container" class="space-y-2">
                    <!-- 동적으로 렌더링 -->
                </div>
            </div>
        </div>

        <div class="flex justify-between items-center mb-4">
            <h3 class="text-lg font-medium text-gray-800">검사 기준서 섹션</h3>
            <button type="button" onclick="addSection()" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1.5 rounded-lg text-sm flex items-center gap-1">
                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
                </svg>
                섹션 추가
            </button>
        </div>
        <div id="sections-container" class="space-y-4">
            <!-- 동적으로 추가됨 -->
        </div>
        <p id="sections-empty" class="text-gray-400 text-center py-8 hidden">검사 기준서 섹션이 없습니다. 섹션 추가 버튼을 클릭하세요.</p>
    </div>

    <!-- 테이블 컬럼 탭 -->
    <div id="content-columns" class="tab-content bg-white rounded-lg shadow-sm p-6 hidden">
        <div class="flex justify-between items-center mb-4">
            <div class="flex items-center gap-3">
                <h3 class="text-lg font-medium text-gray-800">검사 데이터 테이블 컬럼</h3>
                <span id="auto-columns-indicator" class="text-xs text-green-600 bg-green-50 px-2 py-0.5 rounded hidden"></span>
            </div>
            <div class="flex items-center gap-2">
                <button type="button" onclick="applyAutoColumns()" class="bg-emerald-600 hover:bg-emerald-700 text-white px-3 py-1.5 rounded-lg text-sm flex items-center gap-1" title="검사 기준서 항목에서 컬럼을 자동 생성합니다">
                    <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                    </svg>
                    기준서에서 자동 생성
                </button>
                <button type="button" onclick="addColumn()" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1.5 rounded-lg text-sm flex items-center gap-1">
                    <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
                    </svg>
                    컬럼 추가
                </button>
            </div>
        </div>
        <p class="text-xs text-gray-500 mb-3">검사 기준서 항목의 측정유형에서 컬럼을 자동 생성하거나, 수동으로 추가/편집할 수 있습니다.</p>
        <div id="columns-container" class="space-y-3">
            <!-- 동적으로 추가됨 -->
        </div>
        <p id="columns-empty" class="text-gray-400 text-center py-8 hidden">테이블 컬럼이 없습니다. "기준서에서 자동 생성" 또는 "컬럼 추가" 버튼을 클릭하세요.</p>
    </div>
</div>

<!-- 미리보기 모달 (공통 partial) -->
@include('document-templates.partials.preview-modal')
@endsection

@push('scripts')
<script>
    // ===== 상태 관리 =====
    const templateState = {
        id: {{ $template->id ?? 'null' }},
        name: '',
        category: '',
        title: '',
        company_name: '',
        footer_remark_label: '부적합 내용',
        footer_judgement_label: '종합판정',
        footer_judgement_options: ['합격', '불합격', '조건부합격'],
        is_active: true,
        linked_item_ids: null,
        linked_process_id: null,
        approval_lines: [],
        basic_fields: [],
        sections: [],
        columns: [],
        section_fields: [],
        template_links: []
    };

    // 시스템 프리셋
    const fieldPresets = @json($presets ?? []);
    const basicFieldKeys = @json($basicFieldKeys ?? []);

    // 고유 ID 생성
    let uniqueId = 0;
    function generateId() {
        return `temp_${++uniqueId}`;
    }

    // ===== 초기화 =====
    document.addEventListener('DOMContentLoaded', function() {
        @if($template && isset($templateData))
        // 기존 데이터 로드 (컨트롤러에서 준비된 데이터 사용)
        const loadedData = @json($templateData);
        templateState.name = loadedData.name || '';
        templateState.category = loadedData.category || '';
        templateState.title = loadedData.title || '';
        templateState.company_name = loadedData.company_name || '';
        templateState.footer_remark_label = loadedData.footer_remark_label || '';
        templateState.footer_judgement_label = loadedData.footer_judgement_label || '';
        templateState.footer_judgement_options = loadedData.footer_judgement_options || [];
        templateState.is_active = loadedData.is_active || false;
        templateState.linked_item_ids = loadedData.linked_item_ids || null;
        templateState.linked_process_id = loadedData.linked_process_id || null;
        templateState.approval_lines = loadedData.approval_lines || [];
        templateState.basic_fields = loadedData.basic_fields || [];
        templateState.sections = loadedData.sections || [];
        templateState.columns = loadedData.columns || [];
        templateState.section_fields = loadedData.section_fields || [];
        templateState.template_links = loadedData.template_links || [];
        @endif

        // UI 초기화
        initBasicInfo();
        renderJudgementOptions();
        renderApprovalLines();
        renderBasicFields();
        loadInspectionMethods(); // 검사방식 옵션 로드 후 renderSections 자동 호출
        renderColumns();
    });

    let userSearchTimer = null;

    // ===== 기본정보 =====
    function initBasicInfo() {
        document.getElementById('name').value = templateState.name || '';
        document.getElementById('title').value = templateState.title || '';
        document.getElementById('footer_remark_label').value = templateState.footer_remark_label || '';
        document.getElementById('footer_judgement_label').value = templateState.footer_judgement_label || '';
        document.getElementById('is_active').checked = templateState.is_active;

        // 회사명 자동채움 (생성 시)
        @if($isCreate && $tenant)
        document.getElementById('company_name').value = '{{ $tenant->company_name ?? '' }}';
        templateState.company_name = '{{ $tenant->company_name ?? '' }}';
        @else
        document.getElementById('company_name').value = templateState.company_name || '';
        @endif

        // 분류 초기값 설정
        const categorySelect = document.getElementById('category');
        const categoryValue = templateState.category || '';
        const predefined = ['수입검사', '중간검사', '품질검사'];
        const existingOptions = Array.from(categorySelect.options).map(o => o.value);

        if (categoryValue && !existingOptions.includes(categoryValue) && categoryValue !== '__custom__') {
            // 기존 카테고리 목록에 없는 커스텀 값
            categorySelect.value = '__custom__';
            document.getElementById('category-custom').value = categoryValue;
            document.getElementById('category-custom').classList.remove('hidden');
        } else {
            categorySelect.value = categoryValue;
        }
        onCategoryChange(categorySelect.value, true);

        // 동적 연결 UI 렌더링
        populateLinkSourceTable();
        // 프리셋 select 초기화
        initPresetSelect();
        // 필드 설정 렌더링
        renderSectionFields();

        // 변경 이벤트 바인딩
        ['name', 'title', 'company_name', 'footer_remark_label', 'footer_judgement_label'].forEach(field => {
            document.getElementById(field).addEventListener('input', function() {
                templateState[field] = this.value;
            });
        });
        document.getElementById('is_active').addEventListener('change', function() {
            templateState.is_active = this.checked;
        });
    }

    // ===== 분류 변경 핸들러 =====
    function onCategoryChange(value, isInit = false) {
        const customInput = document.getElementById('category-custom');

        // 직접 입력 모드
        if (value === '__custom__') {
            customInput.classList.remove('hidden');
            customInput.focus();
            templateState.category = customInput.value;
        } else {
            customInput.classList.add('hidden');
            templateState.category = value;
        }

        // 분류 변경 시 프리셋 자동 적용 제안 (초기 로드 제외)
        if (!isInit && value && value !== '__custom__') {
            const matchingPreset = fieldPresets.find(p => p.category === value);
            if (matchingPreset && templateState.section_fields.length === 0) {
                if (confirm(`'${value}' 카테고리에 맞는 프리셋(${matchingPreset.name})을 적용할까요?`)) {
                    applyPresetData(matchingPreset);
                }
            }
        }

        // 연결 UI 렌더링
        populateLinkSourceTable();
    }

    // ===== 결재라인 단계명 변경 핸들러 =====
    function onApprovalNameChange(id, value) {
        const line = templateState.approval_lines.find(l => l.id == id);
        if (!line) return;
        line.name = value;
        if (value === '작성') {
            line.dept = '(작성자)';
            line.role = '(작성자)';
            line.user_id = null;
            line.user_name = null;
        } else {
            if (line.dept === '(작성자)') line.dept = '';
            if (line.role === '(작성자)') line.role = '';
        }
        renderApprovalLines();
    }

    // ===== 결재라인 사용자 검색 =====
    function searchApprovalUser(lineId, query) {
        clearTimeout(userSearchTimer);
        const resultsContainer = document.getElementById(`user-results-${lineId}`);
        if (query.length < 1) {
            resultsContainer.classList.add('hidden');
            return;
        }
        userSearchTimer = setTimeout(() => {
            fetch(`/api/admin/tenant-users/search?q=${encodeURIComponent(query)}`, {
                headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}' }
            })
            .then(r => r.json())
            .then(result => {
                if (!result.success || !result.data.length) {
                    resultsContainer.innerHTML = '<div class="px-3 py-2 text-sm text-gray-400">결과 없음</div>';
                    resultsContainer.classList.remove('hidden');
                    return;
                }
                resultsContainer.innerHTML = result.data.map(user => `
                    <div class="px-3 py-2 text-sm hover:bg-blue-50 cursor-pointer"
                         onclick="selectApprovalUser('${lineId}', ${user.id}, '${escapeHtml(user.name)}', '${escapeHtml(user.department_name || '')}')">
                        <span class="font-medium">${escapeHtml(user.name)}</span>
                        ${user.department_name ? `<span class="text-gray-400 ml-2">${escapeHtml(user.department_name)}</span>` : ''}
                    </div>
                `).join('');
                resultsContainer.classList.remove('hidden');
            });
        }, 300);
    }

    function selectApprovalUser(lineId, userId, userName, deptName) {
        const line = templateState.approval_lines.find(l => l.id == lineId);
        if (!line) return;
        line.user_id = userId;
        line.user_name = userName;
        if (deptName && !line.dept) line.dept = deptName;

        // UI 업데이트
        const searchInput = document.getElementById(`user-search-${lineId}`);
        if (searchInput) searchInput.value = userName;
        const hiddenInput = document.getElementById(`user-id-${lineId}`);
        if (hiddenInput) hiddenInput.value = userId;
        const resultsContainer = document.getElementById(`user-results-${lineId}`);
        if (resultsContainer) resultsContainer.classList.add('hidden');
    }

    // ===== 종합판정 옵션 =====
    function renderJudgementOptions() {
        const container = document.getElementById('judgement-options-container');
        container.innerHTML = templateState.footer_judgement_options.map((opt, idx) => `
            <div class="flex items-center gap-1 bg-gray-100 rounded-lg px-2 py-1">
                <input type="text" value="${escapeHtml(opt)}" placeholder="옵션"
                       onchange="updateJudgementOption(${idx}, this.value)"
                       class="w-24 px-2 py-1 border border-gray-200 rounded text-sm bg-white">
                <button onclick="removeJudgementOption(${idx})" class="text-red-400 hover:text-red-600">
                    <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
                    </svg>
                </button>
            </div>
        `).join('');
    }

    function addJudgementOption() {
        templateState.footer_judgement_options.push('');
        renderJudgementOptions();
        // 마지막 input에 포커스
        const inputs = document.querySelectorAll('#judgement-options-container input[type="text"]');
        if (inputs.length) inputs[inputs.length - 1].focus();
    }

    function updateJudgementOption(idx, value) {
        templateState.footer_judgement_options[idx] = value;
    }

    function removeJudgementOption(idx) {
        templateState.footer_judgement_options.splice(idx, 1);
        renderJudgementOptions();
    }

    // ===== 기본필드 (basic_fields) =====
    function addBasicField() {
        templateState.basic_fields.push({
            id: generateId(),
            label: '',
            field_key: null,
            field_type: 'text',
            default_value: ''
        });
        renderBasicFields();
    }

    function removeBasicField(id) {
        templateState.basic_fields = templateState.basic_fields.filter(f => f.id !=id);
        renderBasicFields();
    }

    function updateBasicField(id, field, value) {
        const bf = templateState.basic_fields.find(f => f.id ==id);
        if (bf) bf[field] = value;
    }

    function renderBasicFields() {
        const container = document.getElementById('basic-fields-container');
        const emptyMsg = document.getElementById('basic-fields-empty');

        if (templateState.basic_fields.length === 0) {
            container.innerHTML = '';
            emptyMsg.classList.remove('hidden');
            return;
        }

        emptyMsg.classList.add('hidden');
        container.innerHTML = templateState.basic_fields.map((field, idx) => `
            <div class="flex items-center gap-3 p-3 bg-gray-50 rounded-lg cursor-move" data-bf-id="${field.id}">
                <span class="text-gray-400 font-bold" title="드래그하여 순서 변경">⋮⋮</span>
                <span class="text-gray-400 font-mono text-sm w-6">${idx + 1}</span>
                <input type="text" value="${escapeHtml(field.label)}" placeholder="필드명 (예: 품명, LOT NO)"
                       onchange="updateBasicField('${field.id}', 'label', this.value)"
                       class="flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm">
                <select onchange="updateBasicField('${field.id}', 'field_key', this.value || null)"
                        class="w-36 px-3 py-2 border border-gray-300 rounded-lg text-sm">
                    <option value="">연동키 선택</option>
                    ${basicFieldKeys.map(k => `<option value="${k.code}" ${field.field_key === k.code ? 'selected' : ''}>${k.name} (${k.code})</option>`).join('')}
                </select>
                <select onchange="updateBasicField('${field.id}', 'field_type', this.value)"
                        class="w-28 px-3 py-2 border border-gray-300 rounded-lg text-sm">
                    <option value="text" ${field.field_type === 'text' ? 'selected' : ''}>텍스트</option>
                    <option value="date" ${field.field_type === 'date' ? 'selected' : ''}>날짜</option>
                    <option value="number" ${field.field_type === 'number' ? 'selected' : ''}>숫자</option>
                    <option value="select" ${field.field_type === 'select' ? 'selected' : ''}>선택</option>
                    <option value="item_search" ${field.field_type === 'item_search' ? 'selected' : ''}>품목검색</option>
                </select>
                <input type="text" value="${escapeHtml(field.default_value || '')}" placeholder="기본값"
                       onchange="updateBasicField('${field.id}', 'default_value', this.value)"
                       class="w-32 px-3 py-2 border border-gray-300 rounded-lg text-sm">
                <button onclick="removeBasicField('${field.id}')" class="text-red-500 hover:text-red-700 p-1">
                    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                    </svg>
                </button>
            </div>
        `).join('');
    }

    // ===== 탭 전환 =====
    function switchTab(tabId) {
        // 모든 탭 버튼 비활성화
        document.querySelectorAll('.tab-btn').forEach(btn => {
            btn.classList.remove('border-blue-500', 'text-blue-600');
            btn.classList.add('border-transparent', 'text-gray-500');
        });
        // 선택된 탭 버튼 활성화
        const activeBtn = document.getElementById(`tab-${tabId}`);
        activeBtn.classList.add('border-blue-500', 'text-blue-600');
        activeBtn.classList.remove('border-transparent', 'text-gray-500');

        // 모든 컨텐츠 숨김
        document.querySelectorAll('.tab-content').forEach(content => {
            content.classList.add('hidden');
        });
        // 선택된 컨텐츠 표시
        document.getElementById(`content-${tabId}`).classList.remove('hidden');
    }

    // ===== 결재라인 =====
    function addApprovalLine() {
        const line = { id: generateId(), name: '작성', dept: '(작성자)', role: '(작성자)', user_id: null, user_name: null };
        templateState.approval_lines.push(line);
        renderApprovalLines();
    }

    function removeApprovalLine(id) {
        templateState.approval_lines = templateState.approval_lines.filter(l => l.id !=id);
        renderApprovalLines();
    }

    function updateApprovalLine(id, field, value) {
        const line = templateState.approval_lines.find(l => l.id ==id);
        if (line) line[field] = value;
    }

    function renderApprovalLines() {
        const container = document.getElementById('approval-lines');
        const emptyMsg = document.getElementById('approval-empty');

        if (templateState.approval_lines.length === 0) {
            container.innerHTML = '';
            emptyMsg.classList.remove('hidden');
            return;
        }

        emptyMsg.classList.add('hidden');
        container.innerHTML = templateState.approval_lines.map((line, idx) => {
            const isWriter = (line.name === '작성');
            const userDisplay = isWriter
                ? '<span class="text-gray-400 text-xs px-2">(작성자)</span>'
                : `<div class="relative">
                    <input type="text" id="user-search-${line.id}" placeholder="사용자 검색..."
                           value="${line.user_id ? escapeHtml(line.user_name || '') : ''}"
                           oninput="searchApprovalUser('${line.id}', this.value)"
                           onfocus="searchApprovalUser('${line.id}', this.value)"
                           class="w-40 px-2 py-1 border border-gray-300 rounded text-xs">
                    <input type="hidden" id="user-id-${line.id}" value="${line.user_id || ''}">
                    <div id="user-results-${line.id}" class="absolute z-10 w-full bg-white border border-gray-200 rounded-lg shadow-lg max-h-40 overflow-y-auto hidden"></div>
                  </div>`;
            const deptRoleDisplay = isWriter
                ? '<span class="text-gray-400 text-xs px-2">(작성자)</span>'
                : `<input type="text" value="${escapeHtml(line.dept)}" placeholder="부서"
                       onchange="updateApprovalLine('${line.id}', 'dept', this.value)"
                       class="w-24 px-2 py-1 border border-gray-300 rounded text-xs">
                   <input type="text" value="${escapeHtml(line.role)}" placeholder="직책"
                       onchange="updateApprovalLine('${line.id}', 'role', this.value)"
                       class="w-24 px-2 py-1 border border-gray-300 rounded text-xs">`;

            return `
            <div class="flex items-center gap-2 px-3 py-2 bg-gray-50 rounded cursor-move" data-id="${line.id}">
                <span class="text-gray-300 text-xs cursor-grab" title="드래그하여 순서 변경">⋮⋮</span>
                <span class="text-gray-400 font-mono text-xs w-4">${idx + 1}</span>
                <select onchange="onApprovalNameChange('${line.id}', this.value)"
                        class="w-20 px-2 py-1 border border-gray-300 rounded text-xs">
                    <option value="작성" ${line.name === '작성' ? 'selected' : ''}>작성</option>
                    <option value="검토" ${line.name === '검토' ? 'selected' : ''}>검토</option>
                    <option value="승인" ${line.name === '승인' ? 'selected' : ''}>승인</option>
                    <option value="참조" ${line.name === '참조' ? 'selected' : ''}>참조</option>
                </select>
                ${deptRoleDisplay}
                ${userDisplay}
                <button onclick="removeApprovalLine('${line.id}')" class="text-red-400 hover:text-red-600 p-0.5 ml-auto">
                    <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
                    </svg>
                </button>
            </div>`;
        }).join('');
    }

    // ===== 섹션 관리 =====
    function addSection() {
        const section = { id: generateId(), title: '', image_path: null, items: [] };
        templateState.sections.push(section);
        renderSections();
    }

    function removeSection(id) {
        templateState.sections = templateState.sections.filter(s => s.id !=id);
        renderSections();
    }

    function updateSection(id, field, value) {
        const section = templateState.sections.find(s => s.id ==id);
        if (section) section[field] = value;
    }

    // 검사방식 → 측정유형 자동매핑
    const METHOD_TO_MEASUREMENT = {
        'visual': 'checkbox',
        'check': 'numeric',
        'mill_sheet': 'single_value',
        'certified_agency': 'single_value',
        'substitute_cert': 'substitute',
        'other': 'text'
    };

    // 측정유형 옵션 정의
    const MEASUREMENT_TYPES = [
        { code: 'checkbox', name: 'OK/NG 체크' },
        { code: 'numeric', name: '수치입력(3)' },
        { code: 'single_value', name: '단일값' },
        { code: 'substitute', name: '성적서 대체' },
        { code: 'text', name: '자유입력' }
    ];

    // 검사방식(inspection_method) 옵션 - 페이지 로드 시 API에서 가져옴
    let inspectionMethods = [];

    function loadInspectionMethods() {
        fetch('/api/admin/common-codes/inspection_method', {
            headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}' }
        })
        .then(r => r.json())
        .then(result => {
            if (result.success && result.data) {
                inspectionMethods = result.data;
            } else {
                // fallback 기본값
                inspectionMethods = [
                    { code: 'visual', name: '육안검사' },
                    { code: 'check', name: '체크검사' },
                    { code: 'mill_sheet', name: '공급업체 밀시트' },
                    { code: 'certified_agency', name: '공인시험기관' },
                    { code: 'substitute_cert', name: '공급업체 성적서 대체' },
                    { code: 'other', name: '기타' }
                ];
            }
            renderSections();
        })
        .catch(() => {
            inspectionMethods = [
                { code: 'visual', name: '육안검사' },
                { code: 'check', name: '체크검사' },
                { code: 'mill_sheet', name: '공급업체 밀시트' },
                { code: 'certified_agency', name: '공인시험기관' },
                { code: 'substitute_cert', name: '공급업체 성적서 대체' },
                { code: 'other', name: '기타' }
            ];
            renderSections();
        });
    }

    function onMethodChange(sectionId, itemId, value) {
        updateSectionItem(sectionId, itemId, 'method', value);
        // 자동 매핑
        const mapped = METHOD_TO_MEASUREMENT[value] || '';
        updateSectionItem(sectionId, itemId, 'measurement_type', mapped);
        renderSections();
    }

    function addSectionItem(sectionId) {
        const section = templateState.sections.find(s => s.id ==sectionId);
        if (section) {
            // field_values 기반으로 빈 항목 생성
            const fieldValues = {};
            templateState.section_fields.forEach(f => {
                fieldValues[f.field_key] = null;
            });
            section.items.push({
                id: generateId(),
                category: '',
                item: '',
                standard: '',
                tolerance: null,
                standard_criteria: null,
                method: '',
                measurement_type: '',
                frequency_n: null,
                frequency_c: null,
                frequency: '',
                regulation: '',
                field_values: fieldValues
            });
            renderSections();
        }
    }

    function removeSectionItem(sectionId, itemId) {
        const section = templateState.sections.find(s => s.id ==sectionId);
        if (section) {
            section.items = section.items.filter(i => i.id !=itemId);
            renderSections();
        }
    }

    function updateSectionItem(sectionId, itemId, field, value) {
        const section = templateState.sections.find(s => s.id ==sectionId);
        if (section) {
            const item = section.items.find(i => i.id ==itemId);
            if (item) item[field] = value;
        }
    }

    // ── 공차(Tolerance) 구조화 함수들 ──

    function updateToleranceProp(sectionId, itemId, prop, value) {
        const section = templateState.sections.find(s => s.id == sectionId);
        if (!section) return;
        const item = section.items.find(i => i.id == itemId);
        if (!item) return;

        if (prop === 'type') {
            // 타입 변경 시 초기화
            const defaults = {
                symmetric: { type: 'symmetric', value: null },
                asymmetric: { type: 'asymmetric', plus: null, minus: null },
                range: { type: 'range', min: null, max: null },
                limit: { type: 'limit', op: 'lte', value: null },
            };
            item.tolerance = value ? (defaults[value] || null) : null;
        } else {
            if (!item.tolerance) return;
            const numVal = value !== '' ? parseFloat(value) : null;
            if (prop === 'op') {
                item.tolerance.op = value;
            } else {
                item.tolerance[prop] = numVal;
            }
        }
        renderSections();
    }

    function renderToleranceInput(sectionId, itemId, tol) {
        const tolType = tol?.type || '';
        const selectHtml = `<select onchange="updateToleranceProp('${sectionId}', '${itemId}', 'type', this.value)"
            class="px-1 py-0.5 border border-gray-200 rounded text-xs mb-0.5" style="width:80px">
            <option value="" ${!tolType ? 'selected' : ''}>없음</option>
            <option value="symmetric" ${tolType === 'symmetric' ? 'selected' : ''}>± 대칭</option>
            <option value="asymmetric" ${tolType === 'asymmetric' ? 'selected' : ''}>+/- 비대칭</option>
            <option value="range" ${tolType === 'range' ? 'selected' : ''}>~ 범위</option>
            <option value="limit" ${tolType === 'limit' ? 'selected' : ''}>한계값</option>
        </select>`;

        let fieldsHtml = '';
        if (tolType === 'symmetric') {
            fieldsHtml = `<div class="flex items-center gap-0.5">
                <span class="text-xs text-gray-500">±</span>
                <input type="number" step="any" value="${tol.value ?? ''}" placeholder="0.10"
                       onchange="updateToleranceProp('${sectionId}', '${itemId}', 'value', this.value)"
                       class="flex-1 px-1 py-0.5 border border-gray-200 rounded text-xs">
            </div>`;
        } else if (tolType === 'asymmetric') {
            fieldsHtml = `<div class="flex items-center gap-0.5">
                <span class="text-xs text-gray-500">+</span>
                <input type="number" step="any" value="${tol.plus ?? ''}" placeholder="0.20"
                       onchange="updateToleranceProp('${sectionId}', '${itemId}', 'plus', this.value)"
                       class="px-1 py-0.5 border border-gray-200 rounded text-xs" style="width:36px">
                <span class="text-xs text-gray-500">-</span>
                <input type="number" step="any" value="${tol.minus ?? ''}" placeholder="0.10"
                       onchange="updateToleranceProp('${sectionId}', '${itemId}', 'minus', this.value)"
                       class="px-1 py-0.5 border border-gray-200 rounded text-xs" style="width:36px">
            </div>`;
        } else if (tolType === 'range') {
            fieldsHtml = `<div class="flex items-center gap-0.5">
                <input type="number" step="any" value="${tol.min ?? ''}" placeholder="min"
                       onchange="updateToleranceProp('${sectionId}', '${itemId}', 'min', this.value)"
                       class="px-1 py-0.5 border border-gray-200 rounded text-xs" style="width:36px">
                <span class="text-xs text-gray-400">~</span>
                <input type="number" step="any" value="${tol.max ?? ''}" placeholder="max"
                       onchange="updateToleranceProp('${sectionId}', '${itemId}', 'max', this.value)"
                       class="px-1 py-0.5 border border-gray-200 rounded text-xs" style="width:36px">
            </div>`;
        } else if (tolType === 'limit') {
            fieldsHtml = `<div class="flex items-center gap-0.5">
                <select onchange="updateToleranceProp('${sectionId}', '${itemId}', 'op', this.value)"
                        class="py-0.5 border border-gray-200 rounded text-xs" style="width:28px;padding:2px 0">
                    <option value="lte" ${tol.op === 'lte' ? 'selected' : ''}>≤</option>
                    <option value="lt" ${tol.op === 'lt' ? 'selected' : ''}>&#60;</option>
                    <option value="gte" ${tol.op === 'gte' ? 'selected' : ''}>≥</option>
                    <option value="gt" ${tol.op === 'gt' ? 'selected' : ''}>&#62;</option>
                </select>
                <input type="number" step="any" value="${tol.value ?? ''}" placeholder="0.05"
                       onchange="updateToleranceProp('${sectionId}', '${itemId}', 'value', this.value)"
                       class="px-1 py-0.5 border border-gray-200 rounded text-xs" style="width:48px">
            </div>`;
        }

        return selectHtml + fieldsHtml;
    }

    function formatTolerance(tol) {
        if (!tol || !tol.type) return '-';
        switch (tol.type) {
            case 'symmetric':
                return tol.value != null ? `\u00B1${tol.value}` : '-';
            case 'asymmetric':
                return (tol.plus != null || tol.minus != null)
                    ? `+${tol.plus ?? 0} / -${tol.minus ?? 0}` : '-';
            case 'range':
                return (tol.min != null || tol.max != null)
                    ? `${tol.min ?? ''} ~ ${tol.max ?? ''}` : '-';
            case 'limit': {
                const opSymbol = { lte: '\u2264', lt: '<', gte: '\u2265', gt: '>' };
                return tol.value != null ? `${opSymbol[tol.op] || '\u2264'}${tol.value}` : '-';
            }
            default: return '-';
        }
    }

    function updateStandardCriteria(sectionId, itemId, field, value) {
        const section = templateState.sections.find(s => s.id == sectionId);
        if (!section) return;
        const item = section.items.find(i => i.id == itemId);
        if (!item) return;
        if (!item.standard_criteria) item.standard_criteria = {};
        if (field === 'min' || field === 'max') {
            item.standard_criteria[field] = value !== '' ? parseFloat(value) : null;
            // 기본 연산자 자동 설정
            if (field === 'min' && !item.standard_criteria.min_op) item.standard_criteria.min_op = 'gte';
            if (field === 'max' && !item.standard_criteria.max_op) item.standard_criteria.max_op = 'lte';
        } else {
            item.standard_criteria[field] = value;
        }
        // min/max 둘 다 비어있으면 null로 초기화
        const c = item.standard_criteria;
        if (c.min == null && c.max == null) {
            item.standard_criteria = null;
        }
    }

    function renderSections() {
        const container = document.getElementById('sections-container');
        const emptyMsg = document.getElementById('sections-empty');

        if (templateState.sections.length === 0) {
            container.innerHTML = '';
            emptyMsg.classList.remove('hidden');
            return;
        }

        emptyMsg.classList.add('hidden');
        container.innerHTML = templateState.sections.map((section, idx) => `
            <div class="border border-gray-200 rounded-lg overflow-hidden" data-section-id="${section.id}">
                <div class="bg-gray-50 p-4 flex items-center justify-between">
                    <div class="flex items-center gap-3 flex-1">
                        <span class="text-gray-400 font-bold cursor-move drag-handle" title="드래그하여 순서 변경">⋮⋮</span>
                        <input type="text" value="${escapeHtml(section.title)}" placeholder="섹션 제목 (예: 가이드레일)"
                               onchange="updateSection('${section.id}', 'title', this.value)"
                               class="flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm font-medium">
                    </div>
                    <div class="flex items-center gap-2">
                        <label class="text-gray-600 hover:text-blue-600 text-sm flex items-center gap-1 cursor-pointer">
                            <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
                            </svg>
                            이미지
                            <input type="file" accept="image/*" class="hidden" onchange="uploadSectionImage('${section.id}', this)">
                        </label>
                        <button onclick="addSectionItem('${section.id}')" class="text-blue-600 hover:text-blue-800 text-sm flex items-center gap-1">
                            <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
                            </svg>
                            항목 추가
                        </button>
                        <button onclick="removeSection('${section.id}')" class="text-red-500 hover:text-red-700 p-1">
                            <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                            </svg>
                        </button>
                    </div>
                </div>
                ${section.image_path ? `
                    <div class="px-4 py-2 bg-blue-50 flex items-center justify-between">
                        <div class="flex items-center gap-2">
                            <img src="${getSectionImageUrl(section.image_path)}" alt="섹션 이미지" class="h-16 rounded border border-gray-200">
                            <span class="text-xs text-gray-500">이미지 첨부됨</span>
                        </div>
                        <button onclick="removeSectionImage('${section.id}')" class="text-red-500 hover:text-red-700 text-xs">
                            이미지 삭제
                        </button>
                    </div>
                ` : ''}
                <div class="p-4">
                    ${section.items.length > 0 ? `
                        <div class="overflow-x-auto">
                            <table class="w-full text-sm" style="min-width:${calcTableWidth()}px">
                                <thead class="bg-gray-100">
                                    <tr>
                                        ${templateState.section_fields.map(f => `
                                            <th class="px-2 py-2 text-left text-xs font-medium text-gray-500" style="min-width:${f.width || '100px'}">${escapeHtml(f.label)}</th>
                                        `).join('')}
                                        <th class="px-2 py-2" style="width:30px"></th>
                                    </tr>
                                </thead>
                                <tbody>
                                    ${section.items.map(item => `
                                        <tr class="border-t" data-item-id="${item.id}">
                                            ${templateState.section_fields.map(f => `
                                                <td class="px-1 py-1">
                                                    ${renderDynamicFieldInput(f, section.id, item)}
                                                </td>
                                            `).join('')}
                                            <td class="px-1 py-1">
                                                <button onclick="removeSectionItem('${section.id}', '${item.id}')" class="text-red-400 hover:text-red-600">
                                                    <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
                                                    </svg>
                                                </button>
                                            </td>
                                        </tr>
                                    `).join('')}
                                </tbody>
                            </table>
                        </div>
                    ` : `
                        <p class="text-gray-400 text-center py-4 text-sm">항목이 없습니다. 항목 추가 버튼을 클릭하세요.</p>
                    `}
                </div>
            </div>
        `).join('');
    }

    // ===== 검사기준서 → 테이블컬럼 자동 파생 (Phase 5.0) =====

    /**
     * 모든 섹션의 items를 분석하여 columns를 자동 생성한다.
     * 규칙:
     *   Step 1: 정적 컬럼 (NO, 검사항목, 검사기준) — 항상 포함
     *   Step 2: 동적 컬럼 — items의 measurement_type/method에서 파생
     *     - checkbox(육안) → check 컬럼
     *     - numeric(체크/계측) → complex 컬럼 (sub_labels: n1~n{max(frequency_n)})
     *     - single_value(밀시트/공인기관) → text 컬럼 (측정값)
     *     - text(기타) → text 컬럼
     *   Step 3: 부가 컬럼 — 검사방식(다양하면), 비고, 판정(항상)
     *
     * @param {boolean} confirmOverwrite - true면 기존 columns 덮어쓰기 확인 건너뜀
     * @returns {Array} 생성된 columns 배열
     */
    function generateColumnsFromItems(confirmOverwrite = false) {
        // 모든 섹션의 items 수집
        const allItems = templateState.sections.flatMap(s => s.items || []);

        if (allItems.length === 0) {
            showToast('검사 기준서에 항목이 없습니다. 항목을 먼저 추가하세요.', 'warning');
            return null;
        }

        // 기존 컬럼이 있고 사용자 확인 필요한 경우
        if (!confirmOverwrite && templateState.columns.length > 0) {
            if (!confirm('기존 테이블 컬럼이 자동 생성된 컬럼으로 교체됩니다. 계속하시겠습니까?')) {
                return null;
            }
        }

        const columns = [];
        let sortOrder = 1;

        // --- Step 1: 정적 컬럼 ---
        columns.push({ id: generateId(), label: 'NO', width: '40px', column_type: 'text', group_name: '', sub_labels: null, _auto: true });
        sortOrder++;
        columns.push({ id: generateId(), label: '검사항목', width: '120px', column_type: 'text', group_name: '', sub_labels: null, _auto: true });
        sortOrder++;
        columns.push({ id: generateId(), label: '검사기준', width: '150px', column_type: 'text', group_name: '', sub_labels: null, _auto: true });
        sortOrder++;

        // --- Step 2: 동적 컬럼 (measurement_type 분석) ---
        const types = new Set();
        let maxFrequencyN = 3; // 기본 3회 측정
        const methods = new Set();

        allItems.forEach(item => {
            const mt = item.measurement_type || '';
            if (mt) types.add(mt);
            if (item.method) methods.add(item.method);
            // frequency_n에서 최대값 추출
            const fn = parseInt(item.frequency_n);
            if (!isNaN(fn) && fn > maxFrequencyN) maxFrequencyN = fn;
            // frequency 문자열에서 n= 값 추출 (예: "n=3, c=0")
            if (item.frequency) {
                const match = item.frequency.match(/n\s*=\s*(\d+)/i);
                if (match) {
                    const nVal = parseInt(match[1]);
                    if (nVal > maxFrequencyN) maxFrequencyN = nVal;
                }
            }
        });

        // checkbox → check 컬럼 (OK/NG)
        if (types.has('checkbox')) {
            columns.push({ id: generateId(), label: 'OK/NG', width: '60px', column_type: 'check', group_name: '', sub_labels: null, _auto: true });
            sortOrder++;
        }

        // numeric → complex 컬럼 (측정치 n1~nN)
        if (types.has('numeric')) {
            const subLabels = [];
            for (let i = 1; i <= maxFrequencyN; i++) {
                subLabels.push(`n${i}`);
            }
            columns.push({ id: generateId(), label: '측정치', width: `${Math.max(160, maxFrequencyN * 60)}px`, column_type: 'complex', group_name: '측정치', sub_labels: subLabels, _auto: true });
            sortOrder++;
        }

        // single_value → text 컬럼 (측정값)
        if (types.has('single_value')) {
            columns.push({ id: generateId(), label: '측정값', width: '100px', column_type: 'text', group_name: '', sub_labels: null, _auto: true });
            sortOrder++;
        }

        // substitute → text 컬럼 (성적서 번호)
        if (types.has('substitute')) {
            columns.push({ id: generateId(), label: '성적서 번호', width: '120px', column_type: 'text', group_name: '', sub_labels: null, _auto: true });
            sortOrder++;
        }

        // text(기타) → text 컬럼
        if (types.has('text')) {
            columns.push({ id: generateId(), label: '비고/기타', width: '100px', column_type: 'text', group_name: '', sub_labels: null, _auto: true });
            sortOrder++;
        }

        // --- Step 3: 부가 컬럼 ---

        // 검사방식: 다양한 method가 있으면 포함
        if (methods.size > 1) {
            columns.push({ id: generateId(), label: '검사방식', width: '100px', column_type: 'text', group_name: '', sub_labels: null, _auto: true });
            sortOrder++;
        }

        // 판정 (항상 포함)
        columns.push({ id: generateId(), label: '판정', width: '80px', column_type: 'select', group_name: '', sub_labels: null, _auto: true });

        return columns;
    }

    /**
     * 자동 파생 실행 + 상태 반영 + 렌더링
     */
    function applyAutoColumns(confirmOverwrite = false) {
        const columns = generateColumnsFromItems(confirmOverwrite);
        if (columns) {
            templateState.columns = columns;
            renderColumns();
            showToast(`테이블 컬럼 ${columns.length}개가 자동 생성되었습니다.`, 'success');
            // 컬럼 탭에 자동생성 표시 업데이트
            updateAutoColumnsIndicator();
        }
    }

    /**
     * 자동생성 여부 표시 업데이트
     */
    function updateAutoColumnsIndicator() {
        const indicator = document.getElementById('auto-columns-indicator');
        if (!indicator) return;
        const hasAutoColumns = templateState.columns.some(c => c._auto);
        if (hasAutoColumns) {
            indicator.classList.remove('hidden');
            indicator.textContent = `자동 생성됨 (${templateState.columns.filter(c => c._auto).length}/${templateState.columns.length}개)`;
        } else {
            indicator.classList.add('hidden');
        }
    }

    // ===== 컬럼 관리 =====
    function addColumn() {
        const column = { id: generateId(), label: '', width: '100px', column_type: 'text', group_name: '', sub_labels: null };
        templateState.columns.push(column);
        renderColumns();
    }

    function removeColumn(id) {
        templateState.columns = templateState.columns.filter(c => c.id !=id);
        renderColumns();
    }

    function updateColumn(id, field, value) {
        const column = templateState.columns.find(c => c.id ==id);
        if (column) column[field] = value;
    }

    function renderColumns() {
        const container = document.getElementById('columns-container');
        const emptyMsg = document.getElementById('columns-empty');

        if (templateState.columns.length === 0) {
            container.innerHTML = '';
            emptyMsg.classList.remove('hidden');
            updateAutoColumnsIndicator();
            return;
        }

        emptyMsg.classList.add('hidden');
        container.innerHTML = templateState.columns.map((col, idx) => `
            <div class="p-3 bg-gray-50 rounded-lg cursor-move" data-column-id="${col.id}">
                <div class="flex items-center gap-3">
                    <span class="text-gray-400 font-bold" title="드래그하여 순서 변경">⋮⋮</span>
                    <span class="text-gray-400 font-mono text-sm w-6">${idx + 1}</span>
                    <input type="text" value="${escapeHtml(col.label)}" placeholder="컬럼명"
                           onchange="updateColumn('${col.id}', 'label', this.value)"
                           class="flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm">
                    <input type="text" value="${escapeHtml(col.width)}" placeholder="너비"
                           onchange="updateColumn('${col.id}', 'width', this.value)"
                           class="w-24 px-3 py-2 border border-gray-300 rounded-lg text-sm">
                    <select onchange="handleColumnTypeChange('${col.id}', this.value)"
                            class="w-32 px-3 py-2 border border-gray-300 rounded-lg text-sm">
                        <option value="text" ${col.column_type === 'text' ? 'selected' : ''}>텍스트</option>
                        <option value="check" ${col.column_type === 'check' ? 'selected' : ''}>체크</option>
                        <option value="measurement" ${col.column_type === 'measurement' ? 'selected' : ''}>측정값</option>
                        <option value="select" ${col.column_type === 'select' ? 'selected' : ''}>선택</option>
                        <option value="complex" ${col.column_type === 'complex' ? 'selected' : ''}>복합(하위컬럼)</option>
                    </select>
                    <input type="text" value="${escapeHtml(col.group_name || '')}" placeholder="그룹명"
                           onchange="updateColumn('${col.id}', 'group_name', this.value)"
                           class="w-28 px-3 py-2 border border-gray-300 rounded-lg text-sm">
                    <button onclick="removeColumn('${col.id}')" class="text-red-500 hover:text-red-700 p-1">
                        <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                        </svg>
                    </button>
                </div>
                ${col.column_type === 'complex' ? `
                    <div class="ml-10 mt-2 p-2 bg-white rounded border border-gray-200">
                        <div class="flex items-center gap-2 mb-2">
                            <span class="text-xs font-medium text-gray-600">하위 라벨:</span>
                            <button onclick="addSubLabel('${col.id}')" class="text-blue-600 hover:text-blue-800 text-xs">+ 추가</button>
                        </div>
                        <div class="flex flex-wrap gap-2">
                            ${(col.sub_labels || []).map((label, si) => `
                                <div class="flex items-center gap-1 bg-blue-50 rounded px-2 py-1">
                                    <input type="text" value="${escapeHtml(label)}" placeholder="${si + 1}"
                                           onchange="updateSubLabel('${col.id}', ${si}, this.value)"
                                           class="w-16 px-1 py-0.5 border border-blue-200 rounded text-xs bg-white text-center">
                                    <button onclick="removeSubLabel('${col.id}', ${si})" class="text-red-400 hover:text-red-600">
                                        <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
                                        </svg>
                                    </button>
                                </div>
                            `).join('')}
                            ${(!col.sub_labels || col.sub_labels.length === 0) ? '<span class="text-xs text-gray-400">하위 라벨이 없습니다.</span>' : ''}
                        </div>
                    </div>
                ` : ''}
            </div>
        `).join('');

        updateAutoColumnsIndicator();
    }

    // ===== 컬럼 타입 변경 처리 =====
    function handleColumnTypeChange(id, value) {
        const column = templateState.columns.find(c => c.id ==id);
        if (column) {
            column.column_type = value;
            if (value === 'complex' && !column.sub_labels) {
                column.sub_labels = ['1', '2', '3', '4', '5'];
            }
            if (value !== 'complex') {
                column.sub_labels = null;
            }
            renderColumns();
        }
    }

    function addSubLabel(colId) {
        const column = templateState.columns.find(c => c.id ==colId);
        if (column) {
            if (!column.sub_labels) column.sub_labels = [];
            column.sub_labels.push('');
            renderColumns();
            // 마지막 input에 포커스
            setTimeout(() => {
                const colEl = document.querySelector(`[data-column-id="${colId}"]`);
                if (colEl) {
                    const inputs = colEl.querySelectorAll('.bg-blue-50 input');
                    if (inputs.length) inputs[inputs.length - 1].focus();
                }
            }, 50);
        }
    }

    function updateSubLabel(colId, idx, value) {
        const column = templateState.columns.find(c => c.id ==colId);
        if (column && column.sub_labels) {
            column.sub_labels[idx] = value;
        }
    }

    function removeSubLabel(colId, idx) {
        const column = templateState.columns.find(c => c.id ==colId);
        if (column && column.sub_labels) {
            column.sub_labels.splice(idx, 1);
            renderColumns();
        }
    }

    // template_links의 items 값을 linked_item_ids로 동기화
    function syncLinkedItemIds() {
        const link = getMainLink();
        if (link && link.source_table === 'items' && link.values && link.values.length > 0) {
            return link.values.map(v => v.linkable_id || v.id).filter(Boolean);
        }
        return templateState.linked_item_ids;
    }

    // ===== 저장 =====
    function saveTemplate() {
        const name = document.getElementById('name').value.trim();
        if (!name) {
            showToast('양식명은 필수입니다.', 'warning');
            switchTab('basic');
            document.getElementById('name').focus();
            return;
        }

        const data = {
            name: name,
            category: document.getElementById('category').value,
            title: document.getElementById('title').value,

            company_name: document.getElementById('company_name').value,
            footer_remark_label: document.getElementById('footer_remark_label').value,
            footer_judgement_label: document.getElementById('footer_judgement_label').value,
            footer_judgement_options: templateState.footer_judgement_options.filter(o => o.trim() !== ''),
            is_active: document.getElementById('is_active').checked,
            linked_item_ids: syncLinkedItemIds(),
            linked_process_id: templateState.linked_process_id,
            approval_lines: templateState.approval_lines,
            basic_fields: templateState.basic_fields,
            sections: templateState.sections,
            columns: templateState.columns.map(c => { const { _auto, ...rest } = c; return rest; }),
            section_fields: templateState.section_fields,
            template_links: templateState.template_links.filter(l => l.source_table)
        };

        // 디버그: 섹션별 image_path 확인
        console.log('[saveTemplate] sections image_path:', data.sections.map(s => ({ id: s.id, title: s.title, image_path: s.image_path })));

        const url = templateState.id
            ? `/api/admin/document-templates/${templateState.id}`
            : '/api/admin/document-templates';
        const method = templateState.id ? 'PUT' : 'POST';

        fetch(url, {
            method: method,
            headers: {
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': '{{ csrf_token() }}',
                'Accept': 'application/json'
            },
            body: JSON.stringify(data)
        })
        .then(response => response.json())
        .then(result => {
            if (result.success) {
                showToast(result.message || '저장되었습니다.', 'success');
                if (!templateState.id && result.data?.id) {
                    // 새로 생성된 경우 편집 페이지로 이동
                    window.location.href = `/document-templates/${result.data.id}/edit`;
                }
            } else {
                showToast(result.message || '저장에 실패했습니다.', 'error');
            }
        })
        .catch(error => {
            console.error('Save error:', error);
            showToast('저장 중 오류가 발생했습니다.', 'error');
        });
    }

    // ===== 미리보기 (공통 buildDocumentPreviewHtml 사용) =====
    function openPreviewModal() {
        const getMethodName = (code) => {
            const m = inspectionMethods.find(im => im.code === code);
            return m ? m.name : (code || '-');
        };

        // field_values를 top-level 프로퍼티로 풀어서 미리보기 호환
        const normalizedSections = templateState.sections.map(s => ({
            ...s,
            items: (s.items || []).map(item => {
                const merged = { ...item };
                if (item.field_values) {
                    Object.entries(item.field_values).forEach(([k, v]) => {
                        if (v !== null && v !== undefined) {
                            merged[k] = v;
                        }
                    });
                }
                return merged;
            })
        }));

        const data = {
            title: document.getElementById('title').value,
            company_name: document.getElementById('company_name').value,
            footer_remark_label: document.getElementById('footer_remark_label').value,
            footer_judgement_label: document.getElementById('footer_judgement_label').value,
            footer_judgement_options: templateState.footer_judgement_options,
            approval_lines: templateState.approval_lines,
            basic_fields: templateState.basic_fields,
            sections: normalizedSections,
            columns: templateState.columns,
            methodResolver: getMethodName
        };

        const content = document.getElementById('preview-content');
        content.innerHTML = buildDocumentPreviewHtml(data);
        document.getElementById('preview-modal').classList.remove('hidden');
    }

    // ===== 이미지 업로드 =====
    function uploadSectionImage(sectionId, input) {
        const file = input.files[0];
        if (!file) return;

        const formData = new FormData();
        formData.append('image', file);

        showToast('이미지 업로드 중...', 'info');

        fetch('/api/admin/document-templates/upload-image', {
            method: 'POST',
            headers: {
                'X-CSRF-TOKEN': '{{ csrf_token() }}',
                'Accept': 'application/json'
            },
            body: formData
        })
        .then(response => response.json())
        .then(result => {
            if (result.success) {
                const section = templateState.sections.find(s => s.id ==sectionId);
                if (section) {
                    section.image_path = result.path;
                    renderSections();
                    showToast('이미지가 업로드되었습니다.', 'success');
                }
            } else {
                showToast(result.message || '이미지 업로드에 실패했습니다.', 'error');
            }
        })
        .catch(error => {
            console.error('Upload error:', error);
            showToast('이미지 업로드 중 오류가 발생했습니다.', 'error');
        });

        input.value = '';
    }

    function removeSectionImage(sectionId) {
        console.log('[removeSectionImage] called with sectionId:', sectionId);
        const section = templateState.sections.find(s => s.id == sectionId);
        console.log('[removeSectionImage] found section:', section ? section.id : 'NOT FOUND', 'image_path:', section?.image_path);
        if (section) {
            section.image_path = null;
            try {
                renderSections();
                showToast('이미지가 삭제되었습니다. 저장 버튼을 눌러 반영하세요.', 'info');
            } catch (e) {
                console.error('[removeSectionImage] renderSections error:', e);
                showToast('이미지 삭제 중 오류가 발생했습니다.', 'error');
            }
        } else {
            console.warn('[removeSectionImage] section not found for id:', sectionId);
        }
    }

    // ===== SortableJS 초기화 =====
    function initSortable() {
        // 섹션 정렬
        const sectionsContainer = document.getElementById('sections-container');
        if (sectionsContainer && typeof Sortable !== 'undefined') {
            new Sortable(sectionsContainer, {
                animation: 150,
                handle: '.drag-handle',
                onEnd: function(evt) {
                    const newOrder = [];
                    sectionsContainer.querySelectorAll('[data-section-id]').forEach((el, idx) => {
                        const sectionId = el.dataset.sectionId;
                        const section = templateState.sections.find(s => s.id ==sectionId);
                        if (section) newOrder.push(section);
                    });
                    templateState.sections = newOrder;
                }
            });
        }

        // 결재라인 정렬
        const approvalContainer = document.getElementById('approval-lines');
        if (approvalContainer && typeof Sortable !== 'undefined') {
            new Sortable(approvalContainer, {
                animation: 150,
                onEnd: function(evt) {
                    const newOrder = [];
                    approvalContainer.querySelectorAll('[data-id]').forEach((el) => {
                        const id = el.dataset.id;
                        const line = templateState.approval_lines.find(l => l.id ==id);
                        if (line) newOrder.push(line);
                    });
                    templateState.approval_lines = newOrder;
                }
            });
        }

        // 기본필드 정렬
        const basicFieldsContainer = document.getElementById('basic-fields-container');
        if (basicFieldsContainer && typeof Sortable !== 'undefined') {
            new Sortable(basicFieldsContainer, {
                animation: 150,
                onEnd: function(evt) {
                    const newOrder = [];
                    basicFieldsContainer.querySelectorAll('[data-bf-id]').forEach((el) => {
                        const id = el.dataset.bfId;
                        const field = templateState.basic_fields.find(f => f.id ==id);
                        if (field) newOrder.push(field);
                    });
                    templateState.basic_fields = newOrder;
                }
            });
        }

        // 컬럼 정렬
        const columnsContainer = document.getElementById('columns-container');
        if (columnsContainer && typeof Sortable !== 'undefined') {
            new Sortable(columnsContainer, {
                animation: 150,
                onEnd: function(evt) {
                    const newOrder = [];
                    columnsContainer.querySelectorAll('[data-column-id]').forEach((el) => {
                        const id = el.dataset.columnId;
                        const col = templateState.columns.find(c => c.id ==id);
                        if (col) newOrder.push(col);
                    });
                    templateState.columns = newOrder;
                }
            });
        }
    }

    // 렌더링 후 SortableJS 재초기화
    const originalRenderApprovalLines = renderApprovalLines;
    renderApprovalLines = function() {
        originalRenderApprovalLines();
        setTimeout(initSortable, 100);
    };

    const originalRenderBasicFields = renderBasicFields;
    renderBasicFields = function() {
        originalRenderBasicFields();
        setTimeout(initSortable, 100);
    };

    const originalRenderSections = renderSections;
    renderSections = function() {
        originalRenderSections();
        setTimeout(initSortable, 100);
    };

    const originalRenderColumns = renderColumns;
    renderColumns = function() {
        originalRenderColumns();
        setTimeout(initSortable, 100);
    };

    // 초기 SortableJS 로드
    document.addEventListener('DOMContentLoaded', function() {
        setTimeout(initSortable, 500);
    });

    // ===== 검색 드롭다운 닫기 =====
    document.addEventListener('click', function(e) {
        // 동적 연결 검색 결과 닫기
        if (!e.target.closest('[id^="link-search-"]') && !e.target.closest('[id^="link-results-"]')) {
            document.querySelectorAll('[id^="link-results-"]').forEach(el => el.classList.add('hidden'));
        }
        // 사용자 검색 결과 닫기
        if (!e.target.closest('[id^="user-search-"]') && !e.target.closest('[id^="user-results-"]')) {
            document.querySelectorAll('[id^="user-results-"]').forEach(el => el.classList.add('hidden'));
        }
    });

    // ===== 동적 필드 설정 =====
    const FIELD_TYPES = [
        { code: 'text', name: '텍스트' },
        { code: 'number', name: '숫자' },
        { code: 'select', name: '정적 드롭다운' },
        { code: 'select_api', name: 'API 드롭다운' },
        { code: 'json_tolerance', name: '공차 복합' },
        { code: 'json_criteria', name: '기준범위 복합' },
        { code: 'composite_frequency', name: '검사주기 복합' }
    ];

    function toggleFieldSettings() {
        const body = document.getElementById('field-settings-body');
        const arrow = document.getElementById('field-settings-arrow');
        body.classList.toggle('hidden');
        arrow.classList.toggle('rotate-180');
    }

    function initPresetSelect() {
        const select = document.getElementById('preset-select');
        if (!select) return;
        select.innerHTML = '<option value="">프리셋에서 가져오기...</option>';
        fieldPresets.forEach(p => {
            select.innerHTML += `<option value="${p.id}">${escapeHtml(p.name)}</option>`;
        });
    }

    function applyPreset() {
        const select = document.getElementById('preset-select');
        const presetId = parseInt(select.value);
        if (!presetId) return;
        const preset = fieldPresets.find(p => p.id === presetId);
        if (!preset) return;
        if (templateState.section_fields.length > 0) {
            if (!confirm('기존 필드 설정을 프리셋으로 대체하시겠습니까?')) return;
        }
        applyPresetData(preset);
    }

    function applyPresetData(preset) {
        // 필드 적용
        templateState.section_fields = (preset.fields || []).map((f, idx) => ({
            id: generateId(),
            field_key: f.field_key,
            label: f.label,
            field_type: f.field_type,
            options: f.options || null,
            width: f.width || '100px',
            is_required: f.is_required || false
        }));
        // 연결 적용
        if (preset.links) {
            templateState.template_links = preset.links.map((l, idx) => ({
                id: generateId(),
                link_key: l.link_key,
                label: l.label,
                link_type: l.link_type,
                source_table: l.source_table,
                search_params: l.search_params || null,
                display_fields: l.display_fields || null,
                is_required: l.is_required || false,
                values: []
            }));
        }
        renderSectionFields();
        populateLinkSourceTable();
        renderSections();
    }

    function addSectionField() {
        templateState.section_fields.push({
            id: generateId(),
            field_key: '',
            label: '',
            field_type: 'text',
            options: null,
            width: '100px',
            is_required: false
        });
        renderSectionFields();
    }

    function removeSectionField(id) {
        templateState.section_fields = templateState.section_fields.filter(f => f.id != id);
        renderSectionFields();
        renderSections();
    }

    function updateSectionField(id, key, value) {
        const field = templateState.section_fields.find(f => f.id == id);
        if (field) field[key] = value;
    }

    function renderSectionFields() {
        const container = document.getElementById('section-fields-container');
        if (!container) return;
        const label = document.getElementById('field-settings-label');
        if (label) label.textContent = `필드 설정 (${templateState.section_fields.length}개 필드)`;

        if (templateState.section_fields.length === 0) {
            container.innerHTML = '<p class="text-gray-400 text-center py-2 text-xs">필드가 없습니다. 프리셋을 적용하거나 직접 추가하세요.</p>';
            return;
        }

        container.innerHTML = templateState.section_fields.map((f, idx) => `
            <div class="flex items-center gap-2 p-2 bg-gray-50 rounded" data-sf-id="${f.id}">
                <span class="text-gray-400 font-bold cursor-move text-xs">⋮⋮</span>
                <span class="text-gray-400 text-xs w-5">${idx + 1}</span>
                <input type="text" value="${escapeHtml(f.field_key)}" placeholder="field_key"
                       onchange="updateSectionField('${f.id}', 'field_key', this.value)"
                       class="w-24 px-2 py-1 border border-gray-300 rounded text-xs">
                <input type="text" value="${escapeHtml(f.label)}" placeholder="표시명"
                       onchange="updateSectionField('${f.id}', 'label', this.value)"
                       class="w-20 px-2 py-1 border border-gray-300 rounded text-xs">
                <select onchange="updateSectionField('${f.id}', 'field_type', this.value)"
                        class="w-28 px-1 py-1 border border-gray-300 rounded text-xs">
                    ${FIELD_TYPES.map(ft => `<option value="${ft.code}" ${f.field_type === ft.code ? 'selected' : ''}>${ft.name}</option>`).join('')}
                </select>
                <input type="text" value="${escapeHtml(f.width)}" placeholder="너비"
                       onchange="updateSectionField('${f.id}', 'width', this.value)"
                       class="w-16 px-2 py-1 border border-gray-300 rounded text-xs">
                <label class="flex items-center gap-1 text-xs">
                    <input type="checkbox" ${f.is_required ? 'checked' : ''}
                           onchange="updateSectionField('${f.id}', 'is_required', this.checked)"
                           class="w-3 h-3">
                    필수
                </label>
                <button onclick="removeSectionField('${f.id}')" class="text-red-400 hover:text-red-600">
                    <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
                    </svg>
                </button>
            </div>
        `).join('');
    }

    // ===== 연결 설정 (소스테이블 1개 + 체크박스 다건 검색) =====
    let sourceTableOptions = [];
    let linkSearchTimer = null;
    let checkedItems = new Map(); // id → {id, title, subtitle}

    function getMainLink() {
        if (templateState.template_links.length === 0) return null;
        return templateState.template_links[0];
    }

    function ensureMainLink() {
        if (templateState.template_links.length === 0) {
            templateState.template_links.push({
                id: generateId(),
                link_key: '',
                label: '',
                link_type: 'multiple',
                source_table: '',
                search_params: null,
                display_fields: null,
                is_required: false,
                values: []
            });
        }
        return templateState.template_links[0];
    }

    async function loadSourceTableOptions() {
        try {
            const res = await fetch('/api/admin/source-tables');
            const json = await res.json();
            if (json.success) {
                sourceTableOptions = json.data;
            }
        } catch (e) {
            console.error('소스 테이블 목록 로드 실패:', e);
        }
    }

    function populateLinkSourceTable() {
        const select = document.getElementById('link-source-table');
        if (!select) return;

        const link = getMainLink();
        const currentValue = link ? link.source_table : '';

        let html = '<option value="">소스 테이블 선택</option>';
        sourceTableOptions.forEach(t => {
            html += `<option value="${t.key}" ${currentValue === t.key ? 'selected' : ''}>${escapeHtml(t.label || t.key)}</option>`;
        });
        select.innerHTML = html;

        // 직접 입력 필드 동기화
        const customInput = document.getElementById('link-source-table-custom');
        if (customInput) {
            const isKnown = currentValue && sourceTableOptions.find(t => t.key === currentValue);
            if (isKnown) {
                customInput.value = '';
                customInput.disabled = true;
            } else {
                customInput.disabled = false;
                customInput.value = currentValue || '';
            }
        }

        // link_type 동기화
        const typeSelect = document.getElementById('link-type');
        if (typeSelect && link) {
            typeSelect.value = link.link_type || 'multiple';
        }

        // 소스 테이블이 설정되어 있으면 검색 패널 표시 + 태그 렌더
        if (currentValue) {
            document.getElementById('link-search-panel')?.classList.remove('hidden');
            renderLinkValueTags();
        }
    }

    function onLinkSourceTableChange(value) {
        const link = ensureMainLink();
        const panel = document.getElementById('link-search-panel');
        const customInput = document.getElementById('link-source-table-custom');

        if (!value) {
            link.source_table = '';
            link.values = [];
            panel?.classList.add('hidden');
            if (customInput) { customInput.disabled = false; customInput.value = ''; }
            renderLinkValueTags();
            return;
        }

        link.source_table = value;
        link.values = [];
        link.link_key = value;
        if (customInput) { customInput.disabled = true; customInput.value = ''; }

        // 메타 정보 자동 설정
        const tableInfo = sourceTableOptions.find(t => t.key === value);
        if (tableInfo) {
            link.label = tableInfo.label || value;
            link.display_fields = { title: tableInfo.title_field, subtitle: tableInfo.subtitle_field };
        }

        panel?.classList.remove('hidden');
        checkedItems.clear();
        renderLinkValueTags();

        // 검색 초기화
        const searchInput = document.getElementById('link-search-input');
        if (searchInput) searchInput.value = '';
        document.getElementById('link-search-results')?.classList.add('hidden');
    }

    function onLinkSourceTableCustom(value) {
        const link = ensureMainLink();
        const panel = document.getElementById('link-search-panel');
        const select = document.getElementById('link-source-table');

        if (!value) {
            link.source_table = '';
            link.values = [];
            panel?.classList.add('hidden');
            if (select) select.value = '';
            renderLinkValueTags();
            return;
        }

        link.source_table = value;
        link.values = [];
        link.link_key = value;
        link.label = value;
        if (select) select.value = '';

        panel?.classList.remove('hidden');
        checkedItems.clear();
        renderLinkValueTags();

        const searchInput = document.getElementById('link-search-input');
        if (searchInput) searchInput.value = '';
        document.getElementById('link-search-results')?.classList.add('hidden');
    }

    function onLinkTypeChange(value) {
        const link = ensureMainLink();
        link.link_type = value;

        // 단일로 변경 시 첫 번째만 유지
        if (value === 'single' && link.values.length > 1) {
            link.values = [link.values[0]];
            renderLinkValueTags();
        }
    }

    async function searchLinkValues(linkId, query) {
        const link = getMainLink();
        if (!link || !link.source_table) return;

        clearTimeout(linkSearchTimer);
        const resultsEl = document.getElementById('link-search-results');
        if (!resultsEl) return;

        if (query.length < 1) {
            resultsEl.classList.add('hidden');
            document.getElementById('btn-add-checked')?.classList.add('hidden');
            checkedItems.clear();
            return;
        }

        linkSearchTimer = setTimeout(async () => {
            try {
                let url = `/api/admin/source-tables/${link.source_table}/search?q=${encodeURIComponent(query)}`;
                if (link.search_params) {
                    Object.entries(link.search_params).forEach(([k, v]) => {
                        url += `&${k}=${encodeURIComponent(v)}`;
                    });
                }
                const res = await fetch(url);
                const json = await res.json();
                if (json.success && json.data.length > 0) {
                    const titleField = json.meta.title_field;
                    const subtitleField = json.meta.subtitle_field;
                    const existingIds = (link.values || []).map(v => v.linkable_id || v.id);

                    checkedItems.clear();
                    resultsEl.innerHTML = json.data.map(item => {
                        const isLinked = existingIds.includes(item.id);
                        return `
                            <label class="flex items-center gap-2 px-3 py-1.5 hover:bg-blue-50 cursor-pointer text-xs border-b border-gray-100 ${isLinked ? 'bg-gray-50 opacity-60' : ''}">
                                <input type="checkbox" value="${item.id}"
                                       data-title="${escapeHtml(item[titleField] || '')}"
                                       data-subtitle="${escapeHtml(item[subtitleField] || '')}"
                                       onchange="onSearchCheckChange(this)"
                                       class="w-3.5 h-3.5 rounded text-blue-600"
                                       ${isLinked ? 'disabled checked' : ''}>
                                <div class="flex-1">
                                    <span class="font-medium">${escapeHtml(item[titleField] || '')}</span>
                                    ${item[subtitleField] ? `<span class="text-gray-400 ml-1">${escapeHtml(item[subtitleField] || '')}</span>` : ''}
                                </div>
                                ${isLinked ? '<span class="text-blue-500 text-[10px]">연결됨</span>' : ''}
                            </label>
                        `;
                    }).join('');
                    resultsEl.classList.remove('hidden');
                    updateAddCheckedButton();
                } else {
                    resultsEl.innerHTML = '<div class="px-3 py-2 text-xs text-gray-400">검색 결과 없음</div>';
                    resultsEl.classList.remove('hidden');
                    document.getElementById('btn-add-checked')?.classList.add('hidden');
                }
            } catch (e) {
                console.error('연결 검색 실패:', e);
            }
        }, 300);
    }

    function onSearchCheckChange(checkbox) {
        const id = parseInt(checkbox.value);
        if (checkbox.checked) {
            checkedItems.set(id, {
                id: id,
                title: checkbox.dataset.title,
                subtitle: checkbox.dataset.subtitle
            });
        } else {
            checkedItems.delete(id);
        }
        updateAddCheckedButton();
    }

    function updateAddCheckedButton() {
        const btn = document.getElementById('btn-add-checked');
        if (!btn) return;
        if (checkedItems.size > 0) {
            btn.classList.remove('hidden');
            btn.textContent = `선택 추가 (${checkedItems.size})`;
        } else {
            btn.classList.add('hidden');
        }
    }

    function addCheckedLinkValues() {
        const link = getMainLink();
        if (!link) return;
        if (!link.values) link.values = [];

        // 단일이면 마지막 체크만
        if (link.link_type === 'single') {
            const last = Array.from(checkedItems.values()).pop();
            if (last) {
                link.values = [{ linkable_id: last.id, display_text: last.title + (last.subtitle ? ` (${last.subtitle})` : '') }];
            }
        } else {
            checkedItems.forEach(item => {
                if (!link.values.find(v => (v.linkable_id || v.id) === item.id)) {
                    link.values.push({ linkable_id: item.id, display_text: item.title + (item.subtitle ? ` (${item.subtitle})` : '') });
                }
            });
        }

        checkedItems.clear();
        // 검색 결과 닫고 초기화
        document.getElementById('link-search-results')?.classList.add('hidden');
        document.getElementById('btn-add-checked')?.classList.add('hidden');
        document.getElementById('link-search-input').value = '';
        renderLinkValueTags();
    }

    function removeLinkValue(itemId) {
        const link = getMainLink();
        if (!link) return;
        link.values = (link.values || []).filter(v => (v.linkable_id || v.id) !== itemId);
        renderLinkValueTags();
    }

    function renderLinkValueTags() {
        const container = document.getElementById('link-value-tags');
        if (!container) return;
        const link = getMainLink();
        if (!link || !link.values || link.values.length === 0) {
            container.innerHTML = '';
            return;
        }

        container.innerHTML = link.values.map(v => `
            <span class="inline-flex items-center bg-blue-100 text-blue-700 text-xs px-2 py-0.5 rounded">
                ${escapeHtml(v.display_text || 'ID: ' + (v.linkable_id || v.id))}
                <button onclick="removeLinkValue(${v.linkable_id || v.id})" class="ml-1 text-blue-400 hover:text-blue-600">&times;</button>
            </span>
        `).join('');
    }

    // 페이지 로드 시 소스 테이블 옵션 로드
    loadSourceTableOptions().then(() => {
        populateLinkSourceTable();
    });

    // ===== 동적 필드 렌더링 (검사 기준서 셀) =====
    function getItemFieldValue(item, fieldKey) {
        // field_values 우선, 기존 컬럼 fallback
        if (item.field_values && item.field_values[fieldKey] !== undefined && item.field_values[fieldKey] !== null) {
            return item.field_values[fieldKey];
        }
        return item[fieldKey] ?? null;
    }

    function updateDynamicField(sectionId, itemId, fieldKey, value) {
        const section = templateState.sections.find(s => s.id == sectionId);
        if (!section) return;
        const item = section.items.find(i => i.id == itemId);
        if (!item) return;
        // 기존 컬럼에도 업데이트 (하위 호환)
        item[fieldKey] = value;
        // field_values에도 업데이트
        if (!item.field_values || Array.isArray(item.field_values)) item.field_values = {};
        item.field_values[fieldKey] = value;
    }

    function calcTableWidth() {
        let width = 30; // 삭제 버튼 컬럼
        templateState.section_fields.forEach(f => {
            width += parseInt(f.width) || 100;
        });
        return Math.max(width, 600);
    }

    // 참조속성 업데이트
    function updateReferenceAttribute(sectionId, itemId, value) {
        const section = templateState.sections.find(s => s.id == sectionId);
        if (!section) return;
        const item = section.items.find(i => i.id == itemId);
        if (!item) return;
        if (!item.field_values || Array.isArray(item.field_values)) item.field_values = {};
        item.field_values.reference_attribute = value || null;
    }

    function renderDynamicFieldInput(field, sectionId, item) {
        const val = getItemFieldValue(item, field.field_key);
        const fk = field.field_key;
        const sid = sectionId;
        const iid = item.id;

        switch (field.field_type) {
            case 'text':
                return `<input type="text" value="${escapeHtml(val || '')}" placeholder="${escapeHtml(field.label)}"
                               onchange="updateDynamicField('${sid}', '${iid}', '${fk}', this.value)"
                               class="w-full px-2 py-1 border border-gray-200 rounded text-xs">`;

            case 'number':
                return `<input type="number" step="any" value="${val ?? ''}" placeholder="${escapeHtml(field.label)}"
                               onchange="updateDynamicField('${sid}', '${iid}', '${fk}', this.value ? parseFloat(this.value) : null)"
                               class="w-full px-2 py-1 border border-gray-200 rounded text-xs">`;

            case 'select': {
                const choices = field.options?.choices || [];
                return `<select onchange="updateDynamicField('${sid}', '${iid}', '${fk}', this.value)"
                                class="w-full px-1 py-1 border border-gray-200 rounded text-xs">
                            <option value="">선택</option>
                            ${choices.map(c => `<option value="${c.code}" ${val === c.code ? 'selected' : ''}>${escapeHtml(c.name)}</option>`).join('')}
                        </select>`;
            }

            case 'select_api': {
                // API 드롭다운 - 검사방식 등 비동기 로드된 데이터 사용
                const autoMap = field.options?.auto_map;
                if (autoMap) {
                    return `<select onchange="onMethodChange('${sid}', '${iid}', this.value)"
                                    class="w-full px-1 py-1 border border-gray-200 rounded text-xs">
                                <option value="">선택</option>
                                ${inspectionMethods.map(m => `<option value="${m.code}" ${val === m.code ? 'selected' : ''}>${escapeHtml(m.name)}</option>`).join('')}
                            </select>`;
                }
                return `<input type="text" value="${escapeHtml(val || '')}" placeholder="${escapeHtml(field.label)}"
                               onchange="updateDynamicField('${sid}', '${iid}', '${fk}', this.value)"
                               class="w-full px-2 py-1 border border-gray-200 rounded text-xs">`;
            }

            case 'json_tolerance':
                return renderToleranceInput(sid, iid, val || item.tolerance);

            case 'text_with_criteria': {
                // 상단: 참조속성 + 검사기준 텍스트, 하단: 기준범위 min/max
                const c = getItemFieldValue(item, 'standard_criteria') || item.standard_criteria;
                const refAttr = (item.field_values && item.field_values.reference_attribute) || '';
                return `<div class="flex flex-col gap-1">
                            <div class="flex gap-1">
                                <select onchange="updateReferenceAttribute('${sid}', '${iid}', this.value)"
                                        class="px-1 py-1 border border-gray-200 rounded text-xs flex-shrink-0" style="width:72px"
                                        title="참조속성">
                                    <option value="" ${!refAttr ? 'selected' : ''}>기준치수</option>
                                    <option value="thickness" ${refAttr === 'thickness' ? 'selected' : ''}>두께</option>
                                    <option value="width" ${refAttr === 'width' ? 'selected' : ''}>너비</option>
                                    <option value="length" ${refAttr === 'length' ? 'selected' : ''}>길이</option>
                                </select>
                                <input type="text" value="${escapeHtml(val || '')}" placeholder="검사기준"
                                       onchange="updateDynamicField('${sid}', '${iid}', '${fk}', this.value)"
                                       class="flex-1 min-w-0 px-2 py-1 border border-gray-200 rounded text-xs">
                            </div>
                            <div style="display:grid;grid-template-columns:1fr auto 8px 1fr auto;align-items:center;gap:2px">
                                <input type="number" step="any" value="${c?.min ?? ''}" placeholder="min"
                                       onchange="updateStandardCriteria('${sid}', '${iid}', 'min', this.value)"
                                       class="w-full px-1 py-0.5 border border-gray-200 rounded text-xs text-center">
                                <select onchange="updateStandardCriteria('${sid}', '${iid}', 'min_op', this.value)"
                                        class="py-0.5 border border-gray-200 rounded text-xs" style="min-width:48px;padding-left:2px;padding-right:2px">
                                    <option value="gte" ${(c?.min_op || 'gte') === 'gte' ? 'selected' : ''}>이상</option>
                                    <option value="gt" ${c?.min_op === 'gt' ? 'selected' : ''}>초과</option>
                                </select>
                                <span class="text-xs text-gray-400 text-center">~</span>
                                <input type="number" step="any" value="${c?.max ?? ''}" placeholder="max"
                                       onchange="updateStandardCriteria('${sid}', '${iid}', 'max', this.value)"
                                       class="w-full px-1 py-0.5 border border-gray-200 rounded text-xs text-center">
                                <select onchange="updateStandardCriteria('${sid}', '${iid}', 'max_op', this.value)"
                                        class="py-0.5 border border-gray-200 rounded text-xs" style="min-width:48px;padding-left:2px;padding-right:2px">
                                    <option value="lte" ${(c?.max_op || 'lte') === 'lte' ? 'selected' : ''}>이하</option>
                                    <option value="lt" ${c?.max_op === 'lt' ? 'selected' : ''}>미만</option>
                                </select>
                            </div>
                        </div>`;
            }

            case 'composite_frequency': {
                const freq = val || item.frequency || '';
                const fn = item.frequency_n ?? getItemFieldValue(item, 'frequency_n');
                const fc = item.frequency_c ?? getItemFieldValue(item, 'frequency_c');
                return `<input type="text" value="${escapeHtml(freq)}" placeholder="주기"
                               onchange="updateDynamicField('${sid}', '${iid}', 'frequency', this.value)"
                               class="w-full px-2 py-1 border border-gray-200 rounded text-xs mb-1">
                        <div class="flex items-center gap-0.5">
                            <span class="text-xs text-gray-500">n=</span>
                            <input type="number" value="${fn ?? ''}" min="1"
                                   onchange="updateDynamicField('${sid}', '${iid}', 'frequency_n', this.value ? parseInt(this.value) : null)"
                                   class="w-10 px-1 py-0.5 border border-gray-200 rounded text-xs text-center">
                            <span style="width:10px;"></span>
                            <span class="text-xs text-gray-500">c=</span>
                            <input type="number" value="${fc ?? ''}" min="0"
                                   onchange="updateDynamicField('${sid}', '${iid}', 'frequency_c', this.value ? parseInt(this.value) : null)"
                                   class="w-10 px-1 py-0.5 border border-gray-200 rounded text-xs text-center">
                        </div>`;
            }

            default:
                return `<input type="text" value="${escapeHtml(val || '')}" placeholder="${escapeHtml(field.label)}"
                               onchange="updateDynamicField('${sid}', '${iid}', '${fk}', this.value)"
                               class="w-full px-2 py-1 border border-gray-200 rounded text-xs">`;
        }
    }

    // ===== 유틸리티 =====
    function getSectionImageUrl(imagePath) {
        if (!imagePath) return '';
        if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) return imagePath;
        // 새 API 업로드 형식 (tenant path: 1/temp/2026/02/xxx.jpg)
        if (/^\d+\//.test(imagePath)) {
            return 'http://api.sam.kr/storage/tenants/' + imagePath;
        }
        // 레거시 형식 (document-templates/xxx.jpg) - MNG 로컬 스토리지
        return '/storage/' + imagePath;
    }

    function escapeHtml(text) {
        if (!text) return '';
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    function formatStandard(item) {
        const c = item.standard_criteria;
        if (c && (c.min != null || c.max != null)) {
            const opLabel = { gte: '이상', gt: '초과', lte: '이하', lt: '미만' };
            const parts = [];
            if (c.min != null) parts.push(`${c.min} ${opLabel[c.min_op || 'gte']}`);
            if (c.max != null) parts.push(`${c.max} ${opLabel[c.max_op || 'lte']}`);
            return parts.join(' ~ ');
        }
        let std = item.standard || '-';
        const tolStr = formatTolerance(item.tolerance);
        if (tolStr !== '-') std += ' (' + tolStr + ')';
        return escapeHtml(std);
    }

    function formatFrequency(item) {
        const parts = [];
        if (item.frequency_n != null && item.frequency_n !== '') {
            let nc = `n=${item.frequency_n}`;
            if (item.frequency_c != null && item.frequency_c !== '') {
                nc += `, c=${item.frequency_c}`;
            }
            parts.push(nc);
        }
        if (item.frequency) {
            parts.push(escapeHtml(item.frequency));
        }
        return parts.length > 0 ? parts.join(' / ') : '-';
    }
</script>

<!-- SortableJS CDN -->
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
@endpush
