<script setup>
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
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 recurrings = ref([])

// 무료 회원 정기결제 등록 한도(써보고 → 업셀). 유료는 무제한. 백엔드에서도 강제.
const FREE_RECURRING_LIMIT = 2
const atRecurringLimit = computed(
  () => !auth.isPremium && recurrings.value.length >= FREE_RECURRING_LIMIT,
)
const loading = ref(false)
const error = ref(null)

function won(n) { return (n ?? 0).toLocaleString('ko-KR') }
function typeLabel(t) {
  return t === 'INCOME' ? '수입' : t === 'TRANSFER' ? '이체' : '지출'
}
function freqLabel(r) {
  if (r.frequency === 'MONTHLY') return `매월 ${r.dayOfMonth}일`
  return `매년 ${r.monthOfYear}/${r.dayOfMonth}`
}

function payKey(r) {
  if (r.frequency === 'YEARLY') return (r.monthOfYear || 0) * 100 + (r.dayOfMonth || 0)
  return r.dayOfMonth || 0
}

const PERIODS = [
  { key: 'MONTH', label: '월간 거래', freqs: ['MONTHLY'] },
  { key: 'YEAR',  label: '년간 거래', freqs: ['YEARLY'] },
]
const grouped = computed(() =>
  PERIODS.map((p) => {
    const items = recurrings.value.filter((r) => p.freqs.includes(r.frequency))
    const catMap = {}
    for (const r of items) {
      const cat = r.type === 'TRANSFER' ? '이체' : r.category || '미분류'
      if (!catMap[cat]) catMap[cat] = { category: cat, items: [], subtotal: 0, minKey: Infinity }
      catMap[cat].items.push(r)
      catMap[cat].minKey = Math.min(catMap[cat].minKey, payKey(r))
      if (r.active) catMap[cat].subtotal += r.amount || 0
    }
    const cats = Object.values(catMap)
    cats.forEach((c) => c.items.sort((a, b) => payKey(a) - payKey(b)))
    cats.sort((a, b) => a.minKey - b.minKey || a.category.localeCompare(b.category, 'ko'))
    const total = items.filter((r) => r.active).reduce((s, r) => s + (r.amount || 0), 0)
    return { ...p, cats, total, count: items.length }
  }).filter((g) => g.count > 0),
)

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

async function runNow() {
  try {
    const res = await accountApi.runRecurrings()
    alert(`${res.generated}건의 정기결제가 반영되었습니다.`)
    await load()
  } catch (e) {
    alert(e.response?.data?.message || '반영에 실패했습니다.')
  }
}

async function openCreate() {
  if (atRecurringLimit.value) {
    const go = await dialog.confirm(
      `무료 회원은 정기결제를 ${FREE_RECURRING_LIMIT}개까지 등록할 수 있어요.\n유료로 업그레이드하면 무제한이에요.`,
      { title: '등록 한도', okText: '업그레이드', cancelText: '닫기' },
    )
    if (go) router.push('/upgrade')
    return
  }
  router.push('/account/recurrings/new')
}
function openEdit(r) {
  router.push(`/account/recurrings/${r.id}/edit`)
}

async function remove(r) {
  if (!(await dialog.confirm(`'${r.title}' 정기결제를 삭제할까요?\n이미 생성된 내역은 유지됩니다.`, { title: '정기결제 삭제', danger: true }))) return
  try {
    await accountApi.removeRecurring(r.id)
    await load()
  } catch (e) {
    alert(e.response?.data?.message || '삭제에 실패했습니다.')
  }
}

onMounted(load)
</script>

<template>
  <section class="recur">
    <p class="hint">등록한 주기에 맞춰 가계부 진입 시 자동으로 <b>'확인 필요'</b> 내역이 생성됩니다(중복 없이). 가계부에서 실제 결제·이체를 확인한 뒤 <b>'확인'</b>을 눌러 확정하세요.</p>
    <div class="recur-actions">
      <IconBtn icon="refresh" title="지금 반영" @click="runNow" />
      <IconBtn icon="plus" title="정기결제 추가" variant="primary" @click="openCreate" />
    </div>
    <p v-if="atRecurringLimit" class="msg recur-limit">
      무료 {{ FREE_RECURRING_LIMIT }}개까지 등록 완료 ·
      <RouterLink to="/upgrade" class="recur-upsell">유료 무제한 →</RouterLink>
    </p>

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

    <div v-else-if="recurrings.length" class="recur-groups">
      <section v-for="g in grouped" :key="g.key" class="period-group">
        <div class="period-head">
          <h2>{{ g.label }}</h2>
          <span class="period-total">합계 {{ won(g.total) }}</span>
        </div>
        <div v-for="c in g.cats" :key="c.category" class="cat-group">
          <div class="cat-head">
            <span class="cat-name">{{ c.category }}</span>
            <span class="cat-subtotal">소계 {{ won(c.subtotal) }}</span>
          </div>
          <ul class="recur-list">
            <li v-for="r in c.items" :key="r.id" class="recur-row" :class="{ inactive: !r.active }">
              <div class="info">
                <div class="line1">
                  <span class="title">{{ r.title }}</span>
                  <span class="type-badge" :class="r.type.toLowerCase()">{{ typeLabel(r.type) }}</span>
                  <span v-if="!r.active" class="off">중지</span>
                </div>
                <div class="sub">{{ freqLabel(r) }} · {{ won(r.amount) }}</div>
                <div v-if="r.nextDate" class="next">다음 {{ r.nextDate }}</div>
              </div>
              <div class="actions">
                <IconBtn icon="edit" title="수정" size="sm" @click="openEdit(r)" />
                <IconBtn icon="trash" title="삭제" variant="danger" size="sm" @click="remove(r)" />
              </div>
            </li>
          </ul>
        </div>
      </section>
    </div>
    <p v-else-if="!loading" class="msg">등록된 정기결제가 없습니다.</p>
  </section>
</template>

<style scoped>
.recur {
  max-width: 640px;
  margin: 0 auto;
}
.hint {
  font-size: 0.85rem;
  opacity: 0.7;
  margin: 0.5rem 0 1rem;
}
.recur-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
button {
  padding: 0.45rem 0.85rem;
  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); }

.recur-groups { margin-top: 0.5rem; }
.period-group { margin-bottom: 1.5rem; }
.period-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-bottom: 0.3rem;
  border-bottom: 2px solid var(--color-border);
  margin-bottom: 0.5rem;
}
.period-head h2 { font-size: 1.1rem; font-weight: 700; }
.period-total { font-size: 0.95rem; font-weight: 700; color: hsla(160, 100%, 37%, 1); }
.cat-group { margin-bottom: 0.6rem; }
.cat-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 0.25rem 0.1rem;
  background: var(--color-background-soft);
  border-radius: 4px;
}
.cat-name    { font-size: 0.88rem; font-weight: 600; }
.cat-subtotal { font-size: 0.82rem; font-weight: 600; opacity: 0.8; }
.recur-list { list-style: none; padding-left: 0; margin: 0; }
.recur-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--color-border);
}
.info { flex: 1; min-width: 0; }
.recur-row.inactive { opacity: 0.55; }
.line1 { display: flex; align-items: center; gap: 0.4rem; }
.title { font-weight: 600; }
.type-badge {
  font-size: 0.72rem;
  border: 1px solid var(--color-border);
  border-radius: 3px;
  padding: 0.05rem 0.35rem;
}
.type-badge.income  { color: #2e7d32; border-color: #2e7d32; }
.type-badge.expense { color: #c0392b; border-color: #c0392b; }
.off  { font-size: 0.72rem; opacity: 0.6; }
.sub  { font-size: 0.83rem; opacity: 0.75; margin-top: 0.15rem; }
.next { font-size: 0.78rem; opacity: 0.6; margin-top: 0.1rem; }
.actions { display: flex; gap: 0.4rem; flex-shrink: 0; }
.actions button { padding: 0.2rem 0.55rem; font-size: 0.82rem; }
.msg { margin: 0.75rem 0; }
.msg.error { color: #c0392b; }
.msg.recur-limit { color: #b8860b; font-size: 0.85rem; }
.recur-upsell { color: hsla(160, 100%, 37%, 1); font-weight: 700; }
</style>
