<script setup>
import { computed, onBeforeUnmount, onMounted, ref, watch, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import Sortable from 'sortablejs'
import { accountApi } from '@/api/accountApi'
import { useDialog } from '@/composables/dialog'
import { useAuthStore } from '@/stores/auth'
import IconBtn from '@/components/ui/IconBtn.vue'

const dialog = useDialog()
const auth = useAuthStore()
const router = useRouter()

const TABS = [
  { key: 'BANK', label: '은행계좌' },
  { key: 'CASH', label: '현금' },
  { key: 'CARD', label: '신용/체크카드' },
  { key: 'LOAN', label: '대출' },
  { key: 'MINUS', label: '마이너스통장' },
  { key: 'INVEST', label: '투자' },
]
const wallets = ref([])
const networth = ref({ totalAssets: 0, totalLiabilities: 0, netWorth: 0 })
const loading = ref(false)
const error = ref(null)
// 순서변경(잠금) 모드 — 평소엔 잠금(드래그·핸들 숨김), 켤 때만 드래그 가능
const reorderMode = ref(false)
// 종류별 그룹(탭 제거) — TABS 순서로, 계좌가 있는 종류만 노출
const groups = computed(() =>
  TABS.map((t) => ({ ...t, wallets: wallets.value.filter((w) => w.type === t.key) })).filter(
    (g) => g.wallets.length,
  ),
)

// 계좌 클릭 → 별도 상세 화면(계좌별 내역)
function goDetail(w) {
  router.push(`/account/wallets/${w.id}`)
}
// 추가/수정은 별도 화면으로(모달 → 화면전환)
function openCreate() {
  router.push('/account/wallets/new')
}
function openEdit(w) {
  router.push(`/account/wallets/${w.id}/edit`)
}

// ===== 드래그앤드랍 순서 변경 (종류별 그룹마다 SortableJS, 터치 지원) =====
let sortables = []
function destroySortables() {
  sortables.forEach((s) => s.destroy())
  sortables = []
}
function initSortables() {
  destroySortables()
  if (!reorderMode.value) return // 잠금 상태에선 드래그 비활성화
  document.querySelectorAll('.wallet-group-list').forEach((el) => {
    sortables.push(
      Sortable.create(el, {
        handle: '.drag-handle',
        animation: 150,
        onEnd: (evt) => {
          if (evt.oldIndex === evt.newIndex) return
          const type = el.dataset.type
          const ids = [...el.querySelectorAll(':scope > .wallet-item')].map((li) => Number(li.dataset.id))
          // 낙관적 반영: Sortable 이 옮긴 DOM 순서에 맞춰 데이터도 재정렬(Vue 재렌더 정합)
          const byId = new Map(wallets.value.map((w) => [w.id, w]))
          const moved = ids.map((id) => byId.get(id)).filter(Boolean)
          wallets.value = [...moved, ...wallets.value.filter((w) => w.type !== type)]
          persistOrder(type, ids)
        },
      }),
    )
  })
}
// 순서변경 모드 토글 시 드래그 바인딩/해제
watch(reorderMode, async () => {
  await nextTick()
  initSortables()
})
async function persistOrder(type, ids) {
  try {
    await accountApi.reorderWallets(type, ids)
    await load()
  } catch (e) {
    alert(e.response?.data?.message || '순서 저장에 실패했습니다.')
    await load()
  }
}

function won(n) {
  return (n ?? 0).toLocaleString('ko-KR')
}

// 계좌번호 마스킹: 끝 4자리만 노출(구분자 유지), 눈 버튼으로 전체 보기 토글
const revealedAccts = ref(new Set())
function maskAccount(num) {
  if (!num) return ''
  const digitCount = (num.match(/\d/g) || []).length
  if (digitCount <= 4) return num
  const keep = digitCount - 4
  let seen = 0
  return num.replace(/\d/g, (d) => {
    seen += 1
    return seen <= keep ? '*' : d
  })
}
function toggleReveal(id) {
  const s = new Set(revealedAccts.value)
  s.has(id) ? s.delete(id) : s.add(id)
  revealedAccts.value = s
}
async function load() {
  loading.value = true
  error.value = null
  try {
    const [ws, nw] = await Promise.all([accountApi.wallets(), accountApi.netWorth()])
    wallets.value = ws
    networth.value = nw
  } catch (e) {
    error.value = e.response?.data?.message || '불러오지 못했습니다.'
  } finally {
    loading.value = false
  }
  // 그룹 렌더 후 종류별 드래그 재바인딩
  await nextTick()
  initSortables()
}

async function remove(w) {
  if (!(await dialog.confirm(`'${w.name}' 을(를) 삭제할까요?`, { title: '삭제', danger: true }))) return
  try {
    await accountApi.removeWallet(w.id)
    await load()
  } catch (e) {
    alert(e.response?.data?.message || '삭제에 실패했습니다.')
  }
}

function cardTypeLabel(v) {
  return v === 'CHECK' ? '체크' : v === 'CREDIT' ? '신용' : ''
}
function loanMethodLabel(v) {
  return v === 'EQUAL_PAYMENT' ? '원리금균등' : v === 'EQUAL_PRINCIPAL' ? '원금균등' : v === 'BULLET' ? '만기일시' : ''
}

onMounted(load)
onBeforeUnmount(destroySortables)
</script>

<template>
  <section class="wallet">

    <!-- 순자산 요약 -->
    <div class="networth">
      <div class="nw-card">
        <span class="label">총자산</span>
        <span class="value asset">{{ won(networth.totalAssets) }}</span>
      </div>
      <div class="nw-card">
        <span class="label">총부채</span>
        <span class="value debt">{{ won(networth.totalLiabilities) }}</span>
      </div>
      <div class="nw-card">
        <span class="label">순자산</span>
        <span class="value">{{ won(networth.netWorth) }}</span>
      </div>
    </div>

    <div class="wallet-head">
      <button
        v-if="wallets.length > 1"
        type="button" class="text-btn reorder-btn" :class="{ active: reorderMode }"
        @click="reorderMode = !reorderMode"
      >{{ reorderMode ? '완료' : '순서변경' }}</button>
      <IconBtn class="tab-add" icon="plus" title="계좌 추가" variant="primary" @click="openCreate" />
    </div>

    <p v-if="reorderMode" class="msg reorder-hint">≡ 손잡이를 끌어 순서를 바꾸세요. 끝나면 <b>완료</b>를 누르세요.</p>
    <p v-if="error" class="msg error">{{ error }}</p>
    <p v-if="loading" class="msg">불러오는 중...</p>

    <template v-if="!loading && groups.length">
      <section v-for="g in groups" :key="g.key" class="wallet-group">
        <h3 class="wg-title">{{ g.label }}</h3>
        <ul class="wallet-list wallet-group-list" :data-type="g.key">
          <li v-for="w in g.wallets" :key="w.id" :data-id="w.id" class="wallet-item">
            <div class="wallet-row">
              <span v-if="reorderMode" class="drag-handle" title="드래그하여 순서 변경">≡</span>
              <div class="info">
                <div class="line1">
                  <span
                    class="name" :class="{ link: !reorderMode && w.type !== 'INVEST' }"
                    @click="!reorderMode && w.type !== 'INVEST' && goDetail(w)"
                  >{{ w.name }}</span>
                  <span v-if="w.type === 'CARD'" class="badge">{{ cardTypeLabel(w.cardType) }}</span>
                </div>
                <span class="sub">
                  {{ w.issuer }}
                  <template v-if="(w.type === 'BANK' || w.type === 'MINUS') && w.accountNumber">
                    · {{ revealedAccts.has(w.id) ? w.accountNumber : maskAccount(w.accountNumber) }}
                    <button
                      type="button" class="acct-eye"
                      :title="revealedAccts.has(w.id) ? '가리기' : '전체 보기'"
                      @click.stop="toggleReveal(w.id)"
                    >{{ revealedAccts.has(w.id) ? '🙈' : '👁' }}</button>
                  </template>
                  <template v-if="w.type === 'LOAN'">
                    <span v-if="w.loanAmount"> · 실행 {{ won(w.loanAmount) }}원</span>
                    <span v-if="w.loanRate"> · {{ w.loanRate }}%<span v-if="w.loanMethod"> / {{ loanMethodLabel(w.loanMethod) }}</span></span>
                  </template>
                </span>
              </div>
              <div class="balance-wrap">
                <div v-if="w.type === 'INVEST'" class="balance">{{ won(w.investedAmount) }}</div>
                <div v-else class="balance" :class="{ neg: w.balance < 0 }">{{ won(w.balance) }}</div>
              </div>
              <div v-if="!reorderMode" class="actions">
                <IconBtn icon="edit" title="수정" size="sm" @click="openEdit(w)" />
                <IconBtn icon="trash" title="삭제" variant="danger" size="sm" @click="remove(w)" />
              </div>
            </div>
          </li>
        </ul>
      </section>
    </template>

    <div v-else-if="!loading" class="empty-state">
      <p class="empty-emoji">🏦</p>
      <p class="empty-title">아직 등록된 계좌가 없어요</p>
      <p class="empty-desc">은행·카드·현금·대출·마이너스통장·투자를 추가해보세요.</p>
      <button type="button" class="empty-cta" @click="openCreate">＋ 계좌 추가</button>
    </div>

  </section>
</template>

<style scoped>
.wallet {
  max-width: 640px;
  margin: 0 auto;
}
.head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}
h1 {
  font-size: 1.5rem;
}
button {
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-background-soft);
  color: var(--color-text);
  cursor: pointer;
}
button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
button.danger {
  border-color: #c0392b;
  color: #c0392b;
}
button.primary {
  border-color: hsla(160, 100%, 37%, 1);
  color: hsla(160, 100%, 37%, 1);
}
.networth {
  display: flex;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
}
.nw-card {
  flex: 1;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 0.7rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.nw-card .label {
  font-size: 0.82rem;
  opacity: 0.7;
}
.nw-card .value {
  font-size: 1.1rem;
  font-weight: 700;
}
.nw-card .value.asset {
  color: #2e7d32;
}
.nw-card .value.debt {
  color: #c0392b;
}
.wallet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}
.tab-add {
  flex-shrink: 0;
  margin-left: auto;
}
.text-btn {
  border: 0;
  background: transparent;
  color: var(--color-text);
  opacity: 0.75;
  font-size: 0.88rem;
  padding: 0.35rem 0.5rem;
  cursor: pointer;
}
.reorder-btn.active {
  color: hsla(160, 100%, 37%, 1);
  font-weight: 700;
  opacity: 1;
}
.reorder-hint {
  font-size: 0.82rem;
  opacity: 0.7;
  margin: 0 0 0.6rem;
}
.wallet-group {
  margin-bottom: 1.4rem;
}
.wg-title {
  font-size: 0.9rem;
  font-weight: 700;
  opacity: 0.7;
  margin: 0 0 0.35rem;
  padding-bottom: 0.3rem;
  border-bottom: 1px solid var(--color-border);
}
.wallet-list {
  list-style: none;
  padding-left: 0;
  margin: 0;
}
.wallet-item {
  border-bottom: 1px solid var(--color-border);
}
.wallet-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 0;
}
.drag-handle {
  cursor: grab;
  user-select: none;
  opacity: 0.45;
  font-size: 1.1rem;
  padding: 0 0.15rem;
  touch-action: none;
}
.drag-handle:active {
  cursor: grabbing;
}
.chevron {
  width: 1rem;
  opacity: 0.6;
  font-size: 0.8rem;
}
.entry-drop {
  padding: 0.25rem 0 0.75rem 1.6rem;
}
.drop-msg {
  font-size: 0.85rem;
  opacity: 0.65;
  padding: 0.5rem 0;
}
.refresh-note {
  font-size: 0.82rem;
  opacity: 0.6;
}
.manual-note {
  padding: 0.6rem 0.2rem;
  font-size: 0.85rem;
}
.manual-note p {
  margin: 0 0 0.3rem;
}
.manual-note .manual-sub {
  opacity: 0.6;
  font-size: 0.78rem;
  margin: 0;
}
.invest-figs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}
.invest-figs .fig {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.5rem 0.6rem;
  background: var(--color-background-soft, #f4f5f7);
  border-radius: 8px;
}
.invest-figs .fig-k {
  font-size: 0.72rem;
  opacity: 0.6;
}
.invest-figs .fig-v {
  font-size: 0.95rem;
  font-weight: 600;
}
.invest-figs .fig-v.pos {
  color: #1a7f37;
}
.invest-figs .fig-v.neg {
  color: #cf222e;
}
.month-nav {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0 0.4rem;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 0.3rem;
}
.mn-btn {
  width: 1.8rem;
  height: 1.8rem;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-background-soft);
  color: var(--color-text);
  cursor: pointer;
  line-height: 1;
}
.mn-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.mn-label {
  font-weight: 700;
  font-size: 0.9rem;
  min-width: 4.2rem;
  text-align: center;
}
.mn-sum {
  margin-left: auto;
  font-size: 0.82rem;
  font-weight: 600;
}
.mn-sum.pos {
  color: #2e7d32;
}
.mn-sum.neg {
  color: #c0392b;
}
.drop-list {
  list-style: none;
}
.drop-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.35rem 0;
  font-size: 0.85rem;
  border-top: 1px dashed var(--color-border);
}
.d-date {
  width: 3rem;
  opacity: 0.7;
  white-space: nowrap;
}
.d-desc {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.d-amount {
  white-space: nowrap;
  font-weight: 600;
}
.d-amount.pos {
  color: #2e7d32;
}
.d-amount.neg {
  color: #c0392b;
}
.info {
  flex: 1;
  min-width: 0;
}
.line1 {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.name {
  font-weight: 600;
}
.name.link {
  cursor: pointer;
  color: hsla(160, 100%, 37%, 1);
}
.name.link:active {
  opacity: 0.7;
}
.badge {
  font-size: 0.72rem;
  border: 1px solid var(--color-border);
  border-radius: 3px;
  padding: 0.05rem 0.35rem;
}
.sub {
  font-size: 0.82rem;
  opacity: 0.7;
}
.acct-eye {
  border: 0;
  background: transparent;
  padding: 0 0.15rem;
  font-size: 0.78rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
}
.acct-eye:hover {
  opacity: 1;
}
.balance-wrap {
  text-align: right;
  white-space: nowrap;
}
.balance {
  font-weight: 700;
  white-space: nowrap;
}
.balance.neg {
  color: #c0392b;
}
.gain {
  font-size: 0.76rem;
  font-weight: 600;
}
.gain.pos {
  color: #2e7d32;
}
.gain.neg {
  color: #c0392b;
}
.form-hint {
  font-size: 0.76rem;
  opacity: 0.65;
  margin: -0.2rem 0 0.1rem;
}
.actions {
  display: flex;
  gap: 0.4rem;
}
.actions button {
  padding: 0.2rem 0.55rem;
  font-size: 0.82rem;
}
.msg {
  margin: 1rem 0;
}
/* 신규 유저 빈 상태 */
.empty-state {
  text-align: center;
  padding: 2.4rem 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);
}
.msg.error {
  color: #c0392b;
}
.msg.wallet-limit {
  color: #b8860b;
  font-size: 0.85rem;
}

.wallet-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.wallet-form label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.85rem;
}
.wallet-form input,
.wallet-form select {
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-background-soft);
  color: var(--color-text);
}
/* 배지형 선택 */
.field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.field-label {
  font-size: 0.82rem;
  opacity: 0.7;
}
.chip-group {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}
.chip {
  padding: 0.28rem 0.75rem;
  border: 1.5px solid var(--color-border);
  border-radius: 100px;
  background: var(--color-background-soft);
  color: var(--color-text);
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  line-height: 1.4;
  transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.chip:disabled { opacity: 0.45; cursor: not-allowed; }
.chip.active {
  border-color: hsla(160, 100%, 37%, 1);
  background: hsla(160, 100%, 37%, 1);
  color: #fff;
}
.buttons {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.5rem;
}
@media (max-width: 768px) {
  .wallet {
    max-width: 100%;
  }
  .networth {
    gap: 0.5rem;
  }
  .nw-card {
    padding: 0.5rem 0.6rem;
  }
  .nw-card .value {
    font-size: 0.95rem;
  }
  .tabs button {
    padding: 0.55rem 0.6rem;
    font-size: 0.9rem;
  }
  /* 한 줄 유지: 이름(축소) · 잔액 · 아이콘 */
  .wallet-row {
    column-gap: 0.4rem;
  }
  .info {
    flex: 1;
    min-width: 0;
  }
  /* 이름은 한 줄(말줄임), sub(예수금·주식 등)는 자연 줄바꿈 — 손익과 겹치지 않게 */
  .line1 {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .sub {
    word-break: break-all;
  }
  .wallet-row {
    align-items: flex-start;
  }
  .balance {
    font-size: 0.95rem;
  }
  .balance-wrap {
    flex-shrink: 0;
    padding-left: 0.3rem;
  }
  .actions {
    flex-shrink: 0;
    gap: 0.3rem;
  }
}
</style>
