<template>
  <div class="admin--page-content">
    <div class="admin--form">
      <form @submit.prevent="handleSubmit">

        <!-- ============================
             챌린지 기본 정보
        ============================ -->
        <table class="admin--form--table">
          <colgroup>
            <col style="width: 140px;">
            <col>
          </colgroup>
          <tbody>
            <tr>
              <th><div>챌린지명 <span class="admin--required">*</span></div></th>
              <td>
                <div class="input--wrap">
                  <input v-model="formData.name" type="text" class="w--full admin--form-input" placeholder="예: 동해안 왕대구 선상낚시대회" required />
                </div>
              </td>
            </tr>
            <tr>
              <th><div>참가비 <span class="admin--required">*</span></div></th>
              <td>
                <div class="input--wrap">
                  <input
                    v-model="formData.fee"
                    type="number"
                    min="0"
                    class="admin--form-input w--200"
                    :placeholder="isFree ? '0 (무료)' : '예: 10000'"
                    :disabled="isFree"
                    required
                  />
                  <span>원</span>
                  <label class="admin--radio-label ml--16">
                    <input type="checkbox" v-model="isFree" @change="onFreeChange" /> 무료
                  </label>
                </div>
              </td>
            </tr>
            <tr>
              <th><div>기간 <span class="admin--required">*</span></div></th>
              <td>
                <div class="input--wrap">
                  <DatePicker v-model="startDate" placeholder="📅 YYYY-MM-DD" />
                  <span class="admin--date-separator">-</span>
                  <DatePicker v-model="endDate" placeholder="📅 YYYY-MM-DD" />
                </div>
              </td>
            </tr>
            <tr>
              <th><div>최대 참가자 <span class="admin--required">*</span></div></th>
              <td>
                <div class="input--wrap">
                  <input v-model="formData.max_participants" type="number" min="100" max="999999" class="admin--form-input w--120" placeholder="100 ~ 999999" required />
                  <span>명</span>
                </div>
              </td>
            </tr>
            <tr>
              <th><div>타이틀 이미지</div></th>
              <td>
                <div class="input--wrap">
                  <input
                    ref="imageInput"
                    type="file"
                    accept="image/*"
                    class="admin--form-file-hidden"
                    @change="onImageChange"
                  />
                  <button type="button" class="admin--btn-small admin--btn-blue" @click="triggerImageInput">
                    {{ existingImagePath || image ? '이미지 변경' : '이미지 선택' }}
                  </button>
                  <span v-if="image" class="ml--16">{{ image.file.name }} (신규)</span>
                  <span v-else-if="existingImagePath" class="ml--16">{{ existingImageName || '기존 이미지' }}</span>
                  <button
                    v-if="existingImagePath && !image"
                    type="button"
                    class="admin--btn-small admin--btn-red ml--8"
                    @click="removeExistingImage"
                  >
                    이미지 제거
                  </button>
                </div>
                <p class="mt--10">권장 1200x800, JPG/PNG/GIF/WebP, 5MB 이하 (선택 사항)</p>

                <!-- 신규 이미지 미리보기 (있으면 우선) -->
                <div v-if="image" class="onboard--photo-grid mt--10">
                  <div class="onboard--photo-item">
                    <img :src="image.preview" alt="신규 미리보기" />
                    <button type="button" class="onboard--photo-remove" @click="removeImage"></button>
                  </div>
                </div>
                <!-- 신규 없으면 기존 이미지 -->
                <div v-else-if="existingImagePath" class="onboard--photo-grid mt--10">
                  <div class="onboard--photo-item">
                    <img :src="getImageUrl(existingImagePath)" alt="기존 이미지" />
                  </div>
                </div>
              </td>
            </tr>
            <tr>
              <th><div>상태 <span class="admin--required">*</span></div></th>
              <td>
                <div class="input--wrap">
                  <label class="admin--radio-label">
                    <input type="radio" v-model="formData.status_YN" value="Y" /> 사용중
                  </label>
                  <label class="admin--radio-label ml--16">
                    <input type="radio" v-model="formData.status_YN" value="N" /> 미사용
                  </label>
                </div>
              </td>
            </tr>
            <tr>
              <th><div>상세내용</div></th>
              <td>
                <ClientOnly>
                  <SunEditor
                    v-model="formData.description"
                    height="400px"
                    placeholder="챌린지 상세 설명을 입력하세요. (참가 방법ㆍ규칙ㆍ유의사항 등)"
                  />
                </ClientOnly>
              </td>
            </tr>
          </tbody>
        </table>

        <!-- ============================
             라운드 설정
        ============================ -->
        <h3 class="admin--table--middle--title">라운드 설정</h3>
        <p class="admin--table--middle--desc">
          라운드별로 장소 범위(전체/개별)를 선택하고, 장소마다 아이템을 배정합니다. 최대 5라운드까지 등록할 수 있습니다.
        </p>

        <div
          v-for="(round, rIdx) in rounds"
          :key="round._key"
          class="admin--round--box--wrap"
          :class="{ 'mt--16': rIdx > 0 }"
        >
          <div class="admin--round--title">
            라운드 {{ round.round_no }}
            <span v-if="round.place_mode === 'all'">전체 장소ㆍ아이템 {{ round.items.length }}</span>
            <span v-else>개별 장소 {{ round.places.length }}</span>
            <!-- 최소 2라운드 이상. 3라운드부터 라운드 삭제 버튼 노출 -->
            <button
              v-if="rounds.length > 2"
              type="button"
              class="round--remove--btn"
              @click="removeRound(rIdx)"
            >
              라운드 삭제
            </button>
          </div>

          <div class="admin--round--box">
            <div class="input--wrap mt--16">
              <label class="admin--round--radio">
                <input
                  type="radio"
                  :name="'place_mode_' + round._key"
                  value="all"
                  :checked="round.place_mode === 'all'"
                  @change="changePlaceMode(round, 'all')"
                />
                전체 장소에 동일 적용
              </label>
              <label class="admin--round--radio">
                <input
                  type="radio"
                  :name="'place_mode_' + round._key"
                  value="specific"
                  :checked="round.place_mode === 'specific'"
                  @change="changePlaceMode(round, 'specific')"
                />
                장소별 개별 설정
              </label>
            </div>

            <div class="qual--wrap">
              <p class="mt--16 mb--4">진출자 {{ rIdx === 0 ? '인원' : '확률' }}</p>
              <div class="input--wrap">
                <input
                  v-model="round.qualified"
                  type="number"
                  min="1"
                  class="admin--form-input w--120"
                  :placeholder="rIdx === 0 ? '예: 30' : '예: 50'"
                  required
                />
                <!-- 1라운드 단위 : 명, 그 외 라운드 단위 : % -->
                <span>{{ rIdx === 0 ? '명' : '%' }}</span>
              </div>
            </div>

            <!-- 전체 적용 모드 — 라운드 단위 아이템 -->
            <div v-if="round.place_mode === 'all'" class="item--select--wrap">
              <div class="item--select--btn--wrap mt--16 mb--4">
                <p>배정 아이템ㆍ수량 {{ round.items.length }}</p>
                <button type="button" @click="openItemModal(round)">+ 아이템 선택</button>
              </div>
              <div class="item--selected--wrap">
                <div v-for="(it, iIdx) in round.items" :key="it.item_id" class="item--selected">
                  {{ it.name }}<button type="button" @click="round.items.splice(iIdx, 1)">✕</button>
                </div>
              </div>
            </div>

            <!-- 장소별 개별 설정 모드 -->
            <template v-else>
              <div
                v-for="(place, pIdx) in round.places"
                :key="place._key"
                class="round--place--wrap"
              >
                <div class="admin--round--title">
                  장소 {{ pIdx + 1 }}
                  <button
                    type="button"
                    class="place--remove--btn"
                    @click="removePlace(round, pIdx)"
                  >✕</button>
                </div>

                <div class="place--select--wrap">
                  <p class="mb--4">장소 정의</p>

                  <!-- 분야/지역/제휴 셀렉트 — 항상 노출 -->
                  <div class="input--wrap">
                    <select v-model="place.field_id" class="admin--form-select">
                      <option value="">전체 분야</option>
                      <option v-for="f in fieldOptions" :key="f.id" :value="f.id">{{ f.name }}</option>
                    </select>
                    <select v-model="place.area_id" class="admin--form-select">
                      <option value="">전체 지역</option>
                      <option v-for="a in areaOptions" :key="a.id" :value="a.id">{{ a.name }}</option>
                    </select>
                    <select v-model="place.partnership_YN" class="admin--form-select">
                      <option value="">제휴 여부</option>
                      <option value="Y">제휴</option>
                      <option value="N">비제휴</option>
                    </select>

                    <!-- 장소 미선택 시: "장소 선택" 버튼 + 드롭다운 -->
                    <div v-if="place.onboards.length === 0" class="place--select--btn--wrap">
                      <button
                        type="button"
                        class="admin--form-select"
                        @click.stop="openDropdown(place)"
                      >
                        장소 선택
                      </button>
                      <div
                        v-if="place.dropdownOpen"
                        class="all--place--wrap"
                        @click.stop
                      >
                        <div class="place--top">
                          <div class="search--wrap">
                            <input v-model="place.searchKeyword" type="text" placeholder="선상ㆍ낚시터명 검색">
                          </div>
                          <div class="check--wrap">
                            <label>
                              <input
                                type="checkbox"
                                :checked="isAllFilteredSelected(place)"
                                @change="toggleAll(place)"
                              >
                              전체
                              <span>조건의 모든 장소에 적용</span>
                            </label>
                          </div>
                          <div class="all--place">
                            <p>등록된 선상ㆍ낚시터</p>
                            <ul class="all--place--list mt--6">
                              <template v-for="group in groupedFilteredPlaces(place)" :key="group.area">
                                <p class="group--header">
                                  {{ group.area }}
                                  <button
                                    type="button"
                                    @click="toggleAllInGroup(place, group.items)"
                                  >
                                    {{ isAllInGroupSelected(place, group.items) ? '그룹 해제' : '그룹 전체 선택' }}
                                  </button>
                                </p>
                                <li v-for="p in group.items" :key="placeKey(p)">
                                  <label>
                                    <input
                                      type="checkbox"
                                      :checked="place.tempSelected.includes(placeKey(p))"
                                      @change="togglePlaceInTemp(place, placeKey(p))"
                                    >
                                    <span>{{ p._placeType === 'onboard' ? '🚤' : '🎣' }} {{ p.name }}</span>
                                    <span :class="p.partnership_YN === 'Y' ? 'on' : 'off'">
                                      {{ p.partnership_YN === 'Y' ? '제휴' : '비제휴' }}
                                    </span>
                                    <p>{{ p.field_name || '-' }}</p>
                                  </label>
                                </li>
                              </template>
                              <li v-if="filteredPlaces(place).length === 0" class="empty">
                                조건에 맞는 장소가 없습니다.
                              </li>
                            </ul>
                          </div>
                        </div>
                        <div class="place--bot">
                          <p>{{ place.tempSelected.length }}개 선택</p>
                          <button type="button" @click="applyDropdown(place)">적용</button>
                        </div>
                      </div>
                    </div>
                  </div>

                  <!-- 장소 선택 후 — 별도 영역에 "선상ㆍ낚시터 복수 선택" + 칩 -->
                  <template v-if="place.onboards.length > 0">
                    <p class="mt--16 mb--4">선상ㆍ낚시터 복수 선택</p>
                    <div class="place--select--btn--wrap">
                      <div
                        class="admin--form-select"
                        @click.stop="openDropdown(place)"
                      >
                        <div
                          v-for="chip in displayChips(place).slice(0, 2)"
                          :key="chip.key"
                          class="place--selected"
                          :class="{ 'is-group': chip.type === 'group' }"
                        >
                          {{ chip.icon }} {{ chip.label }}
                          <button
                            type="button"
                            @click.stop="removeChipFromPlace(place, chip)"
                          >✕</button>
                        </div>
                        <div v-if="displayChips(place).length > 2" class="place--selected">
                          + {{ displayChips(place).length - 2 }}
                        </div>
                      </div>

                      <div
                        v-if="place.dropdownOpen"
                        class="all--place--wrap"
                        @click.stop
                      >
                        <div class="place--top">
                          <div class="search--wrap">
                            <input v-model="place.searchKeyword" type="text" placeholder="선상ㆍ낚시터명 검색">
                          </div>
                          <div class="check--wrap">
                            <label>
                              <input
                                type="checkbox"
                                :checked="isAllFilteredSelected(place)"
                                @change="toggleAll(place)"
                              >
                              전체
                              <span>조건의 모든 장소에 적용</span>
                            </label>
                          </div>
                          <div class="all--place">
                            <p>등록된 선상ㆍ낚시터</p>
                            <ul class="all--place--list mt--6">
                              <template v-for="group in groupedFilteredPlaces(place)" :key="group.area">
                                <p class="group--header">
                                  {{ group.area }}
                                  <button
                                    type="button"
                                    @click="toggleAllInGroup(place, group.items)"
                                  >
                                    {{ isAllInGroupSelected(place, group.items) ? '그룹 해제' : '그룹 전체 선택' }}
                                  </button>
                                </p>
                                <li v-for="p in group.items" :key="placeKey(p)">
                                  <label>
                                    <input
                                      type="checkbox"
                                      :checked="place.tempSelected.includes(placeKey(p))"
                                      @change="togglePlaceInTemp(place, placeKey(p))"
                                    >
                                    <span>{{ p._placeType === 'onboard' ? '🚤' : '🎣' }} {{ p.name }}</span>
                                    <span :class="p.partnership_YN === 'Y' ? 'on' : 'off'">
                                      {{ p.partnership_YN === 'Y' ? '제휴' : '비제휴' }}
                                    </span>
                                    <p>{{ p.field_name || '-' }}</p>
                                  </label>
                                </li>
                              </template>
                              <li v-if="filteredPlaces(place).length === 0" class="empty">
                                조건에 맞는 장소가 없습니다.
                              </li>
                            </ul>
                          </div>
                        </div>
                        <div class="place--bot">
                          <p>{{ place.tempSelected.length }}개 선택</p>
                          <button type="button" @click="applyDropdown(place)">적용</button>
                        </div>
                      </div>
                    </div>
                  </template>
                </div>

                <!-- 장소별 아이템 -->
                <div class="item--select--wrap">
                  <div class="item--select--btn--wrap mb--4 mt--16">
                    <p>배정 아이템ㆍ수량 {{ place.items.length }}</p>
                    <button type="button" @click="openItemModal(place)">+ 아이템 선택</button>
                  </div>
                  <div class="item--selected--wrap">
                    <div v-for="(it, iIdx) in place.items" :key="it.item_id" class="item--selected">
                      {{ it.name }}<button type="button" @click="place.items.splice(iIdx, 1)">✕</button>
                    </div>
                  </div>
                </div>
              </div>

              <button type="button" class="place--add--btn" @click="addPlace(round)">
                + 장소 추가
              </button>
            </template>
          </div>
        </div>

        <button
          v-if="rounds.length < 5"
          type="button"
          class="round--add--btn"
          @click="addRound"
        >
          + 라운드 추가 (최대 5라운드)
        </button>

        <!-- 버튼 영역 -->
        <div class="admin--form-actions">
          <button type="button" class="admin--btn" @click="goToDetail">
            ← 취소
          </button>
          <button type="submit" class="admin--btn admin--btn-red ml--auto" :disabled="isSaving || isLoading">
            {{ isSaving ? "저장 중..." : "수정 저장" }}
          </button>
        </div>

        <!-- 성공/에러 메시지 -->
        <div v-if="successMessage" class="admin--alert admin--alert-success">
          {{ successMessage }}
        </div>
        <div v-if="errorMessage" class="admin--alert admin--alert-error">
          {{ errorMessage }}
        </div>
      </form>
    </div>

    <!-- ============================
         아이템 선택 모달
    ============================ -->
    <ClientOnly>
      <Teleport to="body">
        <div
          v-if="itemModal.isOpen"
          class="admin--modal-overlay admin--alert-overlay"
          @click.self="closeItemModal"
        >
          <div class="admin--modal admin--form-modal admin--item-modal" @click.stop>
            <div class="admin--modal-header">
              <h4>아이템 선택</h4>
              <button type="button" class="admin--modal-close" @click="closeItemModal">✕</button>
            </div>
            <div class="admin--modal-body">
              <div class="admin--item-modal__search mb--16">
                <input
                  v-model="itemModal.searchKeyword"
                  type="text"
                  class="admin--form-input w--full"
                  placeholder="🔍 아이템명 검색"
                />
              </div>

              <ul v-if="filteredItems().length > 0" class="admin--item-modal__grid">
                <li
                  v-for="it in filteredItems()"
                  :key="it.id"
                  class="admin--item-modal__card"
                  :class="{ 'is-selected': itemModal.tempSelected.includes(it.id) }"
                >
                  <label>
                    <input
                      type="checkbox"
                      :checked="itemModal.tempSelected.includes(it.id)"
                      @change="toggleItemInModal(it.id)"
                    />
                    <div class="admin--item-modal__thumb">
                      <img
                        v-if="it.file_path"
                        :src="getImageUrl(it.file_path)"
                        :alt="it.name"
                      />
                      <div v-else class="admin--item-modal__no-img">🎁</div>
                    </div>
                    <div class="admin--item-modal__name">{{ it.name }}</div>
                    <div class="admin--item-modal__meta">
                      <span v-if="it.type" class="admin--item-modal__type">{{ it.type == 'B' ? '뱃지' : it.type == 'P' ? '포인트' : '진출권' }}</span>
                      <span v-if="it.point !== null && it.point !== undefined" class="admin--item-modal__point">{{ it.point }}P</span>
                    </div>
                  </label>
                </li>
              </ul>

              <div v-else class="admin--item-modal__empty">
                {{ itemModal.searchKeyword ? '검색 결과가 없습니다.' : '등록된 아이템이 없습니다.' }}
              </div>
            </div>
            <div class="admin--modal-footer">
              <span class="admin--item-modal__count mr--auto">{{ itemModal.tempSelected.length }}개 선택</span>
              <button type="button" class="admin--btn" @click="closeItemModal">취소</button>
              <button type="button" class="admin--btn admin--btn-primary-fill ml--8" @click="applyItemModal">적용</button>
            </div>
          </div>
        </div>
      </Teleport>
    </ClientOnly>
  </div>
</template>

<script setup>
  import { ref, onMounted, onBeforeUnmount } from "vue";
  import { useRoute, useRouter } from "vue-router";
  import DatePicker from "~/components/admin/DatePicker.vue";
  import SunEditor from "~/components/admin/SunEditor.vue";

  definePageMeta({
    layout: "admin",
    middleware: ["auth"],
  });

  const route = useRoute();
  const router = useRouter();
  const { get, put, del, upload } = useApi();
  const { getImageUrl } = useImage();

  const challengeId = Number(route.params.id);

  const isLoading = ref(false);
  const isSaving = ref(false);
  const successMessage = ref("");
  const errorMessage = ref("");

  // ============================
  // 옵션 데이터
  // ============================
  const fieldOptions = ref([]);
  const areaOptions = ref([]);
  const placesAll = ref([]);   // 검색용 전체 장소 (선상 + 낚시터, _placeType 필드로 구분)
  const itemsAll = ref([]);    // 아이템 모달용 전체 아이템

  // ============================
  // 챌린지 기본 정보
  // ============================
  const formData = ref({
    name: "",
    fee: "",
    max_participants: "",
    status_YN: "Y",
    description: "",
  });
  const startDate = ref("");
  const endDate = ref("");
  const isFree = ref(false);

  // 무료 체크박스 토글
  const onFreeChange = () => {
    if (isFree.value) {
      formData.value.fee = "0";
    } else {
      formData.value.fee = "";
    }
  };

  // ============================
  // 이미지 업로드 (기존 + 신규)
  // ============================
  const imageInput = ref(null);
  const image = ref(null);                  // 신규 업로드 (file + preview)
  const existingImagePath = ref(null);      // 기존 file_path
  const existingImageName = ref(null);      // 기존 file_name
  const MAX_IMAGE_SIZE = 5 * 1024 * 1024;

  const triggerImageInput = () => imageInput.value?.click();

  const onImageChange = (e) => {
    const file = (e.target.files || [])[0];
    e.target.value = "";
    if (!file) return;
    if (!file.type.startsWith("image/")) {
      errorMessage.value = "이미지 파일만 업로드할 수 있습니다.";
      return;
    }
    if (file.size > MAX_IMAGE_SIZE) {
      errorMessage.value = "이미지가 5MB를 초과합니다.";
      return;
    }
    if (image.value) URL.revokeObjectURL(image.value.preview);
    image.value = { file, preview: URL.createObjectURL(file) };
  };

  const removeImage = () => {
    if (image.value) {
      URL.revokeObjectURL(image.value.preview);
      image.value = null;
    }
  };

  // ============================
  // 라운드/장소 동적 배열
  // ============================
  let _keySeq = 0;
  const nextKey = () => ++_keySeq;

  function createPlace() {
    return {
      _key: nextKey(),
      field_id: "",
      area_id: "",
      partnership_YN: "",
      onboards: [],       // 적용된 장소 키 배열 (예: 'onboard-1', 'fishing-3')
      items: [],          // [{ item_id, name, qty }] — Phase 2
      // UI 상태
      dropdownOpen: false,
      searchKeyword: "",
      tempSelected: [],   // 드롭다운 내 임시 체크 (장소 키 배열)
    };
  }
  function createRound(no) {
    return {
      _key: nextKey(),
      round_no: no,
      place_mode: "all",
      qualified: "",
      items: [],          // [{ item_id, name, qty }] — Phase 2
      places: [],
    };
  }

  const rounds = ref([createRound(1), createRound(2)]);

  function renumberRounds() {
    rounds.value.forEach((r, i) => { r.round_no = i + 1; });
  }

  function addRound() {
    if (rounds.value.length >= 5) return;
    rounds.value.push(createRound(rounds.value.length + 1));
  }
  function removeRound(idx) {
    if (rounds.value.length <= 2) return;
    rounds.value.splice(idx, 1);
    renumberRounds();
  }
  function changePlaceMode(round, mode) {
    round.place_mode = mode;
    // specific 으로 전환했는데 장소가 없으면 자동으로 장소 1 생성
    if (mode === "specific" && round.places.length === 0) {
      round.places.push(createPlace());
    }
  }
  function addPlace(round) {
    round.places.push(createPlace());
  }
  function removePlace(round, idx) {
    round.places.splice(idx, 1);
    // specific 모드인데 장소가 0개면 자동으로 1개 다시 추가 (또는 all 모드로 되돌리기 — 여기선 하나 자동 추가)
    if (round.places.length === 0) {
      round.places.push(createPlace());
    }
  }

  // ============================
  // 장소(선상+낚시터) 검색 드롭다운
  // ============================
  // 장소 키 헬퍼: 'onboard-1', 'fishing-2' 형태로 고유 식별
  const placeKey = (p) => `${p._placeType}-${p.id}`;
  const placeByKey = (k) => placesAll.value.find((p) => placeKey(p) === k);
  const placeNameByKey = (k) => placeByKey(k)?.name || "?";
  const placeTypeByKey = (k) => (k && k.startsWith("fishing-")) ? "fishing" : "onboard";

  function closeAllDropdowns() {
    rounds.value.forEach((r) =>
      r.places.forEach((p) => { p.dropdownOpen = false; })
    );
  }

  function openDropdown(place) {
    closeAllDropdowns();
    place.tempSelected = [...place.onboards];
    place.dropdownOpen = true;
  }

  function filteredPlaces(place) {
    return placesAll.value.filter((p) => {
      if (place.field_id && String(p.field_id) !== String(place.field_id)) return false;
      if (place.area_id && String(p.area_id) !== String(place.area_id)) return false;
      if (place.partnership_YN && p.partnership_YN !== place.partnership_YN) return false;
      if (place.searchKeyword) {
        const kw = place.searchKeyword.toLowerCase();
        if (!String(p.name || "").toLowerCase().includes(kw)) return false;
      }
      return true;
    });
  }

  function togglePlaceInTemp(place, key) {
    const idx = place.tempSelected.indexOf(key);
    if (idx === -1) place.tempSelected.push(key);
    else place.tempSelected.splice(idx, 1);
  }

  function isAllFilteredSelected(place) {
    const filtered = filteredPlaces(place);
    if (filtered.length === 0) return false;
    return filtered.every((p) => place.tempSelected.includes(placeKey(p)));
  }

  function toggleAll(place) {
    const filtered = filteredPlaces(place);
    const filteredKeys = filtered.map(placeKey);
    if (isAllFilteredSelected(place)) {
      const set = new Set(filteredKeys);
      place.tempSelected = place.tempSelected.filter((k) => !set.has(k));
    } else {
      const merged = new Set([...place.tempSelected, ...filteredKeys]);
      place.tempSelected = [...merged];
    }
  }

  // 지역별 그룹화: [{area, items: [...]}, ...]
  function groupedFilteredPlaces(place) {
    const filtered = filteredPlaces(place);
    const map = new Map();
    filtered.forEach((p) => {
      const area = p.area_name || "미분류";
      if (!map.has(area)) map.set(area, []);
      map.get(area).push(p);
    });
    return Array.from(map.entries()).map(([area, items]) => ({ area, items }));
  }

  function isAllInGroupSelected(place, items) {
    if (!items || items.length === 0) return false;
    return items.every((p) => place.tempSelected.includes(placeKey(p)));
  }

  function toggleAllInGroup(place, items) {
    const keys = items.map(placeKey);
    if (isAllInGroupSelected(place, items)) {
      const set = new Set(keys);
      place.tempSelected = place.tempSelected.filter((k) => !set.has(k));
    } else {
      const merged = new Set([...place.tempSelected, ...keys]);
      place.tempSelected = [...merged];
    }
  }

  function applyDropdown(place) {
    place.onboards = [...place.tempSelected];
    place.dropdownOpen = false;
  }

  function removePlaceChip(place, key) {
    place.onboards = place.onboards.filter((k) => k !== key);
  }

  // 칩 표시용 — 같은 지역의 모든 장소가 선택됐으면 "○○ 전체" 그룹 칩으로 묶음
  function displayChips(place) {
    const selectedKeys = new Set(place.onboards);

    const groupedAll = new Map();
    placesAll.value.forEach((p) => {
      const area = p.area_name || "미분류";
      if (!groupedAll.has(area)) groupedAll.set(area, []);
      groupedAll.get(area).push(p);
    });

    const result = [];
    const processedKeys = new Set();

    for (const [area, places] of groupedAll.entries()) {
      if (places.length < 2) continue;
      const groupKeys = places.map(placeKey);
      const allSelected = groupKeys.every((k) => selectedKeys.has(k));
      if (allSelected) {
        result.push({
          key: `group:${area}`,
          type: "group",
          label: `${area} 전체`,
          icon: "📍",
          keys: groupKeys,
        });
        groupKeys.forEach((k) => processedKeys.add(k));
      }
    }

    for (const key of place.onboards) {
      if (processedKeys.has(key)) continue;
      result.push({
        key,
        type: "single",
        label: placeNameByKey(key),
        icon: placeTypeByKey(key) === "onboard" ? "🚤" : "🎣",
        keys: [key],
      });
    }

    return result;
  }

  function removeChipFromPlace(place, chip) {
    const keysToRemove = new Set(chip.keys);
    place.onboards = place.onboards.filter((k) => !keysToRemove.has(k));
  }

  // 외부 클릭 시 모든 드롭다운 닫기
  function handleDocumentClick() {
    closeAllDropdowns();
  }

  // ============================
  // 아이템 선택 모달
  // ============================
  const itemModal = ref({
    isOpen: false,
    target: null,        // round 또는 place 객체 (둘 다 .items 배열 가짐)
    tempSelected: [],    // 임시 선택된 item id 배열
    searchKeyword: "",
  });

  function openItemModal(target) {
    itemModal.value.target = target;
    itemModal.value.tempSelected = target.items.map((i) => i.item_id);
    itemModal.value.searchKeyword = "";
    itemModal.value.isOpen = true;
  }

  function closeItemModal() {
    itemModal.value.isOpen = false;
    itemModal.value.target = null;
    itemModal.value.tempSelected = [];
    itemModal.value.searchKeyword = "";
  }

  function toggleItemInModal(itemId) {
    const idx = itemModal.value.tempSelected.indexOf(itemId);
    if (idx === -1) itemModal.value.tempSelected.push(itemId);
    else itemModal.value.tempSelected.splice(idx, 1);
  }

  function filteredItems() {
    if (!itemModal.value.searchKeyword) return itemsAll.value;
    const kw = itemModal.value.searchKeyword.toLowerCase();
    return itemsAll.value.filter((i) =>
      String(i.name || "").toLowerCase().includes(kw)
    );
  }

  function applyItemModal() {
    const target = itemModal.value.target;
    if (!target) return;
    target.items = itemModal.value.tempSelected.map((id) => {
      const it = itemsAll.value.find((x) => x.id === id);
      return {
        item_id: id,
        name: it?.name || "?",
        type: it?.type || "",
        point: it?.point ?? null,
      };
    });
    closeItemModal();
  }

  // ============================
  // 데이터 로드
  // ============================
  async function loadOptions() {
    try {
      const [fieldRes, areaRes, onboardRes, fishingRes, itemRes] = await Promise.all([
        get("/field/list", { params: { per_page: 1000 } }),
        get("/area/list", { params: { per_page: 1000 } }),
        get("/onboard/list", { params: { per_page: 1000 } }),
        get("/fishing/list", { params: { per_page: 1000 } }),
        get("/item/list", { params: { per_page: 1000, status: "Y" } }),
      ]);
      if (fieldRes.data?.success) fieldOptions.value = (fieldRes.data.data.items || []).reverse();
      if (areaRes.data?.success) areaOptions.value = (areaRes.data.data.items || []).reverse();

      // 선상 + 낚시터 통합 (_placeType으로 구분)
      const onboards = (onboardRes.data?.success ? (onboardRes.data.data.items || []) : [])
        .map((o) => ({ ...o, _placeType: "onboard" }));
      const fishings = (fishingRes.data?.success ? (fishingRes.data.data.items || []) : [])
        .map((f) => ({ ...f, _placeType: "fishing" }));
      placesAll.value = [...onboards, ...fishings];

      if (itemRes.data?.success) itemsAll.value = itemRes.data.data.items || [];
    } catch (e) {
      console.error("Load options error:", e);
    }
  }

  // ============================
  // 챌린지 로드 + 폼 채우기
  // ============================
  async function loadChallenge() {
    isLoading.value = true;
    try {
      const { data, error } = await get(`/challenge/${challengeId}`);
      if (error || !data?.success) {
        errorMessage.value = error?.message || data?.message || "챌린지를 불러올 수 없습니다.";
        return;
      }
      const c = data.data;

      // 기본 정보
      const feeNum = Number(c.fee);
      isFree.value = !isNaN(feeNum) && feeNum === 0;
      formData.value = {
        name: c.name || "",
        fee: String(c.fee ?? ""),
        max_participants: c.max_participants || "",
        status_YN: c.status_YN || "Y",
        description: c.description || "",
      };
      startDate.value = c.start_date ? String(c.start_date).substring(0, 10) : "";
      endDate.value = c.end_date ? String(c.end_date).substring(0, 10) : "";

      // 기존 이미지
      if (c.file_path) {
        existingImagePath.value = c.file_path;
        existingImageName.value = c.file_name;
      }

      // 라운드 변환 (응답 구조 → 폼 구조)
      rounds.value = (c.rounds || []).map((r) => {
        const round = createRound(r.round_no);
        round.place_mode = r.place_mode;
        round.qualified = String(r.qualified || "");

        if (r.place_mode === "all") {
          round.items = (r.items || []).map((it) => ({
            item_id: it.item_id,
            name: it.name,
            type: it.type,
            point: it.point,
          }));
          round.places = [];
        } else {
          round.items = [];
          round.places = (r.places || []).map((p) => {
            const place = createPlace();
            // field_id, area_id, partnership_YN은 응답에 없음 (필터 조건은 저장 안 됨)
            // 사용자가 수정 시 다시 필터 가능
            place.onboards = (p.onboards || []).map((o) => `${o.place_type}-${o.place_id}`);
            place.items = (p.items || []).map((it) => ({
              item_id: it.item_id,
              name: it.name,
              type: it.type,
              point: it.point,
            }));
            return place;
          });
        }
        return round;
      });

      // 최소 2라운드 보장 (이상 케이스 대비)
      while (rounds.value.length < 2) {
        rounds.value.push(createRound(rounds.value.length + 1));
      }
    } catch (e) {
      console.error("[ChallengeEdit] 로드 실패:", e);
      errorMessage.value = "서버 오류가 발생했습니다.";
    } finally {
      isLoading.value = false;
    }
  }

  // 기존 이미지 제거 (즉시 백엔드 호출)
  async function removeExistingImage() {
    if (!confirm("기존 이미지를 제거하시겠습니까?")) return;
    try {
      const { data, error } = await del(`/challenge/${challengeId}/image`);
      if (error || !data?.success) {
        errorMessage.value = error?.message || data?.message || "이미지 제거에 실패했습니다.";
        return;
      }
      existingImagePath.value = null;
      existingImageName.value = null;
      successMessage.value = "이미지가 제거되었습니다.";
    } catch (e) {
      console.error("[ChallengeEdit] 이미지 제거 실패:", e);
      errorMessage.value = "서버 오류가 발생했습니다.";
    }
  }

  // ============================
  // 폼 제출
  // ============================
  async function handleSubmit() {
    errorMessage.value = "";
    successMessage.value = "";

    // 프론트 1차 검증
    if (!formData.value.name.trim()) return (errorMessage.value = "챌린지명을 입력하세요.");
    if (!formData.value.fee.toString().trim()) return (errorMessage.value = "참가비를 입력하세요.");
    if (!startDate.value) return (errorMessage.value = "시작일을 선택하세요.");
    if (!endDate.value) return (errorMessage.value = "종료일을 선택하세요.");
    if (!formData.value.max_participants) return (errorMessage.value = "최대 참가자를 입력하세요.");

    for (let i = 0; i < rounds.value.length; i++) {
      const r = rounds.value[i];
      if (!r.qualified) {
        return (errorMessage.value = `라운드 ${i + 1}의 진출자 수를 입력하세요.`);
      }
      if (r.place_mode === "specific") {
        if (r.places.length === 0) {
          return (errorMessage.value = `라운드 ${i + 1}에 장소를 1개 이상 추가하세요.`);
        }
        for (let j = 0; j < r.places.length; j++) {
          if (r.places[j].onboards.length === 0) {
            return (errorMessage.value = `라운드 ${i + 1} 장소 ${j + 1}에 선상을 1개 이상 선택하세요.`);
          }
        }
      }
    }

    isSaving.value = true;
    try {
      const payload = {
        name: formData.value.name,
        fee: formData.value.fee,
        start_date: startDate.value,
        end_date: endDate.value,
        max_participants: Number(formData.value.max_participants),
        description: formData.value.description,
        status_YN: formData.value.status_YN,
        rounds: rounds.value.map((r) => ({
          round_no: r.round_no,
          place_mode: r.place_mode,
          qualified: Number(r.qualified),
          items: r.place_mode === "all"
            ? r.items.map((it) => ({ item_id: it.item_id }))
            : [],
          places: r.place_mode === "specific"
            ? r.places.map((p) => ({
                // 'onboard-1', 'fishing-3' → [{type:'onboard', id:1}, {type:'fishing', id:3}, ...]
                onboards: p.onboards.map((key) => {
                  const i = key.indexOf("-");
                  return { type: key.substring(0, i), id: Number(key.substring(i + 1)) };
                }),
                items: p.items.map((it) => ({ item_id: it.item_id })),
              }))
            : [],
        })),
      };

      const { data, error } = await put(`/challenge/${challengeId}`, payload);

      if (error || !data?.success) {
        errorMessage.value = error?.message || data?.message || "수정에 실패했습니다.";
        return;
      }

      // 새 이미지가 선택되어 있으면 업로드 (기존 이미지 자동 교체)
      if (image.value) {
        const fd = new FormData();
        fd.append("image", image.value.file);
        const { data: imgRes, error: imgErr } = await upload(`/challenge/${challengeId}/image`, fd);

        if (imgErr || !imgRes?.success) {
          errorMessage.value = "챌린지는 수정됐지만 이미지 업로드에 실패했습니다.";
          setTimeout(() => router.push(`/site-manager/challenge/detail/${challengeId}`), 1500);
          return;
        }
      }

      successMessage.value = data.message || "챌린지가 수정되었습니다.";
      setTimeout(() => {
        router.push(`/site-manager/challenge/detail/${challengeId}`);
      }, 1000);
    } catch (e) {
      errorMessage.value = "서버 오류가 발생했습니다.";
      console.error("Challenge save error:", e);
    } finally {
      isSaving.value = false;
    }
  }

  const goToList = () => router.push("/site-manager/challenge/list");
  const goToDetail = () => router.push(`/site-manager/challenge/detail/${challengeId}`);

  onMounted(async () => {
    document.addEventListener("click", handleDocumentClick);
    // 옵션 먼저 로드한 후 챌린지 로드 (placesAll 채워야 onboards 매핑 가능)
    await loadOptions();
    await loadChallenge();
  });

  onBeforeUnmount(() => {
    document.removeEventListener("click", handleDocumentClick);
  });
</script>
