<script setup lang="ts">
import { ref, computed, onMounted, watch, nextTick } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import api from '../../api';
import { useBetSlipStore } from '../../stores/betSlip';
import TeamEmblem from '../../components/TeamEmblem.vue';
import MatchBetGuide from '../../components/match-detail/MatchBetGuide.vue';
import MarketSelectionsPanel from '../../components/match-detail/MarketSelectionsPanel.vue';
import CorrectScorePanel from '../../components/match-detail/CorrectScorePanel.vue';
import { isCorrectScoreMarket, parseScoreCode } from '../../utils/correctScoreLayout';
import { useOnLocaleChange } from '../../composables/useOnLocaleChange';
import GoldSpinner from '../../components/GoldSpinner.vue';
import { matchPhaseLabel } from '../../utils/matchPhase';
import { formatLocalMatchDateTime, defaultMarketName, DETAIL_MARKET_TYPES } from '@thebet365/shared';
import { resolveSelectionLabel } from '../../utils/selectionLabel';
import { useDesktopBetPopover } from '../../composables/useDesktopBetPopover';
import { useDesktopBetLocate, scrollToBetSelection } from '../../composables/useDesktopBetLocate';

const route = useRoute();
const router = useRouter();
const { t, locale } = useI18n();
const slip = useBetSlipStore();
const { openAt, visible: popoverVisible, pendingItem: popoverItem, cancelClose, scheduleClose } = useDesktopBetPopover();
const { pendingLocate, clearLocate } = useDesktopBetLocate();

function goBack() {
  if (window.history.state && window.history.state.back) {
    router.back();
  } else {
    router.push('/bet');
  }
}

interface Selection {
  id: string;
  selectionCode: string;
  selectionName: string;
  selectionDisplayName?: string;
  odds: string;
  oddsVersion: string;
}

interface Market {
  id: string;
  marketType: string;
  marketDisplayName?: string;
  lineValue?: string | number | null;
  status: string;
  allowSingle?: boolean;
  allowParlay?: boolean;
  promoLabel?: string | null;
  selections: Selection[];
}

interface MatchDetail {
  id: string;
  leagueName?: string;
  leagueLogoUrl?: string | null;
  homeTeamName: string;
  awayTeamName: string;
  homeTeamCode?: string;
  awayTeamCode?: string;
  homeTeamLogoUrl?: string | null;
  awayTeamLogoUrl?: string | null;
  startTime: string;
  status?: string;
  bettingOpen?: boolean;
  matchPhase?: string;
  score?: {
    htHome: number | null;
    htAway: number | null;
    ftHome: number | null;
    ftAway: number | null;
    homeCorners?: number | null;
    awayCorners?: number | null;
    homeYellowCards?: number | null;
    awayYellowCards?: number | null;
    homeRedCards?: number | null;
    awayRedCards?: number | null;
  } | null;
  markets: Market[];
}

const match = ref<MatchDetail | null>(null);
const loading = ref(true);
const selectedMarketTypes = ref<Set<string>>(new Set());

async function loadMatch() {
  loading.value = true;
  try {
    const { data } = await api.get(`/player/matches/${route.params.id}`);
    match.value = data.data;
    selectedMarketTypes.value = new Set();
  } finally {
    loading.value = false;
  }
}

onMounted(() => {
  void loadMatch();
});

useOnLocaleChange(loadMatch);

const kickoff = computed(() => {
  if (!match.value) return '';
  return formatLocalMatchDateTime(match.value.startTime, locale.value, { variant: 'full' });
});

const bettingOpen = computed(() => match.value?.bettingOpen !== false);
const matchPhase = computed<import('../../utils/matchPhase').MatchPhase | null>(() => (match.value?.matchPhase ?? (bettingOpen.value ? 'open' : 'closed_pending')) as import('../../utils/matchPhase').MatchPhase);
const phaseLabel = computed(() => matchPhaseLabel(t, matchPhase.value));

const liveScoreText = computed(() => {
  const s = match.value?.score;
  if (!s || s.ftHome == null || s.ftAway == null) return '';
  return `${s.ftHome} - ${s.ftAway}`;
});

const resultStats = computed(() => {
  const s = match.value?.score;
  if (!s || matchPhase.value !== 'settled') return [];
  
  const statVal = (val: number | null | undefined) => val == null ? '-' : String(val);
  const pair = (h: number | null | undefined, a: number | null | undefined) => `${statVal(h)} - ${statVal(a)}`;

  return [
    { key: 'ht', label: t('bet.result_ht'), value: pair(s.htHome, s.htAway) },
    { key: 'ft', label: t('bet.result_ft'), value: pair(s.ftHome, s.ftAway) },
    { key: 'corners', label: t('bet.result_corners'), value: pair(s.homeCorners, s.awayCorners) },
    { key: 'yellow', label: t('bet.result_yellow_cards'), value: pair(s.homeYellowCards, s.awayYellowCards) },
    { key: 'red', label: t('bet.result_red_cards'), value: pair(s.homeRedCards, s.awayRedCards) },
  ];
});

const showResultStats = computed(() => resultStats.value.length > 0);

const allMarkets = computed(() => match.value?.markets ?? []);

const compactMarkets = computed(() =>
  allMarkets.value.filter((m) => !isCorrectScoreMarket(m.marketType)),
);

const scoreMarkets = computed(() =>
  allMarkets.value.filter((m) => isCorrectScoreMarket(m.marketType)),
);

const marketFilterOptions = computed(() => {
  const labels = new Map<string, string>();
  for (const market of allMarkets.value) {
    if (labels.has(market.marketType)) continue;
    labels.set(
      market.marketType,
      market.marketDisplayName?.trim() || defaultMarketName(market.marketType, locale.value),
    );
  }
  return Array.from(labels.entries())
    .map(([type, label]) => ({ type, label }))
    .sort((a, b) => marketTypeSortIndex(a.type) - marketTypeSortIndex(b.type));
});

const hasMarketFilter = computed(() => selectedMarketTypes.value.size > 0);

const filteredCompactMarkets = computed(() =>
  compactMarkets.value.filter((market) => matchesMarketFilter(market.marketType)),
);

const filteredScoreMarkets = computed(() =>
  scoreMarkets.value.filter((market) => matchesMarketFilter(market.marketType)),
);

function marketTypeSortIndex(marketType: string) {
  const idx = (DETAIL_MARKET_TYPES as readonly string[]).indexOf(marketType);
  return idx >= 0 ? idx : 999;
}

function matchesMarketFilter(marketType: string) {
  if (!hasMarketFilter.value) return true;
  return selectedMarketTypes.value.has(marketType);
}

function isMarketFilterActive(marketType: string) {
  return selectedMarketTypes.value.has(marketType);
}

function isAllMarketFilterActive() {
  return !hasMarketFilter.value;
}

function selectAllMarketFilters() {
  selectedMarketTypes.value = new Set();
}

function toggleMarketFilter(marketType: string) {
  const next = new Set(selectedMarketTypes.value);
  if (next.has(marketType)) next.delete(marketType);
  else next.add(marketType);
  selectedMarketTypes.value = next;
}

function ensureMarketVisibleForLocate(target: { marketId?: string; selectionId: string }) {
  const market =
    allMarkets.value.find((m) => m.id === target.marketId) ??
    allMarkets.value.find((m) => m.selections.some((s) => s.id === target.selectionId));
  if (!market) return;
  if (hasMarketFilter.value && !matchesMarketFilter(market.marketType)) {
    selectedMarketTypes.value = new Set();
  }
}

watch(
  [pendingLocate, () => match.value?.id, loading],
  async ([target, matchId, isLoading]) => {
    if (!target || isLoading || !matchId) return;
    if (String(matchId) !== String(target.matchId)) return;
    ensureMarketVisibleForLocate(target);
    await nextTick();
    const found = await scrollToBetSelection(target.selectionId);
    if (found) clearLocate();
  },
  { flush: 'post' },
);

watch(
  () => route.params.id,
  () => {
    selectedMarketTypes.value = new Set();
  },
);

function marketLabel(market: Market) {
  return market.marketDisplayName?.trim() || market.marketType || '';
}

function normalizeMarketStatus(status?: string) {
  return (status ?? 'OPEN').toUpperCase();
}

function isMarketOpen(market: Market) {
  return normalizeMarketStatus(market.status) === 'OPEN';
}

function marketStatusLabel(status?: string) {
  const normalized = normalizeMarketStatus(status);
  if (normalized === 'SUSPENDED') return t('bet.market_status_suspended');
  if (normalized === 'CLOSED') return t('bet.market_status_closed');
  return '';
}

function isMarketLocked(market: Market) {
  if (!bettingOpen.value || !isMarketOpen(market)) return true;
  return market.allowSingle !== true && market.allowParlay !== true;
}

function selectionLabel(sel: Selection, market: Market) {
  const parsedScore = parseScoreCode(sel.selectionCode, t);
  if (parsedScore) return parsedScore.display;
  return resolveSelectionLabel(t, sel.selectionCode, sel.selectionName, {
    lineValue: market.lineValue,
  });
}

function isSelected(id: string) {
  if (slip.isInSlip(id)) return true;
  return popoverVisible.value && popoverItem.value?.selectionId === id;
}

function buildSlipItem(sel: Selection, market: Market) {
  if (!match.value) return null;
  return {
    selectionId: sel.id,
    oddsVersion: String(sel.oddsVersion),
    matchId: match.value.id,
    matchName: `${match.value.homeTeamName} vs ${match.value.awayTeamName}`,
    marketId: market.id,
    marketName: marketLabel(market),
    selectionName: selectionLabel(sel, market),
    odds: parseFloat(sel.odds),
    marketType: market.marketType,
    lineValue:
      market.lineValue != null && market.lineValue !== ''
        ? parseFloat(String(market.lineValue))
        : null,
    allowSingle: market.allowSingle,
    allowParlay: market.allowParlay,
  };
}

function toggleSelection(sel: Selection, market: Market, event?: MouseEvent) {
  if (!match.value || isMarketLocked(market)) return;
  const item = buildSlipItem(sel, market);
  if (!item || !event) return;
  openAt(event, item);
}

function getHoveredSide() {
  if (!match.value || !popoverVisible.value || !popoverItem.value) return '';
  if (String(popoverItem.value.matchId) !== String(match.value.id)) return '';

  const selId = popoverItem.value.selectionId;
  for (const market of allMarkets.value) {
    const sel = market.selections?.find((s) => s.id === selId);
    if (!sel) continue;
    const code = (sel.selectionCode || '').toUpperCase();
    if (code === 'HOME') return 'home';
    if (code === 'AWAY') return 'away';
    if (code === 'DRAW') return 'draw';
    if (code === 'OVER') return 'home';
    if (code === 'UNDER') return 'away';
    if (code === 'ODD' || code === 'EVEN') return 'draw';
    const selIndex = market.selections?.findIndex((s) => s.id === selId) ?? -1;
    if (selIndex === -1) continue;
    if (market.marketType === 'FT_1X2') {
      if (selIndex === 0) return 'home';
      if (selIndex === 1) return 'draw';
      if (selIndex === 2) return 'away';
    } else {
      if (selIndex === 0) return 'home';
      if (selIndex === 1) return 'away';
    }
  }
  return '';
}
</script>

<template>
  <div class="desktop-match-detail">
    <!-- Fixed Header Breadcrumb -->
    <div class="detail-breadcrumbs">
      <button type="button" class="back-btn" @click="goBack">← {{ t('bet.back') || '返回' }}</button>
      <span class="sep">/</span>
      <span class="curr">{{ match?.leagueName }}</span>
    </div>

    <div class="detail-main">
    <!-- Loading -->
    <div v-if="loading" class="loading-state">
      <GoldSpinner :active="true" />
    </div>

    <template v-else-if="match">
      <!-- High Density Score Band -->
      <div
        class="match-score-band"
        :class="[{ 'phase-settled': matchPhase === 'settled' }, getHoveredSide()]"
        @mouseenter="cancelClose"
        @mouseleave="scheduleClose()"
      >
        <div class="team-side home">
          <TeamEmblem size="xl" :team-code="match.homeTeamCode" :team-name="match.homeTeamName" :logo-url="match.homeTeamLogoUrl" />
          <span class="name">{{ match.homeTeamName }}</span>
        </div>

        <div class="score-arena">
          <div class="versus-row" v-if="liveScoreText">
            <span class="score">{{ match.score?.ftHome }}</span>
            <span class="divider">-</span>
            <span class="score">{{ match.score?.ftAway }}</span>
          </div>
          <div class="versus-row vs" v-else>VS</div>
          <span class="kickoff-time">{{ kickoff }}</span>
        </div>

        <div class="team-side away">
          <TeamEmblem size="xl" :team-code="match.awayTeamCode" :team-name="match.awayTeamName" :logo-url="match.awayTeamLogoUrl" />
          <span class="name">{{ match.awayTeamName }}</span>
        </div>
      </div>

      <!-- Result Stats -->
      <div v-if="showResultStats" class="result-stats-card">
        <h4>{{ t('bet.result_stats_title') || '赛果数据' }}</h4>
        <div class="stats-row">
          <div v-for="item in resultStats" :key="item.key" class="stat-pill">
            <span class="lbl">{{ item.label }}</span>
            <span class="val">{{ item.value }}</span>
          </div>
        </div>
      </div>

      <div v-if="marketFilterOptions.length" class="market-filter-bar">
        <span class="market-filter-label">{{ t('bet.filter_market') }}</span>
        <div class="market-filter-chips">
          <button
            type="button"
            class="market-filter-chip"
            :class="{ active: isAllMarketFilterActive() }"
            @click="selectAllMarketFilters"
          >
            {{ t('bet.time_all') }}
          </button>
          <button
            v-for="option in marketFilterOptions"
            :key="option.type"
            type="button"
            class="market-filter-chip"
            :class="{ active: isMarketFilterActive(option.type) }"
            @click="toggleMarketFilter(option.type)"
          >
            {{ option.label }}
          </button>
        </div>
      </div>

      <!-- Standard markets: 2-col card grid -->
      <div v-if="filteredCompactMarkets.length" class="markets-compact-grid">
        <div
          v-for="market in filteredCompactMarkets"
          :key="market.id"
          class="market-card"
          :class="{ locked: isMarketLocked(market) }"
          @mouseenter="cancelClose"
          @mouseleave="scheduleClose()"
        >
          <div class="market-hdr">
            <span class="market-title">{{ marketLabel(market) }}</span>
            <span v-if="isMarketLocked(market)" class="locked-lbl">{{ t('bet.market_status_closed') }}</span>
          </div>
          <div class="market-body">
            <MarketSelectionsPanel
              desktop-card
              compact
              :locked="isMarketLocked(market)"
              :line-value="market.lineValue"
              :selections="market.selections"
              :is-selected="isSelected"
              @pick="(id, ev) => toggleSelection(market.selections.find(s => s.id === id)!, market, ev)"
            />
          </div>
        </div>
      </div>

      <!-- Correct score -->
      <div v-if="filteredScoreMarkets.length" class="markets-score-section">
        <h4 class="score-section-title">{{ t('bet.correct_score') }}</h4>
        <div class="markets-score-grid">
          <div
            v-for="market in filteredScoreMarkets"
            :key="market.id"
            class="score-block"
            :class="{ locked: isMarketLocked(market) }"
            @mouseenter="cancelClose"
            @mouseleave="scheduleClose()"
          >
            <div class="score-block-hdr">
              <span>{{ marketLabel(market) }}</span>
              <span v-if="isMarketLocked(market)" class="locked-lbl">{{ t('bet.market_status_closed') }}</span>
            </div>
            <CorrectScorePanel
              dense
              :market-type="market.marketType"
              :selections="market.selections"
              :locked="isMarketLocked(market)"
              :is-selected="isSelected"
              @pick="(id, ev) => toggleSelection(market.selections.find(s => s.id === id)!, market, ev)"
            />
          </div>
        </div>
      </div>

      <div
        v-if="!filteredCompactMarkets.length && !filteredScoreMarkets.length"
        class="markets-empty"
      >
        <p>{{ hasMarketFilter ? t('bet.no_markets_filtered') : (t('bet.no_markets') || '暂无可用盘口') }}</p>
      </div>
    </template>
    </div>
  </div>
</template>

<style scoped>
.desktop-match-detail {
  display: flex;
  flex-direction: column;
  max-width: 100%;
  min-height: 100%;
}

.detail-breadcrumbs {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  font-size: 12px;
  color: var(--text-muted);
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.detail-main {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px 16px 14px;
}

.detail-breadcrumbs .sep {
  flex-shrink: 0;
}

.detail-breadcrumbs .curr {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text);
  font-weight: 700;
}

.back-btn {
  flex-shrink: 0;
  background: transparent;
  color: var(--primary-light);
  font-weight: 700;
  border: none;
  padding: 0;
  cursor: pointer;
}

.back-btn:hover {
  text-decoration: underline;
}

.loading-state {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 300px;
}

.match-score-band {
  background: linear-gradient(180deg, var(--bg-body) 0%, var(--bg-card) 100%);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 10px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.team-side {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: 1;
}

.team-side.away {
  flex-direction: row-reverse;
}

.team-side .name {
  font-size: 13px;
  font-weight: 800;
  font-family: var(--font-heading);
  color: var(--text);
}

.score-arena {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 240px;
}

.versus-row {
  display: flex;
  align-items: center;
  gap: 16px;
}

.versus-row .score {
  font-size: 32px;
  font-weight: 900;
  color: var(--primary-light);
  text-shadow: 0 0 10px rgba(0, 102, 204, 0.3);
}

.versus-row .divider {
  font-size: 24px;
  color: var(--text-muted);
}

.versus-row.vs {
  font-size: 22px;
  font-weight: 800;
  color: var(--text-muted);
}

.kickoff-time {
  font-size: 11px;
  color: var(--text-muted);
}

.result-stats-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 16px;
}

.result-stats-card h4 {
  margin: 0 0 12px;
  font-size: 12px;
  font-weight: 800;
  color: var(--primary-light);
  text-transform: uppercase;
}

.stats-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.stat-pill {
  background: var(--bg-body);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 6px 12px;
  display: flex;
  gap: 10px;
  font-size: 11px;
}

.stat-pill .lbl { color: var(--text-muted); }
.stat-pill .val { color: var(--text); font-weight: 700; }

.market-filter-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg-card);
  min-width: 0;
}

.market-filter-label {
  flex-shrink: 0;
  font-size: 10px;
  font-weight: 800;
  color: var(--primary-light);
  white-space: nowrap;
}

.market-filter-chips {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 4px;
  min-width: 0;
  flex: 1;
  overflow-x: auto;
  scrollbar-width: none;
}

.market-filter-chips::-webkit-scrollbar {
  display: none;
}

.market-filter-chip {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  padding: 3px 7px;
  border-radius: 4px;
  border: 1px solid transparent;
  background: rgba(0, 0, 0, 0.04);
  color: var(--text-muted);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap;
  transition: background 0.18s, border-color 0.18s, color 0.18s;
}

.market-filter-chip:hover {
  color: var(--primary);
  background: var(--bg-hover);
}

.market-filter-chip.active {
  color: var(--primary-light);
  background: rgba(0, 102, 204, 0.1);
  border-color: var(--border-active);
  box-shadow: inset 0 0 0 1px rgba(0, 102, 204, 0.08);
}

.markets-score-section {
  margin-top: 4px;
}

.score-section-title {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 800;
  color: var(--primary-light);
}

.markets-empty {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 120px;
  color: var(--text-muted);
  font-size: 13px;
}

.markets-compact-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  align-items: start;
}

@media (min-width: 1360px) {
  .markets-compact-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.market-card {
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
  background: var(--bg-card);
  align-self: start;
}

.market-card.locked {
  opacity: 0.55;
}

.market-hdr {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 10px;
  background: var(--bg-body);
  border-bottom: 1px solid var(--border);
}

.market-title {
  font-size: 11px;
  font-weight: 800;
  color: var(--text);
  line-height: 1.25;
}

.market-body {
  padding: 6px;
}

.markets-score-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 8px;
  align-items: start;
  margin-top: 4px;
}

.score-block {
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
  background: var(--bg-card);
  align-self: start;
}

.score-block.locked {
  opacity: 0.55;
}

.score-block-hdr {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 10px;
  background: var(--bg-body);
  border-bottom: 1px solid var(--border);
  font-size: 11px;
  font-weight: 800;
  color: var(--text);
}

.locked-lbl {
  font-size: 10px;
  color: var(--danger);
  font-weight: 700;
  white-space: nowrap;
}

.team-side {
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.3s ease, filter 0.3s ease;
}

.match-score-band.home .team-side.home {
  transform: scale(1.06);
  filter: brightness(1.08) saturate(1.15);
}

.match-score-band.home .team-side.away {
  opacity: 0.35;
  transform: scale(0.94);
  filter: grayscale(0.6) brightness(0.7);
}

.match-score-band.away .team-side.away {
  transform: scale(1.06);
  filter: brightness(1.08) saturate(1.15);
}

.match-score-band.away .team-side.home {
  opacity: 0.35;
  transform: scale(0.94);
  filter: grayscale(0.6) brightness(0.7);
}

.match-score-band.draw .team-side {
  transform: scale(1.04);
  filter: brightness(1.08) saturate(1.1);
}
</style>
