<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 GoldSpinner from '../components/GoldSpinner.vue';
import { usePullToRefresh } from '../composables/usePullToRefresh';
import { formatMoney } from '../utils/localeDisplay';
import {
  auditActionTone,
  auditActorSecondary,
  formatDepositAuditRemark,
  shouldShowAuditRejectInTimeline,
} from '../utils/depositAuditDisplay';

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

interface DepositAuditLog {
  id: string;
  action: string;
  actorType: string;
  statusBefore: string | null;
  statusAfter: string;
  amount: string | null;
  approvedAmount: string | null;
  remark: string | null;
  createdAt: string;
}

interface DepositOrder {
  id: string;
  orderNo: string;
  paymentMethodId?: string;
  methodType: string;
  amount: string;
  status: string;
  approvedAmount: string | null;
  rejectReason: string | null;
  remark: string | null;
  createdAt: string;
  reviewedAt: string | null;
  paymentMethodName: string | null;
  auditLogs?: DepositAuditLog[];
}

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

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

const selectedOrder = ref<DepositOrder | null>(null);

async function fetchOrders(p = 1) {
  if (loading.value) return;
  loading.value = true;
  try {
    const { data } = await api.get('/player/deposit-orders', { params: { page: p } });
    const result = data.data ?? { items: [], total: 0, pageSize: 20 };
    const newItems = result.items ?? [];

    if (p === 1) {
      items.value = newItems;
    } else {
      items.value = [...items.value, ...newItems];
    }

    total.value = result.total ?? 0;
    const pageSize = result.pageSize ?? 20;
    hasMore.value = newItems.length >= pageSize && items.value.length < total.value;
    page.value = p;
  } catch { /* */ } finally {
    loading.value = false;
    initialLoading.value = false;
  }
}

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

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

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

function statusClass(s: string) {
  if (s === 'APPROVED') return 'status-approved';
  if (s === 'REJECTED') return 'status-rejected';
  return 'status-pending';
}

function statusLabel(s: string) {
  if (s === 'APPROVED') return t('recharge.status_approved');
  if (s === 'REJECTED') return t('recharge.status_rejected');
  return t('recharge.status_pending');
}

function goBack() {
  router.push('/wallet');
}

function goRecharge() {
  router.push('/wallet/recharge');
}

function openDetail(order: DepositOrder) {
  selectedOrder.value = order;
}

function closeDetail() {
  selectedOrder.value = null;
}

function reapply(order: DepositOrder) {
  const query: Record<string, string> = {
    orderId: order.id,
    methodType: order.methodType,
    amount: order.amount,
  };
  if (order.paymentMethodId) {
    query.methodId = order.paymentMethodId;
  }
  router.push({ path: '/wallet/recharge', query });
}

function normalizeText(value: string | null | undefined) {
  return value?.trim() ?? '';
}

/** Backend sets remark = rejectReason on reject; show one line only. */
function orderNote(order: DepositOrder): { label: string; text: string } | null {
  const rejectReason = normalizeText(order.rejectReason);
  const remark = normalizeText(order.remark);

  if (order.status === 'REJECTED') {
    const text = rejectReason || remark;
    if (!text) return null;
    return { label: t('recharge.reject_reason'), text };
  }

  if (remark) {
    return { label: t('recharge.remark'), text: remark };
  }

  return null;
}

function orderNoteLine(order: DepositOrder) {
  const note = orderNote(order);
  return note ? `${note.label}: ${note.text}` : null;
}

function auditActionLabel(action: string) {
  const key = `recharge.audit_${action.toLowerCase()}` as const;
  const translated = t(key);
  return translated !== key ? translated : action;
}

function auditStepClass(action: string) {
  return `audit-step--${auditActionTone(action)}`;
}

function formatAuditTime(iso: string) {
  return new Date(iso).toLocaleString(undefined, {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function formatOrderTime(iso: string) {
  return new Date(iso).toLocaleString();
}

function auditRemarkForTimeline(log: DepositAuditLog, order: DepositOrder) {
  if (log.action === 'REJECTED' && !shouldShowAuditRejectInTimeline(log, order.rejectReason)) {
    return null;
  }
  return formatDepositAuditRemark(log, t);
}

function auditLogsForDisplay(order: DepositOrder) {
  return [...(order.auditLogs ?? [])]
    .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
    .map((log) => ({
      log,
      actor: auditActorSecondary(log, t),
      remark: auditRemarkForTimeline(log, order),
    }));
}

function auditNoteLine(text: string) {
  return `${t('recharge.audit_remark_label')}: ${text}`;
}

function auditNoteDisplayText(remark: { kind: 'note'; text: string }) {
  if (remark.text === t('wallet.remark_deposit_revoke_generic')) {
    return remark.text;
  }
  return auditNoteLine(remark.text);
}

function auditStepCount(order: DepositOrder) {
  return order.auditLogs?.length ?? 0;
}
</script>

<template>
  <div class="recharge-history-page">
    <div class="page-header">
      <button class="back-btn" @click="goBack">‹</button>
      <h2>{{ t('recharge.history_title') }}</h2>
      <button class="recharge-btn" @click="goRecharge">+ {{ t('recharge.title') }}</button>
    </div>

    <div
      class="pull-indicator"
      :style="{ height: `${pullDistance}px`, opacity: Math.min(pullDistance / 48, 1) }"
    >
      <GoldSpinner v-if="spinning" :size="28" :progress="progress" :active="spinning" />
    </div>

    <div v-if="initialLoading && loading" class="state">
      <GoldSpinner :size="36" />
    </div>

    <template v-else>
      <div v-if="!items.length" class="empty">{{ t('recharge.no_orders') }}</div>

      <div v-else class="order-list">
        <div
          v-for="order in items"
          :key="order.id"
          class="order-card"
          :class="{ rejected: order.status === 'REJECTED' }"
          role="button"
          tabindex="0"
          @click="openDetail(order)"
          @keydown.enter="openDetail(order)"
        >
          <div class="order-header">
            <span class="method-badge" :class="order.methodType === 'BANK' ? 'bank' : 'usdt'">{{ order.methodType }}</span>
            <span :class="['status-badge', statusClass(order.status)]">{{ statusLabel(order.status) }}</span>
          </div>
          <div class="order-body">
            <div class="order-amount">{{ formatMoney(order.amount, locale) }}</div>
            <div v-if="order.approvedAmount && order.approvedAmount !== order.amount" class="approved-amount">
              {{ t('recharge.credited') }}: {{ formatMoney(order.approvedAmount, locale) }}
            </div>
            <div class="order-info-row">
              <span class="info-label">{{ order.paymentMethodName || '-' }}</span>
            </div>
            <div class="order-times">
              <div class="time-row">
                <span class="time-label">{{ t('recharge.apply_time') }}</span>
                <span class="time-value">{{ formatOrderTime(order.createdAt) }}</span>
              </div>
              <div v-if="order.reviewedAt" class="time-row">
                <span class="time-label">{{ t('recharge.review_time') }}</span>
                <span class="time-value">{{ formatOrderTime(order.reviewedAt) }}</span>
              </div>
            </div>
            <div
              v-if="orderNoteLine(order)"
              :class="order.status === 'REJECTED' ? 'reject-reason' : 'order-remark'"
            >
              {{ orderNoteLine(order) }}
            </div>
            <div v-if="auditStepCount(order)" class="card-detail-hint">
              <span class="card-detail-summary">
                {{ t('recharge.audit_summary', { count: auditStepCount(order) }) }}
              </span>
              <span class="card-detail-link">{{ t('recharge.view_detail') }} ›</span>
            </div>
            <button
              v-else
              type="button"
              class="card-detail-link-only"
              @click.stop="openDetail(order)"
            >
              {{ t('recharge.view_detail') }} ›
            </button>
          </div>
        </div>
      </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>
    </template>

    <Teleport to="body">
      <div v-if="selectedOrder" class="detail-overlay" @click.self="closeDetail">
        <div class="detail-modal" role="dialog" aria-modal="true" :aria-label="t('recharge.order_detail')">
          <button type="button" class="detail-close" :aria-label="t('common.close')" @click="closeDetail">✕</button>

          <h3 class="detail-title">{{ t('recharge.order_detail') }}</h3>

          <div class="detail-summary">
            <div class="detail-summary-head">
              <span class="method-badge" :class="selectedOrder.methodType === 'BANK' ? 'bank' : 'usdt'">
                {{ selectedOrder.methodType }}
              </span>
              <span :class="['status-badge', statusClass(selectedOrder.status)]">
                {{ statusLabel(selectedOrder.status) }}
              </span>
            </div>
            <div class="detail-amount">{{ formatMoney(selectedOrder.amount, locale) }}</div>
            <div
              v-if="selectedOrder.approvedAmount && selectedOrder.approvedAmount !== selectedOrder.amount"
              class="approved-amount"
            >
              {{ t('recharge.credited') }}: {{ formatMoney(selectedOrder.approvedAmount, locale) }}
            </div>
            <div class="detail-method-name">{{ selectedOrder.paymentMethodName || '-' }}</div>
            <div class="detail-row">
              <span class="detail-label">{{ t('recharge.apply_time') }}</span>
              <span class="detail-value">{{ formatOrderTime(selectedOrder.createdAt) }}</span>
            </div>
            <div v-if="selectedOrder.reviewedAt" class="detail-row">
              <span class="detail-label">{{ t('recharge.review_time') }}</span>
              <span class="detail-value">{{ formatOrderTime(selectedOrder.reviewedAt) }}</span>
            </div>
            <div
              v-if="orderNoteLine(selectedOrder)"
              :class="selectedOrder.status === 'REJECTED' ? 'reject-reason' : 'order-remark'"
            >
              {{ orderNoteLine(selectedOrder) }}
            </div>
          </div>

          <div v-if="selectedOrder.auditLogs?.length" class="detail-audit">
            <h4 class="detail-audit-title">{{ t('recharge.audit_title') }}</h4>
            <div class="audit-track">
              <div
                v-for="(entry, logIdx) in auditLogsForDisplay(selectedOrder)"
                :key="entry.log.id"
                class="audit-step"
                :class="auditStepClass(entry.log.action)"
              >
                <div class="audit-step-rail" aria-hidden="true">
                  <span class="audit-dot" />
                  <span v-if="logIdx < auditLogsForDisplay(selectedOrder).length - 1" class="audit-line" />
                </div>
                <div class="audit-step-body">
                  <div class="audit-step-head">
                    <span class="audit-step-title">{{ auditActionLabel(entry.log.action) }}</span>
                    <time class="audit-step-time">{{ formatAuditTime(entry.log.createdAt) }}</time>
                  </div>
                  <p v-if="entry.actor" class="audit-step-actor">{{ entry.actor }}</p>
                  <p
                    v-if="entry.log.approvedAmount && entry.log.action === 'APPROVED'"
                    class="audit-step-credited"
                  >
                    {{ t('recharge.audit_credited') }} {{ formatMoney(entry.log.approvedAmount, locale) }}
                  </p>
                  <div
                    v-if="entry.remark?.kind === 'reject'"
                    class="audit-step-box audit-step-box--reject"
                  >
                    <span class="audit-step-box-label">{{ t('recharge.reject_reason') }}</span>
                    <span class="audit-step-box-text">{{ entry.remark.text }}</span>
                  </div>
                  <p v-else-if="entry.remark?.kind === 'note'" class="audit-step-note">
                    {{ auditNoteDisplayText(entry.remark) }}
                  </p>
                </div>
              </div>
            </div>
          </div>

          <button
            v-if="selectedOrder.status === 'REJECTED'"
            type="button"
            class="modal-reapply-btn btn-gold-outline"
            @click.stop="reapply(selectedOrder)"
          >
            {{ t('recharge.reapply') }}
          </button>
        </div>
      </div>
    </Teleport>
  </div>
</template>

<style scoped>
.recharge-history-page { padding: 0 16px 24px; }
.page-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 0; }
.page-header h2 { margin: 0; font-size: 17px; font-weight: 700; color: var(--text); }
.back-btn { background: none; border: none; color: var(--primary); font-size: 24px; cursor: pointer; padding: 0 8px; }
.recharge-btn { background: none; border: none; color: var(--primary); font-size: 13px; cursor: pointer; font-weight: 600; }
.state { display: flex; justify-content: center; padding: 48px; }
.empty { text-align: center; color: var(--text-muted); padding: 48px 16px; font-weight: 600; }
.pull-indicator { display: flex; align-items: center; justify-content: center; overflow: hidden; transition: height 0.15s ease; }

.order-list { display: flex; flex-direction: column; gap: 12px; }
.order-card {
  border-radius: var(--radius-lg);
  padding: 16px;
  position: relative;
  overflow: hidden;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.order-card:active {
  opacity: 0.92;
}
.order-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, #F4A261, transparent);
}
.order-card.rejected {
  background: var(--bg-card);
  border-color: rgba(239, 68, 68, 0.3);
}
.order-card.rejected::before {
  background: linear-gradient(90deg, transparent, #EF4444, transparent);
}
.order-card.rejected .order-amount {
  background: none;
  -webkit-background-clip: unset;
  background-clip: unset;
  color: var(--text-muted);
}
.order-card.rejected .info-label {
  color: var(--text-muted);
}
.order-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
.method-badge { padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 700; }
.method-badge.bank { background: rgba(244, 162, 97, 0.15); color: var(--primary-light); }
.method-badge.usdt { background: rgba(16, 185, 129, 0.15); color: var(--success); }
.status-badge { font-size: 12px; font-weight: 700; }
.status-pending { color: var(--warning); }
.status-approved { color: var(--success); }
.status-rejected { color: var(--danger); }
.order-body { }
.order-amount {
  font-size: 22px;
  font-weight: 900;
  margin-bottom: 4px;
  color: var(--primary);
}
.approved-amount { font-size: 12px; color: var(--success); margin-bottom: 6px; font-weight: 600; }
.order-info-row { margin-bottom: 8px; }
.info-label { font-size: 13px; color: var(--primary); font-weight: 600; }
.order-times { display: flex; flex-direction: column; gap: 4px; margin-bottom: 6px; }
.time-row { display: flex; justify-content: space-between; align-items: center; }
.time-label { font-size: 11px; color: var(--text-muted); }
.time-value { font-size: 11px; color: var(--text); font-variant-numeric: tabular-nums; }
.order-remark {
  font-size: 12px;
  color: var(--primary);
  background: rgba(244, 162, 97, 0.08);
  padding: 6px 10px;
  border-radius: 6px;
  margin-top: 6px;
  border-left: 2px solid var(--primary);
  line-height: 1.45;
  word-break: break-word;
}
.reject-reason {
  margin-top: 8px;
  font-size: 12px;
  color: var(--danger);
  background: transparent;
  padding: 6px 0 0;
  border-radius: 0;
  border: none;
  border-top: 1px solid rgba(239, 68, 68, 0.25);
  line-height: 1.45;
  word-break: break-word;
}
.card-detail-hint {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.card-detail-summary {
  font-size: 11px;
  color: var(--text-muted);
  font-weight: 600;
}
.card-detail-link {
  font-size: 11px;
  color: var(--primary);
  font-weight: 700;
  white-space: nowrap;
}
.card-detail-link-only {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 0;
  border: none;
  background: none;
  text-align: right;
  font-size: 11px;
  color: var(--primary);
  font-weight: 700;
  cursor: pointer;
}

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

.detail-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
}

.detail-modal {
  position: relative;
  width: 100%;
  max-width: 480px;
  max-height: min(88vh, 720px);
  overflow-y: auto;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: 14px 14px 0 0;
  padding: 16px 16px calc(14px + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.4);
}

.detail-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-muted);
  font-size: 13px;
  cursor: pointer;
  line-height: 1;
}

.detail-title {
  margin: 0 28px 12px 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}

.detail-summary {
  margin-bottom: 14px;
  padding: 12px;
  border-radius: 10px;
  background: var(--bg-body);
  border: 1px solid var(--border);
}

.detail-summary-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

.detail-amount {
  font-size: 22px;
  font-weight: 700;
  margin-bottom: 4px;
  color: var(--primary);
  letter-spacing: -0.02em;
}

.detail-method-name {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 500;
  margin-bottom: 8px;
}

.detail-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 6px;
}

.detail-label {
  font-size: 12px;
  color: var(--text-muted);
  flex-shrink: 0;
}

.detail-value {
  font-size: 12px;
  color: var(--text);
  text-align: right;
  word-break: break-word;
}

.detail-summary .order-remark {
  margin-top: 8px;
  font-size: 11px;
  color: var(--text-muted);
  background: transparent;
  padding: 6px 0 0;
  border-radius: 0;
  border: none;
  border-top: 1px solid var(--border);
  line-height: 1.45;
  word-break: break-word;
}

.detail-summary .reject-reason {
  margin-top: 8px;
  font-size: 11px;
  color: var(--danger);
  background: transparent;
  padding: 6px 0 0;
  border-radius: 0;
  border: none;
  border-top: 1px solid rgba(239, 68, 68, 0.2);
  line-height: 1.45;
  word-break: break-word;
}

.detail-summary .approved-amount {
  font-size: 11px;
  font-weight: 500;
}

.detail-audit {
  margin-top: 2px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

.detail-audit-title {
  margin: 0 0 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.02em;
}

.audit-track {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.audit-step {
  display: flex;
  gap: 8px;
  min-height: 0;
}

.audit-step-rail {
  flex: 0 0 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 4px;
}

.audit-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--border);
  flex-shrink: 0;
}

.audit-line {
  flex: 1;
  width: 1px;
  min-height: 10px;
  margin: 3px 0;
  background: var(--border);
}

.audit-step-body {
  flex: 1;
  min-width: 0;
  padding-bottom: 12px;
}

.audit-step:last-child .audit-step-body {
  padding-bottom: 0;
}

.audit-step-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.audit-step-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.35;
}

.audit-step-time {
  font-size: 10px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex-shrink: 0;
}

.audit-step-actor {
  margin: 2px 0 0;
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.4;
}

.audit-step-credited {
  margin: 3px 0 0;
  font-size: 11px;
  font-weight: 500;
  color: var(--success);
  line-height: 1.4;
}

.audit-step-note {
  margin: 4px 0 0;
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.45;
  word-break: break-word;
}

.audit-step-box {
  margin-top: 4px;
  padding: 6px 8px;
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.4;
  word-break: break-word;
}

.audit-step-box--reject {
  background: transparent;
  border: 1px solid rgba(239, 68, 68, 0.3);
}

.audit-step-box-label {
  font-size: 10px;
  font-weight: 500;
  color: var(--danger);
  letter-spacing: 0.01em;
}

.audit-step-box-text {
  font-size: 11px;
  color: var(--danger);
}

.audit-step--submitted .audit-dot {
  background: var(--primary);
}
.audit-step--approved .audit-dot {
  background: var(--success);
}
.audit-step--rejected .audit-dot {
  background: var(--danger);
}
.audit-step--revoked .audit-dot {
  background: var(--text-muted);
}
.audit-step--reopened .audit-dot {
  background: var(--primary);
}

.modal-reapply-btn {
  width: 100%;
  margin-top: 14px;
  padding: 11px 16px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
</style>
