<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import api from '../api';
import { formatMoney } from '../utils/localeDisplay';
import { isBetType, isDepositType, isWithdrawType, isCashbackType, txTypeKey, txDisplayType, txAmountClass, txSummaryLabel } from '../utils/walletTx';
import GoldSpinner from '../components/GoldSpinner.vue';
import WalletStatsPanel from '../components/WalletStatsPanel.vue';
import { usePullToRefresh } from '../composables/usePullToRefresh';

const router = useRouter();
const { t, locale } = useI18n();

type Transaction = {
  transactionType: string;
  displayType?: string;
  summary?: string | null;
  summaryKind?: 'opening_bonus' | null;
  referenceType?: string | null;
  amount: string;
  frozenBefore?: string;
  frozenAfter?: string;
  createdAt: string;
  transactionId: string;
};

const items = ref<Transaction[]>([]);
const total = ref(0);
const page = ref(1);
const loading = ref(false);
const initialLoading = ref(true);
const hasMore = ref(true);
const typeFilter = ref('');
const cashbackTotal = ref('0');

const sentinel = ref<HTMLElement | null>(null);
let observer: IntersectionObserver | null = null;

const FILTERS = [
  { key: '', label: 'wallet.filter_all' },
  { key: 'deposit', label: 'wallet.filter_deposit' },
  { key: 'withdraw', label: 'wallet.filter_withdraw' },
  { key: 'bet', label: 'wallet.filter_bet' },
  { key: 'cashback', label: 'wallet.filter_cashback' },
];

const CASHBACK_TYPES = new Set(['CASHBACK', 'CASHBACK_DEPOSIT']);

async function fetchCashbackTotal() {
  try {
    const { data } = await api.get('/player/wallet/transactions/stats');
    const byType = data.data?.byType ?? [];
    let sum = 0;
    for (const g of byType) {
      if (CASHBACK_TYPES.has(g.transactionType?.toUpperCase())) {
        sum += Math.abs(parseFloat(g.totalAmount ?? '0'));
      }
    }
    cashbackTotal.value = sum.toString();
  } catch {
    /* ignore */
  }
}

function txLabel(tx: Transaction): string {
  const key = txTypeKey(txDisplayType(tx));
  if (key) {
    const translated = t(key);
    if (translated !== key) return translated;
  }
  return tx.transactionType;
}

function txSubtitle(tx: Transaction): string {
  return txSummaryLabel(tx, t);
}

function goDetail(tx: Transaction) {
  if (!tx.transactionId) return;
  router.push(`/wallet/transactions/${tx.transactionId}`);
}

async function loadPage(p: number) {
  if (loading.value) return;
  loading.value = true;
  const filterAtRequest = typeFilter.value;
  try {
    const params: Record<string, unknown> = { page: p };
    if (typeFilter.value) params.type = typeFilter.value;
    const { data } = await api.get('/player/wallet/transactions', { params });
    const result = data.data ?? { items: [], total: 0, pageSize: 20 };
    if (filterAtRequest !== typeFilter.value) return;
    total.value = result.total ?? 0;
    const pageSize = result.pageSize ?? 20;
    const newItems = result.items ?? [];
    if (p === 1) {
      items.value = newItems;
    } else {
      items.value = [...items.value, ...newItems];
    }
    hasMore.value = (result.items?.length ?? 0) >= pageSize;
    page.value = p;
  } finally {
    if (filterAtRequest === typeFilter.value) {
      loading.value = false;
      initialLoading.value = false;
    }
  }
}

async function reset() {
  items.value = [];
  total.value = 0;
  page.value = 1;
  hasMore.value = true;
  initialLoading.value = true;
  loading.value = false;
  loadPage(1);
}

function changeFilter(key: string) {
  if (typeFilter.value === key) return;
  typeFilter.value = key;
  reset();
}

const { pullDistance, spinning, progress } = usePullToRefresh({
  onRefresh: async () => { await loadPage(1); await fetchCashbackTotal(); },
});

onMounted(() => {
  loadPage(1);
  fetchCashbackTotal();
  observer = new IntersectionObserver(
    (entries) => {
      if (entries[0].isIntersecting && hasMore.value && !loading.value) {
        loadPage(page.value + 1);
      }
    },
    { rootMargin: '200px' },
  );
  if (sentinel.value) observer.observe(sentinel.value);
});

onUnmounted(() => {
  observer?.disconnect();
});

const pullIndicatorStyle = () => ({
  height: `${pullDistance.value}px`,
  opacity: Math.min(pullDistance.value / 48, 1),
});
</script>

<template>
  <div class="wallet-detail-page">
    <header class="top-bar sub-toolbar">
      <button class="back-btn" type="button" @click="router.back()">&#x2039; {{ t('history.back') }}</button>
    </header>

    <div
      class="pull-indicator"
      :style="pullIndicatorStyle()"
    >
      <GoldSpinner v-if="spinning" :size="28" :progress="progress" :active="spinning" />
    </div>

    <div v-if="initialLoading" class="state">
      <GoldSpinner :size="36" />
      <span class="loading-text">{{ t('bet.loading') }}</span>
    </div>

    <template v-else>
      <WalletStatsPanel class="stats-panel" :items="items" :cashback-total="cashbackTotal" />

      <div class="filter-tabs">
        <button
          v-for="f in FILTERS"
          :key="f.key"
          type="button"
          class="filter-tab"
          :class="{ active: typeFilter === f.key }"
          @click="changeFilter(f.key)"
        >
          {{ t(f.label) }}
        </button>
      </div>

      <div v-if="items.length" class="tx-list">
        <button
          v-for="tx in items"
          :key="tx.transactionId"
          type="button"
          class="tx-row"
          @click="goDetail(tx)"
        >
          <div class="tx-col-left">
            <span class="tx-type">{{ txLabel(tx) }}</span>
            <span v-if="txSubtitle(tx)" class="tx-summary">{{ txSubtitle(tx) }}</span>
            <span class="tx-time">{{ new Date(tx.createdAt).toLocaleString() }}</span>
          </div>
          <div class="tx-col-right">
            <span :class="txAmountClass(tx.amount)">
              {{ formatMoney(tx.amount, locale) }}
            </span>
            <span class="tx-arrow">&#x203A;</span>
          </div>
        </button>
      </div>

      <div ref="sentinel" class="sentinel" />

      <div v-if="loading" class="load-more-spinner">
        <GoldSpinner :size="24" />
      </div>

      <div v-else-if="!hasMore && items.length > 0" class="end-hint">
        {{ t('common.no_more') }}
      </div>

      <div v-if="!items.length && !initialLoading" class="empty">
        {{ t('wallet.no_records') }}
      </div>
    </template>
  </div>
</template>

<style scoped>
.wallet-detail-page {
  padding-bottom: 24px;
}

.stats-panel {
  margin-bottom: var(--space-section);
}

.top-bar {
  margin-bottom: 4px;
}

.back-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 15px;
  font-weight: 500;
  padding: 4px 0 8px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 2px;
}

.pull-indicator {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  transition: height 0.15s ease;
}

.filter-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: var(--space-section);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.filter-tabs::-webkit-scrollbar { display: none; }

.filter-tab {
  flex-shrink: 0;
  padding: 8px 16px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  background: var(--bg-card);
  border: 1px solid var(--border);
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}

.filter-tab.active {
  color: var(--text);
  background: var(--bg-elevated);
  border-color: var(--border-strong);
  font-weight: 600;
}

.state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
  color: var(--text-muted);
  padding: 56px 20px;
  font-weight: 600;
  font-size: 14px;
}

.loading-text {
  font-size: 13px;
}

.tx-list {
  margin-bottom: 0;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.tx-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  text-align: left;
  font-size: 14px;
  padding: 12px 14px;
  border: none;
  border-bottom: 1px solid var(--border);
  background: transparent;
  cursor: pointer;
}

.tx-row:last-child {
  border-bottom: none;
}

.tx-row:active {
  background: var(--bg-hover);
}

.tx-col-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  flex: 1;
}

.tx-col-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.tx-summary {
  font-size: 11px;
  color: var(--text-muted);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tx-type { font-weight: 600; color: var(--text); letter-spacing: -0.01em; }
.pos { color: var(--success); font-weight: 600; font-size: 14px; font-variant-numeric: tabular-nums; }
.neg { color: var(--text); font-weight: 600; font-size: 14px; font-variant-numeric: tabular-nums; }
.zero { color: var(--text-muted); font-weight: 600; font-size: 14px; font-variant-numeric: tabular-nums; }
.tx-time { font-size: 11px; color: var(--text-dim); }
.tx-arrow { font-size: 15px; color: var(--text-dim); font-weight: 400; line-height: 1; }

.sentinel {
  height: 1px;
}

.load-more-spinner {
  display: flex;
  justify-content: center;
  padding: 20px 0 8px;
}

.end-hint {
  text-align: center;
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 600;
  padding: 16px 0 4px;
  letter-spacing: 0.03em;
}

.empty { text-align: center; color: var(--text-muted); padding: 40px 16px; font-weight: 600; }
</style>
