<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import api from '../api';
import { formatMoney, formatMoneyCompact } from '../utils/localeDisplay';
import GoldSpinner from '../components/GoldSpinner.vue';
import { usePullToRefresh } from '../composables/usePullToRefresh';
import { useOnLocaleChange } from '../composables/useOnLocaleChange';

import { parseCashbackApiData, type CashbackRecord } from '../utils/cashback';

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

const highlightBatchNo = computed(() => {
  const q = route.query.batchNo;
  return typeof q === 'string' ? q.trim() : '';
});

const items = ref<CashbackRecord[]>([]);
const loading = ref(false);
const initialLoading = ref(true);
const page = ref(1);
const hasMore = ref(true);

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

const totalAmount = computed(() =>
  items.value.reduce((sum, row) => sum + Math.abs(parseFloat(row.amount) || 0), 0),
);

function formatPeriod(start: string, end: string) {
  const opts: Intl.DateTimeFormatOptions = { month: '2-digit', day: '2-digit' };
  const s = new Date(start).toLocaleDateString(locale.value, opts);
  const e = new Date(end).toLocaleDateString(locale.value, opts);
  return `${s} – ${e}`;
}

function formatRate(rate: string) {
  const n = parseFloat(rate);
  if (!Number.isFinite(n)) return rate;
  return `${(n * 100).toFixed(2)}%`;
}

function formatTime(v: string | null) {
  if (!v) return '—';
  return new Date(v).toLocaleString(locale.value, {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  });
}

async function fetchRecords(p = 1) {
  if (loading.value) return;
  loading.value = true;
  try {
    const { data } = await api.get('/player/cashbacks', { params: { page: p } });
    const newItems = parseCashbackApiData(data.data);
    
    if (p === 1) {
      items.value = newItems;
    } else {
      items.value = [...items.value, ...newItems];
    }
    
    const pageSize = 20;
    hasMore.value = newItems.length >= pageSize;
    page.value = p;
  } catch {
    if (p === 1) items.value = [];
  } finally {
    loading.value = false;
    initialLoading.value = false;
  }
}

useOnLocaleChange(() => {
  items.value = [];
  page.value = 1;
  hasMore.value = true;
  initialLoading.value = true;
  fetchRecords(1);
});

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

onMounted(() => {
  fetchRecords(1);
  observer = new IntersectionObserver(
    (entries) => {
      if (entries[0].isIntersecting && hasMore.value && !loading.value) {
        fetchRecords(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="cashback-page">
    <div class="top-bar">
      <button type="button" class="back-btn" @click="router.back()">
        &#x2039; {{ t('history.back') }}
      </button>
    </div>

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

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

    <template v-else>
      <div class="hero">
        <span class="hero-amount">{{ formatMoney(totalAmount, locale) }}</span>
        <span class="hero-sub">
          {{ t('cashback.total_received') }}
          <template v-if="items.length">
            · {{ t('cashback.record_count', { n: items.length }) }}
          </template>
        </span>
      </div>

      <p class="ledger-hint">{{ t('cashback.ledger_hint') }}</p>

      <p v-if="items.length" class="section-title">{{ t('cashback.list_title') }}</p>

      <div v-if="items.length" class="list-card">
        <article
          v-for="row in items"
          :key="row.id"
          class="record-row"
          :class="{ 'record-row--highlight': highlightBatchNo && row.batchNo === highlightBatchNo }"
        >
          <div class="row-main">
            <div class="row-left">
              <span class="row-amount">{{ formatMoney(row.amount, locale) }}</span>
              <span class="row-period">{{ formatPeriod(row.periodStart, row.periodEnd) }}</span>
            </div>
            <span class="row-rate">{{ formatRate(row.rate) }}</span>
          </div>
          <div class="row-detail">
            <span>{{ t('cashback.effective_stake') }} {{ formatMoneyCompact(row.effectiveStake, locale) }}</span>
            <span>{{ t('cashback.bet_count', { n: row.betCount }) }}</span>
          </div>
          <div class="row-foot">
            <span class="row-batch">{{ row.batchNo }}</span>
            <span class="row-time">{{ formatTime(row.confirmedAt ?? row.createdAt) }}</span>
          </div>
        </article>
      </div>

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

      <div v-if="loading && items.length > 0" 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-else class="empty">
        <p class="empty-title">{{ t('cashback.empty') }}</p>
        <p class="empty-hint">{{ t('cashback.empty_hint') }}</p>
      </div>
    </template>
  </div>
</template>

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

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

.back-btn {
  background: none;
  border: none;
  color: var(--primary-light, #d4af37);
  font-size: 15px;
  font-weight: 700;
  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;
}

.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;
}

.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 18px 16px 16px;
  margin-bottom: 14px;
  border-radius: var(--radius, 12px);
  background: linear-gradient(135deg, rgba(212, 175, 55, 0.14), rgba(26, 26, 26, 0.92));
  border: 1px solid rgba(212, 175, 55, 0.28);
  text-align: center;
}

.hero-amount {
  font-size: 28px;
  font-weight: 800;
  color: #f0b90b;
  line-height: 1.2;
  text-shadow: 0 0 20px rgba(240, 185, 11, 0.2);
}

.hero-sub {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.4;
}

.section-title {
  font-size: 10.5px;
  color: #555;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin: 0 0 10px;
}

.list-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  backdrop-filter: blur(10px);
}

.record-row {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}

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

.record-row--highlight {
  background: rgba(212, 175, 55, 0.08);
  box-shadow: inset 3px 0 0 #d4af37;
}

.ledger-hint {
  margin: 0 0 12px;
  font-size: 12px;
  line-height: 1.5;
  color: #666;
}

.row-main {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
}

.row-left {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.row-amount {
  font-size: 17px;
  font-weight: 800;
  color: var(--primary-light);
}

.row-period {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 600;
}

.row-rate {
  flex-shrink: 0;
  font-size: 12px;
  font-weight: 700;
  color: #f0b90b;
  background: rgba(240, 185, 11, 0.1);
  border: 1px solid rgba(240, 185, 11, 0.22);
  border-radius: 999px;
  padding: 3px 10px;
}

.row-detail {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-muted);
}

.row-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed rgba(255, 255, 255, 0.06);
  font-size: 11px;
  color: #666;
}

.row-batch {
  font-family: ui-monospace, monospace;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 58%;
}

.row-time {
  flex-shrink: 0;
}

.empty {
  text-align: center;
  padding: 48px 20px 32px;
}

.empty-title {
  margin: 0 0 8px;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-muted);
}

.empty-hint {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: #666;
}

.sentinel {
  height: 1px;
}

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

.end-hint {
  text-align: center;
  font-size: 12px;
  color: #555;
  font-weight: 600;
  padding: 16px 0 4px;
  letter-spacing: 0.03em;
}
</style>
