<script setup>
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { accountApi } from '@/api/accountApi'
import IconBtn from '@/components/ui/IconBtn.vue'
import CategoryPicker from '@/components/ui/CategoryPicker.vue'

const categories = ref([])
const loading = ref(false)
const error = ref(null)
const activeType = ref('EXPENSE')
const reorderMode = ref(false)

function toggleReorder() {
  reorderMode.value = !reorderMode.value
}

// 탭 전환 시 순서변경 모드 초기화
watch(activeType, () => { reorderMode.value = false })

// 인앱 확인 모달
const confirmState = reactive({ open: false, title: '', message: '', onOk: null })
function askConfirm(title, message, onOk) {
  confirmState.title = title
  confirmState.message = message
  confirmState.onOk = onOk
  confirmState.open = true
}
function confirmOk() {
  const fn = confirmState.onOk
  confirmState.open = false
  if (fn) fn()
}
function showError(e, fallback) {
  error.value = e.response?.data?.message || fallback
}

const hasCategories = computed(() =>
  categories.value.some((c) => c.type === activeType.value)
)

async function load() {
  loading.value = true
  error.value = null
  try {
    categories.value = await accountApi.categories()
  } catch (e) {
    error.value = e.response?.data?.message || '불러오지 못했습니다.'
  } finally {
    loading.value = false
  }
}

async function onRename(cat, newName) {
  error.value = null
  try {
    await accountApi.updateCategory(cat.id, { type: cat.type, name: newName, parentId: cat.parentId || null })
    await load()
  } catch (e) {
    showError(e, '수정에 실패했습니다.')
  }
}

function onDelete(cat) {
  askConfirm(
    '분류 삭제',
    `'${cat.name}' 분류를 삭제할까요?\n기존 내역의 분류명은 그대로 유지됩니다.`,
    async () => {
      error.value = null
      try {
        await accountApi.removeCategory(cat.id)
        await load()
      } catch (e) {
        showError(e, '삭제에 실패했습니다.')
      }
    },
  )
}

async function onReorder(ids) {
  // 낙관적 로컬 반영
  const idSet = new Set(ids)
  const moved = ids.map((id) => categories.value.find((c) => c.id === id)).filter(Boolean)
  let k = 0
  categories.value = categories.value.map((c) => (idSet.has(c.id) ? moved[k++] : c))
  try {
    await accountApi.reorderCategories(activeType.value, ids)
  } catch (e) {
    showError(e, '순서 저장에 실패했습니다.')
    await load()
  }
}

function importDefaults() {
  askConfirm('기본 분류 불러오기', '관리자가 설정한 기본 분류를 내 분류로 가져올까요?\n같은 이름은 건너뜁니다.', async () => {
    error.value = null
    try {
      categories.value = await accountApi.importCategories()
    } catch (e) {
      showError(e, '불러오기에 실패했습니다.')
    }
  })
}

onMounted(load)
</script>

<template>
  <section class="cat">
    <p class="hint">내역·예산에서 선택할 분류를 관리합니다. <b>대분류 아래 소분류</b>로 묶을 수 있고(2단계), 예산·통계는 소분류 기준입니다. 이름을 바꾸면 기존 내역·예산에도 반영됩니다.</p>

    <div class="tabs-row">
      <div class="tabs">
        <button type="button" :class="{ active: activeType === 'EXPENSE' }" @click="activeType = 'EXPENSE'">지출 분류</button>
        <button type="button" :class="{ active: activeType === 'INCOME' }" @click="activeType = 'INCOME'">수입 분류</button>
      </div>
      <div class="tabs-actions">
        <button type="button" class="text-btn" @click="importDefaults">기본 분류 불러오기</button>
        <button type="button" class="text-btn reorder-btn" :class="{ active: reorderMode }" @click="toggleReorder">
          {{ reorderMode ? '완료' : '순서변경' }}
        </button>
      </div>
    </div>

    <p class="hint sm">
      <template v-if="reorderMode">⠿ 손잡이를 끌어 순서를 바꾸세요. 끝나면 <b>완료</b>.</template>
      <template v-else>✏ 이름 수정 &nbsp;·&nbsp; ✕ 삭제 &nbsp;·&nbsp; 대분류 클릭 시 소분류 펼침</template>
    </p>

    <p v-if="error" class="msg error">{{ error }}</p>
    <p v-if="loading" class="msg">불러오는 중...</p>

    <CategoryPicker
      v-if="!loading || categories.length"
      :admin="true"
      :reorderable="reorderMode"
      :type="activeType"
      :categories="categories"
      @rename="onRename"
      @delete="onDelete"
      @reorder="onReorder"
      @category-added="load"
    />

    <div v-if="!loading && !hasCategories" class="empty-state">
      <p class="empty-emoji">🗂️</p>
      <p class="empty-title">등록된 {{ activeType === 'EXPENSE' ? '지출' : '수입' }} 분류가 없어요</p>
      <p class="empty-desc">기본 분류를 불러오면 식비·교통 등이 한 번에 추가됩니다.</p>
      <button type="button" class="empty-cta" @click="importDefaults">기본 분류 불러오기</button>
    </div>

    <!-- 인앱 확인 모달 -->
    <Teleport to="body">
      <Transition name="fade">
        <div v-if="confirmState.open" class="modal-backdrop" @click.self="confirmState.open = false">
          <div class="modal confirm-modal" role="dialog" aria-modal="true">
            <h2>{{ confirmState.title }}</h2>
            <p class="confirm-body">{{ confirmState.message }}</p>
            <div class="buttons">
              <IconBtn icon="close" title="취소" @click="confirmState.open = false" />
              <IconBtn icon="check" title="확인" variant="primary" @click="confirmOk" />
            </div>
          </div>
        </div>
      </Transition>
    </Teleport>
  </section>
</template>

<style scoped>
.cat {
  max-width: 560px;
  margin: 0 auto;
}
.hint {
  font-size: 0.85rem;
  opacity: 0.7;
  margin: 0.5rem 0 1rem;
}
.hint.sm {
  font-size: 0.78rem;
  margin: 0 0 0.75rem;
}
.tabs-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}
.tabs-row .tabs { flex: none; }
.tabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 0;
}
.tabs button {
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  padding: 0.6rem 1rem;
  white-space: nowrap;
  cursor: pointer;
  color: var(--color-text);
  font-size: 0.9rem;
}
.tabs button.active {
  border-bottom-color: hsla(160, 100%, 37%, 1);
  color: hsla(160, 100%, 37%, 1);
  font-weight: 600;
}
.tabs-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.text-btn {
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: var(--color-background-soft);
  color: var(--color-text);
  padding: 0.4rem 0.75rem;
  font-size: 0.82rem;
  cursor: pointer;
  white-space: nowrap;
}
.text-btn:hover { background: var(--color-background-mute); }
.reorder-btn.active {
  color: #fff;
  background: hsla(160, 100%, 37%, 1);
  border-color: hsla(160, 100%, 37%, 1);
}
.msg { margin: 0.75rem 0; font-size: 0.9rem; }
.msg.error { color: #c0392b; }
/* 빈 상태 */
.empty-state { text-align: center; padding: 2.2rem 1rem 2rem; }
.empty-emoji { font-size: 2.6rem; }
.empty-title { margin-top: 0.6rem; font-size: 1.05rem; font-weight: 700; color: var(--color-heading); }
.empty-desc  { margin-top: 0.3rem; font-size: 0.88rem; opacity: 0.7; }
.empty-cta {
  margin-top: 1.1rem;
  padding: 0.7rem 1.6rem;
  border: 0;
  border-radius: 10px;
  background: hsla(160, 100%, 37%, 1);
  color: #fff;
  font-size: 0.95rem;
  font-weight: 700;
  cursor: pointer;
}
.empty-cta:hover { background: hsla(160, 100%, 32%, 1); }
/* 확인 모달 */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  padding: 1rem;
}
.modal {
  position: relative;
  width: 100%;
  max-width: 340px;
  padding: 1.5rem 1.25rem calc(1.25rem + env(safe-area-inset-bottom));
  background: var(--color-background);
  border: 1px solid var(--color-border);
  border-radius: 12px;
}
.modal h2 { font-size: 1.05rem; margin: 0 0 0.6rem; }
.confirm-body { margin: 0 0 1rem; font-size: 0.9rem; line-height: 1.5; white-space: pre-line; }
.buttons { display: flex; justify-content: flex-end; gap: 0.5rem; }
.fade-enter-active, .fade-leave-active { transition: opacity 0.15s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
</style>
