<template>
  <div class="admin--field-list">
    <!-- 상단 액션 영역 -->
    <div class="admin--search-box type2">
      <div class="admin--search--inner--box">
        <div class="admin--search-form">
          <select v-model="filterTypeId" @change="onSearch" class="admin--form-select admin--search-select">
            <option value="">전체</option>
            <option value="null">구분 없음</option>
            <option v-for="t in typeOptions" :key="t.id" :value="t.id">{{ t.name }}</option>
          </select>
          <input
            v-model="searchQuery"
            type="text"
            placeholder="어종명 검색"
            @keyup.enter="onSearch"
            class="admin--form-input admin--search-input"
          />
          <button @click="onSearch" class="admin--btn-small admin--btn-small-primary">검색</button>
          <button @click="resetSearch" class="admin--btn-small admin--btn-small-secondary">초기화</button>
        </div>
        <div class="admin--search-actions">
          <button
            v-if="hasChanges"
            class="admin--btn-small admin--btn-small-secondary"
            :disabled="isSaving"
            @click="cancelAll"
          >모두 취소</button>
          <button
            class="admin--btn-small admin--btn-small-secondary"
            :disabled="selectedIds.length === 0"
            @click="bulkDelete"
          >
            선택 삭제<span v-if="selectedIds.length"> ({{ selectedIds.length }})</span>
          </button>
          <button class="admin--btn-small admin--btn-small-primary" @click="addNewRow">+ 어종 추가</button>
          <button
            v-if="hasChanges || isSaving"
            class="admin--btn-small admin--btn-small-danger"
            :disabled="isSaving"
            @click="bulkSave"
          >
            {{ isSaving ? "저장 중..." : `일괄 저장 (${changeCount})` }}
          </button>
        </div>
      </div>
      <div class="admin--search--inner--box">
        <div class="admin--search-form">
          <DatePicker v-model="startDate" placeholder="📅 YYYY-MM-DD" />
          <span class="admin--date-separator">-</span>
          <DatePicker v-model="endDate" placeholder="📅 YYYY-MM-DD" />
          <div class="admin--quick-range">
            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('today')">오늘</button>
            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('7d')">7일</button>
            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('15d')">15일</button>
            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('1m')">1개월</button>
            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('3m')">3개월</button>
            <button type="button" class="admin--btn-small admin--btn-small-secondary range--btn" @click="setRange('1y')">1년</button>
          </div>
        </div>
      </div>
    </div>

    <p class="admin--table--top--text">길이 기준 : CM</p>
    <div class="admin--table-wrapper">
      <table class="admin--table fish--table">
        <thead>
          <tr>
            <th style="width: 36px;">
              <div class="input--wrap">
                <input
                  type="checkbox"
                  :checked="isAllSelected"
                  :indeterminate.prop="isPartialSelected"
                  @change="toggleAll($event.target.checked)"
                  aria-label="전체 선택"
                />
              </div>
            </th>
            <th>어종</th>
            <th style="width: 100px;">구분</th>
            <th style="width: 68px;">최소금지</th>
            <th style="width: 68px;">최대길이</th>
            <th style="width: 140px;">1라운드</th>
            <th style="width: 140px;">2라운드</th>
            <th style="width: 140px;">3라운드</th>
            <th style="width: 140px;">4라운드</th>
            <th style="width: 140px;">5라운드</th>
            <th style="width: 90px;">등록일</th>
            <th style="width: 60px;">관리</th>
          </tr>
        </thead>
        <tbody>
          <!-- 신규 행 -->
          <tr v-for="n in newRows" :key="'new-' + n._tempId" class="admin--table-row-new">
            <td></td>
            <td @click.stop>
              <input v-model="n.name" type="text" class="admin--form-input admin--inline-input" placeholder="어종명" @keyup.enter="bulkSave" />
            </td>
            <td @click.stop>
              <select v-model="n.type_id" class="admin--form-select admin--inline-input">
                <option value="">선택</option>
                <option v-for="t in typeOptions" :key="t.id" :value="t.id">{{ t.name }}</option>
              </select>
            </td>
            <td @click.stop>
              <input v-model.number="n.min" type="number" min="0" class="admin--form-input admin--inline-input center" @input="limitDigits" @keyup.enter="bulkSave" />
            </td>
            <td @click.stop>
              <input v-model.number="n.max" type="number" min="0" class="admin--form-input admin--inline-input center" @input="limitDigits" @keyup.enter="bulkSave" />
            </td>
            <td v-for="r in 5" :key="'r' + r + 'new' + n._tempId" @click.stop>
              <div class="admin--range-cell">
                <input v-model.number="n[`round${r}_min`]" type="number" min="0" class="admin--form-input admin--inline-input" placeholder="min" @input="limitDigits" @keyup.enter="bulkSave" />
                <span>~</span>
                <input v-model.number="n[`round${r}_max`]" type="number" min="0" class="admin--form-input admin--inline-input" placeholder="max" @input="limitDigits" @keyup.enter="bulkSave" />
              </div>
            </td>
            <td class="date">{{ todayLabel }}</td>
            <td @click.stop>
              <button class="admin--btn-small mw--0 admin--btn-small-secondary" @click="removeNewRow(n._tempId)">제거</button>
            </td>
          </tr>

          <tr v-if="isLoading">
            <td colspan="12" class="admin--table-loading">데이터를 불러오는 중...</td>
          </tr>
          <tr v-else-if="!displayedItems || displayedItems.length === 0">
            <td colspan="12" class="admin--table-empty" v-if="newRows.length === 0">등록된 어종이 없습니다.</td>
          </tr>
          <tr
            v-else
            v-for="item in displayedItems"
            :key="item.id"
            :class="{
              'admin--table-row-new': editing[item.id],
              'admin--table-row-clickable': !editing[item.id],
            }"
            @click="!editing[item.id] && startEdit(item)"
          >
            <td @click.stop style="padding: 8px;">
              <div class="input--wrap">
                <input type="checkbox" :value="item.id" v-model="selectedIds" />
              </div>
            </td>

            <!-- 수정 모드 -->
            <template v-if="editing[item.id]">
              <td @click.stop style="padding: 8px;">
                <input v-model="editing[item.id].name" type="text" class="admin--form-input admin--inline-input" @keyup.enter="bulkSave" />
              </td>
              <td @click.stop>
                <select v-model="editing[item.id].type_id" class="admin--form-select admin--inline-input">
                  <option value="">선택</option>
                  <option v-for="t in typeOptions" :key="t.id" :value="t.id">{{ t.name }}</option>
                </select>
              </td>
              <td @click.stop>
                <input v-model.number="editing[item.id].min" type="number" min="0" class="admin--form-input admin--inline-input center" @input="limitDigits" @keyup.enter="bulkSave" />
              </td>
              <td @click.stop>
                <input v-model.number="editing[item.id].max" type="number" min="0" class="admin--form-input admin--inline-input center" @input="limitDigits" @keyup.enter="bulkSave" />
              </td>
              <td v-for="r in 5" :key="'r' + r + 'edit' + item.id" @click.stop>
                <div class="admin--range-cell">
                  <input v-model.number="editing[item.id][`round${r}_min`]" type="number" min="0" class="admin--form-input admin--inline-input" placeholder="min" @input="limitDigits" @keyup.enter="bulkSave" />
                  <span>~</span>
                  <input v-model.number="editing[item.id][`round${r}_max`]" type="number" min="0" class="admin--form-input admin--inline-input" placeholder="max" @input="limitDigits" @keyup.enter="bulkSave" />
                </div>
              </td>
              <td class="date">{{ formatDate(item.created_at) }}</td>
              <td @click.stop>
                <button class="admin--btn-small mw--0 admin--btn-small-secondary" @click="cancelEdit(item.id)">취소</button>
              </td>
            </template>

            <!-- 일반 모드 -->
            <template v-else>
              <td class="admin--table-title">{{ item.name }}</td>
              <td>{{ item.type_name || "-" }}</td>
              <td>{{ item.min }}</td>
              <td>{{ item.max }}</td>
              <td v-for="r in 5" :key="'r' + r + 'view' + item.id">
                {{ item[`round${r}_min`] }} ~ {{ item[`round${r}_max`] }}
              </td>
              <td class="date">{{ formatDate(item.created_at) }}</td>
              <td></td>
            </template>
          </tr>
        </tbody>
      </table>
    </div>

    <!-- 토스트 -->
    <Teleport to="body">
      <Transition name="admin--toast">
        <div v-if="toast.show" class="admin--toast" :class="{ 'is-error': toast.type === 'error' }">
          <span class="admin--toast-icon"></span>
          <span class="admin--toast-msg">{{ toast.message }}</span>
          <button class="admin--toast-close" @click="dismissToast">×</button>
        </div>
      </Transition>
    </Teleport>

    <!-- 알림 모달 -->
    <AdminAlertModal
      v-if="alertModal.show"
      :title="alertModal.title"
      :message="alertModal.message"
      :type="alertModal.type"
      @confirm="handleAlertConfirm"
      @cancel="handleAlertCancel"
      @close="closeAlertModal"
    />

    <!-- 페이지네이션 -->
    <div v-if="totalPages > 1" class="admin--pagination">
      <button v-if="totalPages > 2" class="admin--pagination-btn" :disabled="currentPage === 1" @click="changePage(1)" title="처음">◀◀</button>
      <button class="admin--pagination-btn" :disabled="currentPage === 1" @click="changePage(currentPage - 1)" title="이전">◀</button>
      <button v-for="page in visiblePages" :key="page" class="admin--pagination-btn" :class="{ 'is-active': page === currentPage }" @click="changePage(page)">{{ page }}</button>
      <button class="admin--pagination-btn" :disabled="currentPage === totalPages" @click="changePage(currentPage + 1)" title="다음">▶</button>
      <button v-if="totalPages > 2" class="admin--pagination-btn" :disabled="currentPage === totalPages" @click="changePage(totalPages)" title="끝">▶▶</button>
    </div>
  </div>
</template>

<script setup>
  import { ref, computed, onMounted } from "vue";
  import AdminAlertModal from "~/components/admin/AdminAlertModal.vue";
  import DatePicker from "~/components/admin/DatePicker.vue";

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

  const { get, post } = useApi();

  const isLoading = ref(false);
  const isSaving = ref(false);
  const items = ref([]);
  const typeOptions = ref([]);
  const currentPage = ref(1);
  const perPage = ref(10);
  const totalCount = ref(0);
  const totalPages = ref(0);

  // 검색
  const searchQuery = ref("");
  const filterTypeId = ref("");
  const startDate = ref("");
  const endDate = ref("");

  // 토스트
  const toast = ref({ show: false, type: "success", message: "" });
  let toastTimer = null;
  const showToast = (message, type = "success", duration = type === "error" ? 4500 : 2500) => {
    if (toastTimer) clearTimeout(toastTimer);
    toast.value = { show: true, type, message };
    toastTimer = setTimeout(() => { toast.value.show = false; }, duration);
  };
  const dismissToast = () => {
    if (toastTimer) clearTimeout(toastTimer);
    toast.value.show = false;
  };

  // 신규/수정/삭제 상태
  const newRows = ref([]);
  let tempIdCounter = 0;
  const editing = ref({});
  const markedForDeleteIds = ref([]);

  const displayedItems = computed(() =>
    items.value.filter((it) => !markedForDeleteIds.value.includes(it.id))
  );

  const changeCount = computed(
    () => newRows.value.length + Object.keys(editing.value).length + markedForDeleteIds.value.length
  );
  const hasChanges = computed(() => changeCount.value > 0);

  // 오늘 라벨
  const todayLabel = computed(() => {
    const d = new Date();
    return d.toLocaleDateString("ko-KR", { year: "numeric", month: "2-digit", day: "2-digit" });
  });

  // 체크박스
  const selectedIds = ref([]);
  const isAllSelected = computed(
    () => displayedItems.value.length > 0 && displayedItems.value.every((it) => selectedIds.value.includes(it.id))
  );
  const isPartialSelected = computed(() => selectedIds.value.length > 0 && !isAllSelected.value);
  const toggleAll = (checked) => {
    if (checked) {
      const pageIds = displayedItems.value.map((it) => it.id);
      selectedIds.value = Array.from(new Set([...selectedIds.value, ...pageIds]));
    } else {
      const pageIds = new Set(displayedItems.value.map((it) => it.id));
      selectedIds.value = selectedIds.value.filter((id) => !pageIds.has(id));
    }
  };

  // 알림 모달
  const alertModal = ref({ show: false, title: "알림", message: "", type: "alert", onConfirm: null });
  const showConfirm = (message, onConfirm, title = "확인") => {
    alertModal.value = { show: true, title, message, type: "confirm", onConfirm };
  };
  const closeAlertModal = () => { alertModal.value.show = false; };
  const handleAlertConfirm = () => {
    if (alertModal.value.onConfirm) alertModal.value.onConfirm();
    closeAlertModal();
  };
  const handleAlertCancel = () => closeAlertModal();

  // 페이지 번호
  const visiblePages = computed(() => {
    const pages = [];
    const maxVisible = 5;
    let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
    let end = Math.min(totalPages.value, start + maxVisible - 1);
    if (end - start < maxVisible - 1) start = Math.max(1, end - maxVisible + 1);
    for (let i = start; i <= end; i++) pages.push(i);
    return pages;
  });

  // YYYY-MM-DD 포맷
  const toYMD = (d) => {
    const y = d.getFullYear();
    const m = String(d.getMonth() + 1).padStart(2, "0");
    const day = String(d.getDate()).padStart(2, "0");
    return `${y}-${m}-${day}`;
  };

  // 빠른 기간 선택
  const setRange = (kind) => {
    const end = toYMD(new Date());
    const startDt = new Date();
    switch (kind) {
      case "today": break;
      case "7d": startDt.setDate(startDt.getDate() - 7); break;
      case "15d": startDt.setDate(startDt.getDate() - 15); break;
      case "1m": startDt.setMonth(startDt.getMonth() - 1); break;
      case "3m": startDt.setMonth(startDt.getMonth() - 3); break;
      case "1y": startDt.setFullYear(startDt.getFullYear() - 1); break;
    }
    startDate.value = toYMD(startDt);
    endDate.value = end;
    onSearch();
  };

  // 구분 옵션 로드 (species_type)
  const loadTypeOptions = async () => {
    const { data } = await get("/species/list", { params: { per_page: 1000 } });
    if (data?.success) typeOptions.value = data.data.items || [];
  };

  // 데이터 로드
  const loadItems = async () => {
    isLoading.value = true;
    const params = { page: currentPage.value, per_page: perPage.value };
    if (searchQuery.value) params.search = searchQuery.value;
    if (filterTypeId.value) params.type_id = filterTypeId.value;
    if (startDate.value) params.start_date = startDate.value;
    if (endDate.value) params.end_date = endDate.value;

    const { data, error } = await get("/species-challenge/list", { params });
    if (error) {
      items.value = []; totalCount.value = 0; totalPages.value = 0;
    } else if (data?.success && data?.data) {
      items.value = data.data.items || [];
      totalCount.value = data.data.total || 0;
      totalPages.value = data.data.total_pages || 0;
    }
    isLoading.value = false;
  };

  // 검색
  const onSearch = () => {
    currentPage.value = 1;
    loadItems();
  };
  const resetSearch = () => {
    searchQuery.value = "";
    filterTypeId.value = "";
    startDate.value = "";
    endDate.value = "";
    currentPage.value = 1;
    loadItems();
  };

  // 신규 행 추가
  const blankRow = () => ({
    _tempId: ++tempIdCounter,
    type_id: "",
    name: "",
    min: 0,
    max: 0,
    round1_min: 0, round1_max: 0,
    round2_min: 0, round2_max: 0,
    round3_min: 0, round3_max: 0,
    round4_min: 0, round4_max: 0,
    round5_min: 0, round5_max: 0,
  });
  const addNewRow = () => {
    dismissToast();
    newRows.value.push(blankRow());
  };
  const removeNewRow = (tempId) => {
    newRows.value = newRows.value.filter((r) => r._tempId !== tempId);
  };

  // 수정 시작
  const startEdit = (item) => {
    dismissToast();
    editing.value = {
      ...editing.value,
      [item.id]: {
        type_id: item.type_id ?? "",
        name: item.name ?? "",
        min: item.min ?? 0,
        max: item.max ?? 0,
        round1_min: item.round1_min ?? 0, round1_max: item.round1_max ?? 0,
        round2_min: item.round2_min ?? 0, round2_max: item.round2_max ?? 0,
        round3_min: item.round3_min ?? 0, round3_max: item.round3_max ?? 0,
        round4_min: item.round4_min ?? 0, round4_max: item.round4_max ?? 0,
        round5_min: item.round5_min ?? 0, round5_max: item.round5_max ?? 0,
      },
    };
  };
  const cancelEdit = (id) => {
    const next = { ...editing.value };
    delete next[id];
    editing.value = next;
  };

  // 모두 취소
  const cancelAll = () => {
    if (!hasChanges.value) return;
    showConfirm(
      "작성·수정·삭제 표시한 모든 변경사항을 취소하시겠습니까?",
      () => {
        newRows.value = [];
        editing.value = {};
        markedForDeleteIds.value = [];
        dismissToast();
      },
      "변경 취소"
    );
  };

  // number 인풋 자릿수 제한 — 입력 즉시 자르고 v-model 동기화
  const limitDigits = (e, max = 4) => {
    const v = e.target.value;
    if (v.length > max) {
      e.target.value = v.slice(0, max);
      e.target.dispatchEvent(new Event("input", { bubbles: true }));
    }
  };

  // 한 행 검증 (프론트) — 구분은 선택사항 (저장 시 별도 확인 모달로 한 번 더 물음)
  const validateRow = (row, label) => {
    const name = (row.name || "").trim();
    if (!name) return `${label}: 어종명을 입력하세요.`;
    if (name.length > 50) return `${label}: 어종명은 50자 이내`;
    const num = (v) => (v === null || v === "" || isNaN(Number(v))) ? null : Number(v);
    const min = num(row.min); const max = num(row.max);
    if (min === null) return `${label}: 최소금지를 입력하세요.`;
    if (max === null) return `${label}: 최대길이를 입력하세요.`;
    if (max < min) return `${label}: 최대길이는 최소금지 이상`;
    for (let r = 1; r <= 5; r++) {
      const rmin = num(row[`round${r}_min`]);
      const rmax = num(row[`round${r}_max`]);
      if (rmin === null) return `${label}: ${r}라운드 최소를 입력하세요.`;
      if (rmax === null) return `${label}: ${r}라운드 최대를 입력하세요.`;
      if (rmin > rmax) return `${label}: ${r}라운드 최소는 최대보다 작거나 같아야 합니다.`;
      if (rmax > max) return `${label}: ${r}라운드 최대는 최대길이(${max})보다 클 수 없습니다.`;
    }
    if (Number(row.round1_min) < min) return `${label}: 1라운드 최소는 최소금지(${min})보다 작을 수 없습니다.`;
    return null;
  };

  // 일괄 저장
  const bulkSave = async () => {
    dismissToast();
    if (!hasChanges.value) return;

    const creates = newRows.value.map((n) => ({ ...n }));
    const updates = Object.entries(editing.value).map(([id, v]) => ({ id: Number(id), ...v }));

    // 기본 검증 (구분 제외)
    for (let i = 0; i < creates.length; i++) {
      const err = validateRow(creates[i], `신규 ${i + 1}행`);
      if (err) return showToast(err, "error");
    }
    for (let i = 0; i < updates.length; i++) {
      const err = validateRow(updates[i], `수정 ${i + 1}행`);
      if (err) return showToast(err, "error");
    }

    const deletes = [...markedForDeleteIds.value];

    // 실제 서버 호출
    const doSave = async () => {
      isSaving.value = true;
      try {
        const { data, error } = await post("/species-challenge/bulk-save", { creates, updates, deletes });
        if (error || !data?.success) {
          showToast(error?.message || data?.message || "저장 실패", "error");
          return;
        }
        showToast(data.message || "저장되었습니다.", "success");
        newRows.value = [];
        editing.value = {};
        markedForDeleteIds.value = [];
        selectedIds.value = [];
        await loadItems();
      } catch (e) {
        showToast("서버 오류가 발생했습니다.", "error");
        console.error("Bulk save error:", e);
      } finally {
        isSaving.value = false;
      }
    };

    // 구분 미선택 행 카운트 → 확인 모달
    const missingCount = [...creates, ...updates].filter((r) => !r.type_id).length;
    if (missingCount > 0) {
      showConfirm(
        `${missingCount}개 행에 구분이 선택되지 않았습니다.\n그대로 저장하시겠습니까?`,
        doSave,
        "구분 미선택"
      );
      return;
    }

    await doSave();
  };

  // 선택 삭제 — 즉시 X, 일괄 저장 시 처리
  const bulkDelete = () => {
    if (selectedIds.value.length === 0) return;
    const ids = [...selectedIds.value];
    const nextEditing = { ...editing.value };
    ids.forEach((id) => { delete nextEditing[id]; });
    editing.value = nextEditing;
    markedForDeleteIds.value = Array.from(new Set([...markedForDeleteIds.value, ...ids]));
    selectedIds.value = [];
    dismissToast();
  };

  // 페이지 변경
  const changePage = (page) => {
    if (page < 1 || page > totalPages.value) return;
    if (hasChanges.value) {
      return showConfirm(
        "저장하지 않은 변경사항이 있습니다. 페이지를 이동하면 모두 사라집니다.",
        () => {
          newRows.value = [];
          editing.value = {};
          markedForDeleteIds.value = [];
          selectedIds.value = [];
          currentPage.value = page;
          loadItems();
          window.scrollTo({ top: 0, behavior: "smooth" });
        },
        "페이지 이동"
      );
    }
    currentPage.value = page;
    loadItems();
    window.scrollTo({ top: 0, behavior: "smooth" });
  };

  const formatDate = (dateString) => {
    if (!dateString) return "-";
    const date = new Date(dateString.replace(" ", "T"));
    if (isNaN(date.getTime())) return dateString;
    return date.toLocaleDateString("ko-KR", { year: "numeric", month: "2-digit", day: "2-digit" });
  };

  onMounted(async () => {
    await loadTypeOptions();
    await loadItems();
  });
</script>
