<template>
  <view :class="['page-wrapper bg-body', { dark: isDark }]">
    <cwg-match-media :max-width="990" v-if="!isLoginPage">
      <cwg-pc-header @open-right-drawer="openRightDrawer" @open-left-drawer="openLeftDrawer"
        :sidebarVisible="sidebarVisible" v-if="type != 'webview'" />
      <view class="sidebar-mask mask-visible" v-if="sidebarVisible" @click="openLeftDrawer">
      </view>
      <view class="fixed" v-if=pageTitle></view>
      <cwg-header v-if=pageTitle class="custom-header" :title="pageTitle" />
    </cwg-match-media>
    <cwg-language style="width: 0;display: none;" />
    <cwg-progress />

    <view class="page-content" :style="{ backgroundColor: bgColor }">
      <cwg-match-media :max-width="991" v-if="!isLoginPage">
        <view class="left-sidebar" :class="{ 'sidebar-visible': sidebarVisible }">
          <cwg-sidebar @handle-click="openLeftDrawer" />
        </view>
        <view class="sidebar-mask" v-if="sidebarVisible" @click="openLeftDrawer" :style="{
          opacity: maskVisible ? 1 : 0,
          transition: 'opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1)'
        }">
        </view>
      </cwg-match-media>
      <view class="content-info">
        <!--      完善信息提示，-->
        <PrefectInfo v-if="!isLoginPage" />
        <!--      申请成为ib，-->
        <IbInfo ref="ibRef" v-if="!isLoginPage" />

        <view class="content-wrapper" :class="{ 'content-wrapper-padding': isContentPadding }">
          <!-- <cwg-header /> -->
          <transition name="fade" mode="out-in">
            <view>
              <slot />
            </view>
          </transition>
          <cwg-custom-footer v-if=!pageTitle />

          <cwg-match-media :max-width="991" v-if="!isLoginPage">
            <cwg-footer-link v-if=!pageTitle />
          </cwg-match-media>
        </view>
      </view>
      <view class="chat-icon cursor-pointer" :data-tooltip="t('Downloadpage.item16')" :class="{ 'chat-icon-expanded': isChatIconExpanded, 'chat-icon-hidden': type == 'chat' }"
        @click="handleChatIconClick">
        <cwg-icon name="chat" color="#fff" />
      </view>
      <view :style="{ height: isTabBarPage ? '60px' : '0px' }" />
    </view>
    <cwg-match-media :min-width="991" v-if="!isLoginPage">
      <cwg-footer-link />
    </cwg-match-media>

    <cwg-match-media :min-width="992" v-if="!isLoginPage">
      <view class="desktop-sidebar-toggle-fixed" :style="toggleFixedStyle">
        <cwg-sidebar-toggle />
      </view>
    </cwg-match-media>

  </view>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import useRoute, { updateRoute } from '@/hooks/useRoute'
import useRouter from '@/hooks/useRouter'
import useUserStore from '@/stores/use-user-store'
import { userApi } from '@/api/user'
import useGlobalStore from '@/stores/use-global-store'
import PrefectInfo from '@/components/PrefectInfo.vue'
import IbInfo from '@/components/IbInfo.vue'
import { userToken } from "@/composables/config";
import { useI18n } from 'vue-i18n'
import Config from '@/config/index'
import { customApi } from '@/service/custom'
import tool from "@/global/tool"
import LiveChatService from '@/utils/liveChat.js'
import { useWindowWidth } from '@/composables/useWindowWidth'
import { useLeftSidebarCollapse } from '@/composables/useLeftSidebarCollapse'
const windowWidth = useWindowWidth(300)
const isMobile = computed(() => windowWidth.value <= 991)
const { isCollapsed, syncCollapsedFromDom } = useLeftSidebarCollapse()

const SIDEBAR_WIDTH_EXPANDED = 280
const SIDEBAR_WIDTH_COLLAPSED = 64

const toggleFixedStyle = computed(() => {
  const width = isCollapsed.value ? SIDEBAR_WIDTH_COLLAPSED : SIDEBAR_WIDTH_EXPANDED
  return {
    left: `${width}px`,
  }
})
const { t, locale } = useI18n()
const globalStore = useGlobalStore()
const router = useRouter()
const userStore = useUserStore()

const props = defineProps({
  // 是否固定顶部导航栏
  isHeaderFixed: {
    type: Boolean,
    default: false,
  },
  // 是否登录页，登录页不显示侧边栏和顶部导航,注册忘记密码等页面
  isLoginPage: {
    type: Boolean,
    default: false,
  },
  // 是否含有padding 默认有
  isContentPadding: {
    type: Boolean,
    default: true,
  },
  // 主内容背景颜色
  bgColor: {
    type: String,
    default: '',
  },
  // 顶部导航栏标题
  pageTitle: {
    type: String,
    default: '',
  },
  type: {
    type: String,
    default: '',
  },
})
const isDark = computed(() => globalStore.theme === 'dark')
const isTabBarPage = ref(false)
const rightDrawerRef = ref<any>(null)
const noticeDrawerRef = ref<any>(null)
const ibRef = ref<any>(null)
const isChatIconExpanded = ref(false)

// 事件处理函数
const handleOpenIb = () => {
  if (ibRef.value) ibRef.value?.getInfo()
}

const handleOpenNoticeDrawer = () => {
  noticeDrawerRef.value?.open()
}
// 处理聊天图标点击
const handleChatIconClick = () => {
  // 如果还没显示 → 先滑出来
  if (isMobile.value && !isChatIconExpanded.value) {
    isChatIconExpanded.value = true
    return
  }
  if (isMobile.value) {
    router.push('/pages/common/chat')
  } else {
    if (LiveChatService) {
      LiveChatService.showChat()
    }
  }
  setTimeout(() => {
    isChatIconExpanded.value = false
  }, 300)
}

const handleOpenRightDrawer = () => {
  openRightDrawer()
}

// ========== WebSocket ==========
let websock: any = null
let reconnectTimer: any = null
const pushManager = ref<any>({})
const reasons = ref<any>({})

const initWebSocket = () => {
  let token = userToken.value || uni.getStorageSync('token')
  if (!token) return

  token = tool.tokenReplace(token);

  const wsUrl = `${Config.HostWs}/webSocket?Access-Token=${token}`

  websock = uni.connectSocket({
    url: wsUrl,
    success: () => {
      console.log('WebSocket connected successfully')
    },
    fail: () => {
      uni.showToast({ title: t('Msg.socket'), icon: 'none' })
    }
  })

  websock.onOpen(() => {
    console.log('WebSocket opened')
  })

  websock.onError(() => {
    clearTimeout(reconnectTimer)
    reconnectTimer = setTimeout(() => {
      initWebSocket()
    }, 3000)
  })

  websock.onMessage((res: any) => {
    console.log('接受道消息', res)
    try {
      const data = JSON.parse(res.data)
      if (data.newsType == 3) {
        pushRes(data)
      }
      if (data.newsType == 1) {
        // 认证更新文件信息
        uni.$emit('updateImproveFile', data)
      }
      if (data.newsType == 4) {
        // 全局广播未读消息数量更新
        uni.$emit('updateUnreadCount', data.count)
      }
    } catch (e) {
      console.error('WebSocket parse error:', e)
    }
  })

  websock.onClose(() => {
    // console.log('WebSocket closed')
  })
}

const pushRes = (data: any) => {
  const isCn = ['cn', 'zhHant'].includes(locale.value)

  let part1 = ''
  if (data.pushMessageId && pushManager.value[data.pushMessageId]) {
    part1 = isCn
      ? pushManager.value[data.pushMessageId].content
      : pushManager.value[data.pushMessageId].enContent
  }

  let part2 = ''
  if (data.approveDesc && reasons.value[data.approveDesc]) {
    part2 = isCn
      ? reasons.value[data.approveDesc].content
      : reasons.value[data.approveDesc].enContent
  }

  const msg = `${part1}\n${part2}`.trim()

  uni.showModal({
    title: t("news_add_field.Label.Tips"),
    content: msg || t('news_add_field.Label.Tips'),
    showCancel: false,
    confirmText: t('Btn.Confirm'),
    success: (res) => {
      if (res.confirm) {
        pushToSingle(data.newsType)
      }
    }
  })
}

//获取推送列表
const searchPush = async () => {
  if (!userToken.value) return
  let res = await customApi.PushMessageList({ type: null });
  if (res.code == 200) {
    if (res.data == null) {
      pushManager.value = {};
    } else {
      pushManager.value = res.data;
    }
  } else {
    uni.showToast({ title: res.msg, icon: 'none' });
  }
}
//获取原因列表
const searchReasons = async () => {
  if (!userToken.value) return
  let res = await customApi.reasonsRefusalList({ type: null });
  if (res.code == 200) {
    if (res.data == null) {
      reasons.value = {};
    } else {
      reasons.value = res.data;
    }
  } else {
    uni.showToast({ title: res.msg, icon: 'none' });
  }
}



const pushToSingle = (newsType: number) => {
  switch (newsType) {
    case 3:
      router
        .push({ path: "/pages/customer/recording-history", query: { type: 4 } })
        .catch((arr) => arr);
      break;
  }
}

onMounted(() => {
  syncCollapsedFromDom()
  // 只在组件挂载时注册事件监听器
  uni.$once('open-ib', handleOpenIb)
  uni.$on('open-right-drawer', handleOpenRightDrawer)
  searchPush()
  searchReasons()
  initWebSocket()
})

onUnmounted(() => {
  // 在组件销毁时移除事件监听器
  uni.$off('open-ib', handleOpenIb)
  uni.$off('open-right-drawer', handleOpenRightDrawer)

  if (websock) {
    websock.close()
    websock = null
  }
  clearTimeout(reconnectTimer)
})

function openRightDrawer() {
  rightDrawerRef.value?.open()
}

const sidebarVisible = ref(false)
const maskVisible = ref(false)
let sidebarTimer: any = null
let isAnimating = ref(false)

function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): T {
  let timer: any = null
  return ((...args: any[]) => {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => fn(...args), delay)
  }) as T
}

const toggleSidebar = debounce(() => {
  if (isAnimating.value) return

  isAnimating.value = true

  if (maskVisible.value) {
    maskVisible.value = false
    sidebarTimer = setTimeout(() => {
      sidebarVisible.value = false
      isAnimating.value = false
      sidebarTimer = null
    }, 200)
  } else {
    sidebarVisible.value = true
    sidebarTimer = setTimeout(() => {
      maskVisible.value = true
      isAnimating.value = false
      sidebarTimer = null
    }, 200)
  }
}, 300)

function openLeftDrawer() {
  if (sidebarTimer) {
    clearTimeout(sidebarTimer)
    sidebarTimer = null
  }
  toggleSidebar()
}

function handleDrawerNavigate(path: string) {
  router.push(path)
}

async function handleDrawerLogout() {
  try {
    const res = await userApi.logout()
    if (res.code === 200) {
      userStore.clearUserInfo()
      router.push('/pages/login/index')
    }
  } catch (error) {
    userStore.clearUserInfo()
    router.push('/pages/login/index')
  }
}

onLoad(() => {
  updateRoute()
})

onShow(() => {
  updateRoute()
})

</script>

<style lang="scss" scoped>
@import "@/uni.scss";

.page-wrapper {
  height: calc(100vh - (56px + var(--status-bar-height)));
}

.header-box {
  width: 100%;
  height: calc(56px + var(--status-bar-height));
}

.page-content {
  width: 100%;
  height: calc(100vh - (110px + var(--status-bar-height)));
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: relative;
  box-sizing: border-box;

  @media screen and (max-width: 768px) {
    height: calc(100vh - (56px + var(--status-bar-height)));
  }

  .content-info {
    height: calc(100vh - (110px + var(--status-bar-height)));
    overflow: auto;

    @media screen and (max-width: 768px) {
      height: calc(100vh - (56px + var(--status-bar-height)));
    }
  }

}

.left-sidebar {
  width: 0;
  overflow: hidden;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1000;
  background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
  transition: width 81ms cubic-bezier(0.4, 0, 0.2, 1);

}

.sidebar-mask {
  position: absolute;
  left: 0;
  top: 0;
  width: 100vw;
  height: calc(100vh - (56px + var(--status-bar-height)));
  background-color: rgba(0, 0, 0, 0.2);
  z-index: 101;
}

.mask-visible {
  background-color: rgba(0, 0, 0, 0);
  width: 100vw;
  height: calc(56px + var(--status-bar-height));
}

.sidebar-visible {
  width: px2rpx(280);
}

.content-wrapper {
  max-width: px2rpx(1320);
  width: 100%;
  margin: 0 auto;
  padding-top: px2rpx(20);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: calc(100vh - (110px + var(--status-bar-height)));

  @media screen and (max-width: 768px) {
    min-height: calc(100vh - (56px + var(--status-bar-height)));
  }
}

.chat-icon {
  width: px2rpx(50);
  height: px2rpx(50);
  border-radius: 50%;
  background-color: #cf1322;
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  bottom: px2rpx(25);
  right: px2rpx(0);
  z-index: 999;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 px2rpx(8) px2rpx(20) rgba(0, 0, 0, 0.15);
  will-change: transform;
}

@media (max-width: 991px) {
  .chat-icon {
    right: px2rpx(-25);
  }

  .chat-icon-expanded {
    bottom: px2rpx(20);
    right: px2rpx(20);
    transform: scale(1.1);
    box-shadow: 0 px2rpx(12) px2rpx(30) rgba(0, 0, 0, 0.2);
  }
}

.chat-icon:hover {
  transform: scale(1.1);
}



.chat-icon-hidden {
  display: none;
}

.fixed {
  // position: fixed;
  // top: 0;
  // left: 0;
  width: 100%;
  height: calc(56px + var(--status-bar-height));
  --bs-bg-opacity: 1;
  background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
  z-index: 9;
}

.custom-header {
  --bs-bg-opacity: 1;
  background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
  padding: 0 px2rpx(15);
  position: fixed;
  top: calc(var(--status-bar-height));
  left: 0;
}

.content-wrapper-padding {
  padding: px2rpx(16) px2rpx(16) 0 px2rpx(16);

  @media screen and (max-width: 1645px) {
    padding: px2rpx(16) px2rpx(48) 0 px2rpx(48);
  }

  @media screen and (max-width: 768px) {
    padding: px2rpx(16) px2rpx(16) 0 px2rpx(16);
  }
}

@media screen and (max-width: 991px) {
  .page-wrapper {
    height: 100vh;
  }
}


.mobile-menu-btn {
  width: px2rpx(64);
  height: px2rpx(64);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 页面切换动画 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

/* 侧边栏动画优化 */
.left-sidebar {
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.sidebar-mask {
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* 内容区域动画 */
.content-wrapper {
  animation: slideIn 0.2s ease-out;
}

@keyframes slideIn {
  from {
    transform: translateY(20px);
    opacity: 0;
  }

  to {
    transform: translateY(0);
    opacity: 1;
  }
}

.desktop-sidebar-toggle-fixed {
  position: fixed;
  top: 58px;
  z-index: 120;
  display: flex;
  align-items: center;
  height: 48px;
  padding: 0 8px;
  box-sizing: border-box;
  transition: left 281ms cubic-bezier(0.4, 0, 0.2, 1);
}
</style>
