<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import api from '../api';
import { formatAmount, formatAmountFull } from '../utils/format-amount';
import type { AdminDashboard } from './dashboard-types';
import EChartPanel from '../components/dashboard/EChartPanel.vue';
import { buildCombinedTrendOption, buildTriplePieOption } from '../utils/dashboard-charts';
import { betStatusLabel } from '../utils/bet-labels';
import { useAdminLocale } from '../composables/useAdminLocale';
import InviteCodePanel from '../components/InviteCodePanel.vue';

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

const stats = ref<AdminDashboard | null>(null);
const loading = ref(true);
const loadError = ref(false);

onMounted(load);

async function load() {
  loading.value = true;
  loadError.value = false;
  try {
    const { data } = await api.get('/admin/dashboard');
    stats.value = data.data as AdminDashboard;
  } catch {
    stats.value = null;
    loadError.value = true;
  } finally {
    loading.value = false;
  }
}

type KpiLink = { path: string; query?: Record<string, string> };

function goKpiLink(link: KpiLink) {
  router.push(link.query ? { path: link.path, query: link.query } : link.path);
}

const s = computed(() => stats.value);

function fmtCount(val: number | undefined) {
  return (val ?? 0).toLocaleString(localeTag.value, { maximumFractionDigits: 0 });
}

function formatTime(v: string) {
  return new Date(v).toLocaleString(localeTag.value, {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function toNum(v: string | number | undefined) {
  const n = typeof v === 'number' ? v : parseFloat(v ?? '0');
  return Number.isFinite(n) ? n : 0;
}

function pctChange(today: string | number, yesterday: string | number) {
  const t0 = toNum(today);
  const y = toNum(yesterday);
  if (y === 0) return t0 > 0 ? '+100%' : '—';
  const p = ((t0 - y) / y) * 100;
  const sign = p > 0 ? '+' : '';
  return `${sign}${p.toFixed(1)}%`;
}

const chartI18n = computed(() => ({
  locale: locale.value,
  betCountSeries: t('dash.chart_bet_count'),
  axisAmount: t('dash.axis_amount'),
  axisCount: t('dash.axis_count'),
  countSuffix: t('dash.count_suffix'),
  pieTooltip: t('dash.chart_tooltip'),
  noData: t('common.no_data'),
  pieEmpty: t('dash.pie_empty'),
}));

const trendLabels = computed(() => s.value?.trend7d?.map((d) => d.label) ?? []);

const mainTrendOption = computed(() =>
  buildCombinedTrendOption(
    trendLabels.value,
    [
      {
        name: t('dash.chart_stake'),
        color: '#346538',
        values: s.value?.trend7d?.map((d) => toNum(d.stake)) ?? [],
      },
      {
        name: t('dash.chart_payout'),
        color: '#1f6c9f',
        values: s.value?.trend7d?.map((d) => toNum(d.payout)) ?? [],
      },
      {
        name: t('dash.chart_ggr'),
        color: '#956400',
        values: s.value?.trend7d?.map((d) => toNum(d.ggr)) ?? [],
      },
    ],
    s.value?.trend7d?.map((d) => d.betCount) ?? [],
    chartI18n.value,
  ),
);

const distributionOption = computed(() => {
  const m = s.value?.matches;
  const u = s.value?.users;
  const raw = s.value?.bets.todayByStatus ?? {};
  const betColors: Record<string, string> = {
    PENDING: '#956400',
    WON: '#346538',
    LOST: '#9f2f2d',
    VOID: '#8c867c',
    REFUNDED: '#1f6c9f',
  };

  const matchSegs = m
    ? [
        { label: t('dash.match_draft'), value: m.draft, color: '#8c867c' },
        { label: t('dash.match_published'), value: m.published, color: '#346538' },
        { label: t('dash.match_closed'), value: m.closed, color: '#1f6c9f' },
        { label: t('dash.match_pending_settle'), value: m.pendingSettlement, color: '#956400' },
        { label: t('dash.match_settled'), value: m.settled ?? 0, color: '#477a4c' },
      ].filter((x) => x.value > 0)
    : [];

  const betSegs = ['PENDING', 'WON', 'LOST', 'VOID', 'REFUNDED']
    .filter((k) => raw[k]?.count)
    .map((k) => ({
      label: betStatusLabel(k),
      value: raw[k].count,
      color: betColors[k] ?? '#8c867c',
    }));

  const userSegs = u
    ? [
        { label: t('dash.user_active'), value: u.playersActive, color: '#346538' },
        { label: t('dash.user_suspended'), value: u.playersSuspended, color: '#9f2f2d' },
        { label: t('dash.user_direct'), value: u.playersDirect, color: '#1f6c9f' },
        { label: t('dash.user_agents'), value: u.agentsTotal, color: '#956400' },
      ].filter((x) => x.value > 0)
    : [];

  return buildTriplePieOption(
    [
      { title: t('dash.pie_matches'), segments: matchSegs },
      { title: t('dash.pie_bets'), segments: betSegs },
      { title: t('dash.pie_users'), segments: userSegs },
    ],
    chartI18n.value,
  );
});

const kpiPrimary = computed(() => {
  if (!s.value) return [];
  const td = s.value.today;
  const y = s.value.yesterday;
  const yLabel = t('common.yesterday');
  return [
    {
      label: t('dash.kpi_bet_count'),
      value: fmtCount(td.betCount),
      sub: `${yLabel} ${fmtCount(y.betCount)}`,
      delta: pctChange(td.betCount, y.betCount),
    },
    {
      label: t('dash.kpi_stake'),
      value: formatAmount(td.stake, 2, locale.value),
      sub: formatAmountFull(td.stake, locale.value),
      delta: pctChange(td.stake, y.stake),
    },
    {
      label: t('dash.kpi_payout'),
      value: formatAmount(td.payout, 2, locale.value),
      sub: `${yLabel} ${formatAmount(y.payout, 2, locale.value)}`,
      delta: pctChange(td.payout, y.payout),
    },
    {
      label: t('dash.kpi_ggr'),
      value: formatAmount(td.ggr, 2, locale.value),
      sub: `${yLabel} ${formatAmount(y.ggr, 2, locale.value)}`,
      delta: pctChange(td.ggr, y.ggr),
    },
  ];
});

const kpiSecondary = computed(() => {
  if (!s.value) return [];
  const pendingMatches = s.value.matches.pendingSettlement ?? 0;
  return [
    {
      label: t('dash.kpi_users'),
      value: `${fmtCount(s.value.users.playersTotal)} / ${fmtCount(s.value.users.agentsTotal)}`,
      sub: t('dash.kpi_new_players', { n: fmtCount(s.value.today.newPlayers) }),
    },
    {
      label: t('dash.kpi_pending'),
      value: `${fmtCount(s.value.bets.pendingTotal)} ${t('common.bets_unit')}`,
      sub: t('dash.kpi_pending_sub', {
        bets: fmtCount(s.value.bets.pendingTotal),
        matches: fmtCount(pendingMatches),
      }),
      link:
        pendingMatches > 0
          ? { path: '/matches', query: { status: 'PENDING_SETTLEMENT' } }
          : undefined,
    },
    {
      label: t('dash.kpi_wallet'),
      value: formatAmount(s.value.wallets.totalAvailable, 2, locale.value),
      sub: `${t('common.frozen')} ${formatAmount(s.value.wallets.totalFrozen, 2, locale.value)}`,
    },
    {
      label: t('dash.kpi_credit'),
      value: formatAmount(s.value.agents.totalAvailableCredit, 2, locale.value),
      sub: `${t('common.used')} ${formatAmount(s.value.agents.totalUsedCredit, 2, locale.value)}`,
    },
  ];
});
</script>

<template>
  <div class="dashboard-page" v-loading="loading">
    <el-card v-if="!loading && loadError" class="state-card" shadow="never">
      <p class="state-title">{{ t('msg.load_failed') }}</p>
      <p class="state-hint">{{ t('dash.load_error_hint') }}</p>
      <el-button type="primary" size="small" @click="load">{{ t('common.retry') }}</el-button>
    </el-card>

    <template v-else-if="s">
      <InviteCodePanel auto-load class="invite-board" />
      <el-card class="overview-board" shadow="never">
        <div v-if="s.generatedAt" class="board-head">
          <span class="dash-updated">
            {{ t('common.updated_at') }} {{ formatTime(s.generatedAt) }}
          </span>
        </div>

        <div class="kpi-grid kpi-primary">
          <div v-for="item in kpiPrimary" :key="item.label" class="kpi-cell">
            <span class="kpi-label">{{ item.label }}</span>
            <span class="kpi-value">{{ item.value }}</span>
            <span class="kpi-sub">{{ item.sub }}</span>
            <span
              class="kpi-delta"
              :class="{ up: item.delta.startsWith('+'), down: item.delta.startsWith('-') }"
            >
              {{ t('common.vs_yesterday') }} {{ item.delta }}
            </span>
          </div>
        </div>

        <div class="kpi-grid kpi-secondary">
          <div
            v-for="item in kpiSecondary"
            :key="item.label"
            class="kpi-cell compact"
            :class="{ 'kpi-cell--link': item.link }"
            :role="item.link ? 'button' : undefined"
            :tabindex="item.link ? 0 : undefined"
            @click="item.link && goKpiLink(item.link)"
            @keydown.enter.prevent="item.link && goKpiLink(item.link)"
          >
            <span class="kpi-label">{{ item.label }}</span>
            <span class="kpi-value sm">{{ item.value }}</span>
            <span class="kpi-sub">{{ item.sub }}</span>
          </div>
        </div>

        <div class="charts-stack">
          <EChartPanel title="" :option="mainTrendOption" height="300px" class="chart-main" />
          <div class="chart-main-caption">{{ t('dash.trend_caption') }}</div>
          <EChartPanel title="" :option="distributionOption" height="200px" class="chart-dist" />
        </div>
      </el-card>
    </template>
  </div>
</template>

<style scoped>
.dashboard-page { padding-bottom: 32px; }

.state-card {
  border-radius: 14px;
  border: 1px solid #2a2220;
  background: rgba(255, 69, 58, 0.06);
  text-align: center;
  padding: 8px 0 4px;
}
.state-title {
  font-size: 15px;
  font-weight: 700;
  color: #ff8a80;
  margin-bottom: 6px;
}
.state-hint {
  font-size: 13px;
  color: #888;
  margin-bottom: 14px;
}

.invite-board {
  margin-bottom: 12px;
}

.overview-board {
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: #111111;
  margin-bottom: 28px;
}
.overview-board :deep(.el-card__body) {
  padding: 20px 22px 16px;
}
.board-head {
  display: flex;
  justify-content: flex-end;
  margin: -4px 0 14px;
}
.dash-updated {
  font-size: 11px;
  color: #555;
  letter-spacing: 0.02em;
}

.kpi-grid {
  display: grid;
  gap: 10px;
  margin-bottom: 10px;
}
.kpi-primary {
  grid-template-columns: repeat(4, 1fr);
}
.kpi-secondary {
  grid-template-columns: repeat(4, 1fr);
  margin-bottom: 18px;
}
.kpi-cell {
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid #222;
  background: rgba(255, 255, 255, 0.03);
}
.kpi-cell.compact {
  padding: 10px 12px;
}
.kpi-cell--link {
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.kpi-cell--link:hover,
.kpi-cell--link:focus-visible {
  border-color: rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.04);
  outline: none;
}
.kpi-label {
  display: block;
  font-size: 12px;
  color: #737373;
  margin-bottom: 6px;
}
.kpi-value {
  display: block;
  font-size: 22px;
  font-weight: 500;
  color: #f5f5f5;
  line-height: 1.15;
  letter-spacing: -0.02em;
}
.kpi-value.sm {
  font-size: 17px;
}
.kpi-sub {
  display: block;
  font-size: 11px;
  color: #555;
  margin-top: 4px;
}
.kpi-delta {
  display: inline-block;
  margin-top: 6px;
  font-size: 10px;
  font-weight: 600;
  color: #888;
  padding: 2px 6px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.04);
}
.kpi-delta.up { color: #4ade80; }
.kpi-delta.down { color: #f87171; }

.charts-stack {
  border-top: 1px solid #1a1a1a;
  padding-top: 12px;
}
.chart-main-caption {
  font-size: 11px;
  color: #555;
  text-align: center;
  margin: -8px 0 8px;
}
.charts-stack :deep(.chart-panel) {
  border: none;
  background: transparent;
  padding: 8px 0 0;
}
.charts-stack :deep(.chart-title:empty) {
  display: none;
}
.chart-dist {
  margin-top: 4px;
}

@media (max-width: 1200px) {
  .kpi-primary,
  .kpi-secondary {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 640px) {
  .kpi-primary,
  .kpi-secondary {
    grid-template-columns: 1fr;
  }
}

/* Local light overrides for the legacy dashboard entry */
.state-hint {
  color: var(--text-muted);
}

.overview-board {
  border-color: var(--border);
  background: #ffffff;
  box-shadow: var(--shadow);
}

.dash-updated {
  color: #9b9489;
  letter-spacing: 0;
}

.kpi-cell {
  border-color: var(--border-soft);
  background: #fbfaf7;
}

.kpi-cell--link:hover,
.kpi-cell--link:focus-visible {
  border-color: #d5cfc3;
  background: var(--accent-hover);
}

.kpi-label {
  color: var(--text-muted);
}

.kpi-value {
  color: var(--text);
  font-weight: 800;
  letter-spacing: 0;
}

.kpi-sub {
  color: #9b9489;
}

.kpi-delta {
  color: var(--text-muted);
  background: #f0ede6;
}

.kpi-delta.up {
  color: var(--success-text);
  background: var(--success-bg);
}

.kpi-delta.down {
  color: var(--danger-text);
  background: var(--danger-bg);
}

.charts-stack {
  border-top-color: var(--border-soft);
}

.chart-main-caption {
  color: #9b9489;
}
</style>
