<script setup lang="ts">
import { RouterView, RouterLink, useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useAuthStore } from '../stores/auth';
import { useBetSlipStore } from '../stores/betSlip';
import CashBalanceChip from '../components/CashBalanceChip.vue';
import UserAvatarMenu from '../components/UserAvatarMenu.vue';
import LocaleSwitcher from '../components/LocaleSwitcher.vue';
import { useAppLocale } from '../composables/useAppLocale';
import BottomNavIcon from '../components/BottomNavIcon.vue';
import BackToTopButton from '../components/BackToTopButton.vue';
import { computed, defineAsyncComponent, onMounted, onUnmounted, ref, watch } from 'vue';
import { useViewport } from '../composables/useViewport';
import DesktopShell from '../components/desktop/DesktopShell.vue';
import AnnouncementMarquee from '../components/AnnouncementMarquee.vue';

const BetSlipDrawer = defineAsyncComponent(() => import('../components/BetSlipDrawer.vue'));
import { usePlayerHome } from '../composables/usePlayerHome';
import { useInboxFeature } from '../composables/useInboxFeature';
import { usePlayerProfile } from '../composables/usePlayerProfile';
import { useDepositNotifications } from '../composables/useDepositNotifications';
import { usePlayerMessages } from '../composables/usePlayerMessages';
import { startPresencePing, stopPresencePing } from '../composables/usePresencePing';

const { isDesktop } = useViewport();
const { t, locale } = useI18n();
const auth = useAuthStore();
const { initFromUser } = useAppLocale();
const route = useRoute();
const slip = useBetSlipStore();
const { inboxEnabled, hubRoute, hubOpenLabelKey } = useInboxFeature();

const isDetailPage = computed(() => {
  const p = route.path;
  return (
    p.startsWith('/match/') ||
    p.startsWith('/bet/') ||
    p.startsWith('/bets/') ||
    p.startsWith('/wallet/') ||
    p.startsWith('/messages') ||
    p === '/profile/edit' ||
    p === '/profile/cashbacks'
  );
});

const showHeader = computed(() => !isDetailPage.value);
const showAnnouncement = computed(
  () => !isDetailPage.value && !route.path.startsWith('/profile') && !route.path.startsWith('/announcements'),
);

const showBottomNav = computed(() => {
  const p = route.path;
  if (
    p === '/' ||
    p === '/bet' ||
    p === '/announcements' ||
    p.startsWith('/announcements/') ||
    p.startsWith('/match/') ||
    p === '/bets' ||
    p === '/wallet' ||
    p.startsWith('/wallet/')
  ) return true;
  // 邮箱关闭时客服页保留底部导航，避免用户无法离开
  if (!inboxEnabled.value && p === '/messages') return true;
  return false;
});
const { announcements, announcementItems, load: loadPlayerHome } = usePlayerHome();
const { loadProfile, refreshProfile, bindProfileVisibilityRefresh } = usePlayerProfile();
const { startPolling, stopPolling } = useDepositNotifications();
const { unreadCount, refreshUnreadCount, resetMessagesState } = usePlayerMessages();
const mainRef = ref<HTMLElement | null>(null);
const tabScrollTops = new Map<string, number>();
const primaryAnnouncementId = computed(() => announcementItems.value[0]?.id ?? '');
const bottomNavHidden = ref(false);
let lastMainScrollTop = 0;

function onMainScroll() {
  const el = mainRef.value;
  if (!el || !showBottomNav.value) return;

  const scrollTop = el.scrollTop;
  const delta = scrollTop - lastMainScrollTop;

  if (scrollTop <= 8) {
    bottomNavHidden.value = false;
  } else if (delta > 10) {
    bottomNavHidden.value = true;
  } else if (delta < -10) {
    bottomNavHidden.value = false;
  }

  lastMainScrollTop = scrollTop;
}

watch(showBottomNav, (visible) => {
  if (!visible) bottomNavHidden.value = false;
});

watch(
  () => route.fullPath,
  (_path, oldPath) => {
    lastMainScrollTop = 0;
    bottomNavHidden.value = false;
    const el = mainRef.value;
    if (!el) return;
    if (oldPath) tabScrollTops.set(oldPath, el.scrollTop);
    el.scrollTop = tabScrollTops.get(route.fullPath) ?? 0;
  },
);

const balanceRefreshPaths = ['/wallet', '/bets'];
let mainScrollEl: HTMLElement | null = null;

watch(locale, (next, prev) => {
  if (prev && next !== prev) void loadPlayerHome(true);
});

onMounted(() => {
  if (auth.user?.locale) void initFromUser(auth.user.locale);
  bindProfileVisibilityRefresh();
  mainScrollEl = mainRef.value;
  mainScrollEl?.addEventListener('scroll', onMainScroll, { passive: true });
});

onUnmounted(() => {
  mainScrollEl?.removeEventListener('scroll', onMainScroll);
  mainScrollEl = null;
});

watch(
  () => auth.token,
  (token) => {
    // 首页数据（公告、热门赛事）对所有人公开，始终加载
    void loadPlayerHome(true);
    // 个人资料仅登录用户需要
    if (token) {
      void loadProfile(true);
      startPolling();
      startPresencePing();
      if (inboxEnabled.value) void refreshUnreadCount();
    } else {
      stopPolling();
      stopPresencePing();
      resetMessagesState();
    }
  },
  { immediate: true },
);

watch(
  () => route.path,
  (path) => {
    if (!auth.token) return;
    if (inboxEnabled.value && path.startsWith('/messages')) {
      void refreshUnreadCount();
    }
    if (balanceRefreshPaths.some((p) => path === p || path.startsWith(`${p}/`))) {
      void refreshProfile();
    }
  },
);
</script>

<template>
  <DesktopShell v-if="isDesktop" />
  <div v-else class="layout">
    <header v-if="showHeader" class="header">
      <svg class="logo" viewBox="0 0 130 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="TheBet365">
        <text x="0" y="18" font-family="'Inter','SF Pro Display',system-ui,sans-serif" font-size="11" font-weight="800" fill="#6B7280" letter-spacing="0.14em">THE</text>
        <text x="32" y="18" font-family="'Inter','SF Pro Display',system-ui,sans-serif" font-size="18" font-weight="900" fill="#003D6B" letter-spacing="0.01em">BET</text>
        <text x="74" y="18" font-family="'Inter','SF Pro Display',system-ui,sans-serif" font-size="18" font-weight="900" fill="#F8971F" letter-spacing="0.01em">365</text>
      </svg>
      <div class="header-actions">
        <RouterLink
          :to="hubRoute"
          class="support-btn"
          :aria-label="inboxEnabled && unreadCount ? t('messages.unread_badge', { count: unreadCount }) : t(hubOpenLabelKey)"
        >
          <svg class="hub-icon" viewBox="0 0 24 24" aria-hidden="true">
            <path
              d="M12 3C7.03 3 3 6.58 3 11c0 2.02.9 3.86 2.38 5.24L4 21l4.2-1.02A10.8 10.8 0 0 0 12 19c4.97 0 9-3.58 9-8s-4.03-8-9-8Z"
              fill="none"
              stroke="currentColor"
              stroke-width="1.8"
              stroke-linejoin="round"
            />
            <circle cx="9" cy="11" r="1" fill="currentColor" />
            <circle cx="12" cy="11" r="1" fill="currentColor" />
            <circle cx="15" cy="11" r="1" fill="currentColor" />
          </svg>
          <span v-if="auth.user && inboxEnabled && unreadCount > 0" class="hub-badge">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>
        </RouterLink>
        <div class="header-divider" />
        <LocaleSwitcher />
        <template v-if="auth.user">
          <CashBalanceChip />
          <UserAvatarMenu />
        </template>
        <button v-else type="button" class="login-btn" @click="auth.showLoginPrompt(route.fullPath)">
          {{ t('auth.login') }}
        </button>
      </div>
    </header>

    <div v-if="showAnnouncement" class="announce-strip">
      <AnnouncementMarquee
        :items="announcements"
        :target-id="primaryAnnouncementId"
        embedded
      />
    </div>

    <main ref="mainRef" :class="['main', { 'has-nav': showBottomNav, 'main--detail': isDetailPage }]">
      <RouterView v-slot="{ Component, route: viewRoute }">
        <KeepAlive v-if="viewRoute.meta.keepAlive" :max="10">
          <component :is="Component" :key="viewRoute.path" />
        </KeepAlive>
        <component v-else :is="Component" :key="viewRoute.fullPath" />
      </RouterView>
    </main>

    <nav
      v-if="showBottomNav"
      class="bottom-nav"
      :class="{ 'bottom-nav--hidden': bottomNavHidden }"
      aria-label="Main"
    >
      <RouterLink to="/" class="nav-item" :class="{ active: route.path === '/' }">
        <BottomNavIcon name="home" />
        <span class="nav-label">{{ t('nav.home') }}</span>
      </RouterLink>
      <RouterLink
        to="/bet"
        class="nav-item"
        :class="{ active: route.path === '/bet' || route.path.startsWith('/match') }"
      >
        <BottomNavIcon name="bet" />
        <span class="nav-label">{{ t('nav.bet') }}</span>
      </RouterLink>
      <RouterLink to="/bets" class="nav-item" :class="{ active: route.path === '/bets' }">
        <BottomNavIcon name="history" />
        <span class="nav-label">{{ t('nav.bet_history') }}</span>
      </RouterLink>
      <RouterLink
        to="/wallet"
        class="nav-item"
        :class="{ active: route.path === '/wallet' || route.path.startsWith('/wallet/') }"
      >
        <BottomNavIcon name="wallet" />
        <span class="nav-label">{{ t('nav.my_wallet') }}</span>
      </RouterLink>
    </nav>

    <BackToTopButton
      :scroll-el="mainRef"
      :above-nav="showBottomNav && !bottomNavHidden"
    />

    <BetSlipDrawer v-model="slip.drawerOpen" />
  </div>
</template>

<style scoped>
.layout {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg-body);
  box-sizing: border-box;
  padding-top: var(--safe-top);
}
.header {
  flex-shrink: 0;
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  min-height: var(--player-header-h, 48px);
  background: #FFFFFF;
  border-bottom: 1px solid var(--border);
  z-index: 120;
}
.logo {
  height: 22px;
  width: auto;
  display: block;
  flex-shrink: 0;
}
.header-actions {
  --header-chip-h: 32px;
  display: flex;
  gap: 6px;
  align-items: center;
  min-width: 0;
}
.header-actions :deep(.locale-switch:not(.compact)),
.header-actions :deep(.cash-chip),
.header-actions :deep(.avatar-btn) {
  height: var(--header-chip-h);
  box-sizing: border-box;
}
.header-actions :deep(.avatar-btn) {
  width: var(--header-chip-h);
}

.header-divider {
  width: 1px;
  height: 18px;
  background: #E5E7EB;
  flex-shrink: 0;
  margin: 0 2px;
}

.support-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  width: var(--header-chip-h, 32px);
  height: var(--header-chip-h, 32px);
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: #F5F7FA;
  color: var(--primary);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
  flex-shrink: 0;
  position: relative;
  text-decoration: none;
}
.support-btn:active {
  background: var(--bg-hover);
  border-color: var(--border-active);
}

.support-icon, .hub-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.hub-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--primary);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  pointer-events: none;
}

.support-label {
  display: none;
}

.login-btn {
  padding: 6px 18px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--primary);
  background: var(--primary);
  color: #FFFFFF;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s;
}
.login-btn:active {
  background: var(--primary-dark);
}

.announce-strip {
  flex-shrink: 0;
  z-index: 105;
  background: #FFFFFF;
  position: relative;
  border-bottom: 1px solid var(--border);
}

.main {
  flex: 1;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 10px 14px 0;
}
.main.has-nav {
  padding-bottom: calc(var(--player-bottom-nav-h) + var(--safe-bottom));
}
.main.main--detail {
  padding-top: 0;
}

.bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  background: #FFFFFF;
  box-sizing: border-box;
  min-height: calc(var(--player-bottom-nav-h) + var(--safe-bottom));
  padding-bottom: var(--safe-bottom);
  border-top: 1px solid var(--border);
  z-index: 100;
  transition: transform 0.28s ease, opacity 0.28s ease;
  will-change: transform;
}

.bottom-nav--hidden {
  transform: translateY(100%);
  opacity: 0;
  pointer-events: none;
}
.nav-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 7px 2px 8px;
  font-size: 10px;
  color: var(--text-muted);
  font-weight: 500;
  letter-spacing: 0.01em;
  position: relative;
  transition: color 0.2s;
  line-height: 1.2;
  min-width: 0;
  text-decoration: none;
}

.nav-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0 2px;
}

.nav-item.active {
  color: var(--primary);
  font-weight: 700;
}

.nav-item.active :deep(.nav-icon) {
  color: var(--primary);
  filter: drop-shadow(0 1px 2px rgba(0, 61, 107, 0.2));
}

.nav-item.active::after {
  content: '';
  position: absolute;
  top: 0;
  left: 18%;
  right: 18%;
  height: 2.5px;
  background: var(--primary);
  border-radius: 0 0 3px 3px;
}
</style>