<!--
  外部系统 SSO 桥接页（cloud_law -> EchoChat）

  入参（query）：
    - payload: URI 编码的 JSON 字符串 { token, refresh_token, expires_in, user }
    - redirect: URI 编码的目标 hash 路径，例如 /pages/meeting/join?code=XXX-XXX-XXX

  逻辑：
    1. 读取 payload，写入 storage（saveToken + saveUserInfo）
    2. 同步 user store
    3. 跳转 redirect（默认 /pages/meeting/index）
-->
<template>
  <view class="sso">
    <!-- 仅出错时显示文字；正常跳转过程肉眼无感（背景与会议页一致） -->
    <text v-if="hasError" class="sso-title">{{ statusText }}</text>
  </view>
</template>

<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { saveToken, saveUserInfo } from '@/utils/storage'
import { useUserStore } from '@/store/user'
import { useWebSocketStore } from '@/store/websocket'
import { useChatStore } from '@/store/chat'
import { useContactStore } from '@/store/contact'
import { useGroupStore } from '@/store/group'
import { useNotifyStore } from '@/store/notify'

const statusText = ref('正在登录…')
const hasError = ref(false)

function safeDecode(value) {
  try {
    return decodeURIComponent(value)
  } catch (e) {
    return value
  }
}

function readRawQueryParams() {
  const result = {}
  try {
    if (typeof window === 'undefined') return result
    const search = String(window.location.search || '').replace(/^\?/, '')
    const hash = String(window.location.hash || '')
    const hashQuery = hash.indexOf('?') >= 0 ? hash.slice(hash.indexOf('?') + 1) : ''
    ;[search, hashQuery].forEach(raw => {
      if (!raw) return
      const params = new URLSearchParams(raw)
      params.forEach((value, key) => {
        if (result[key] === undefined) {
          result[key] = value
        }
      })
    })
  } catch (e) {}
  return result
}

function readSsoParam(query, key) {
  const value = query && query[key] !== undefined ? query[key] : readRawQueryParams()[key]
  return value === undefined || value === null ? '' : String(value)
}

function resolveSsoPayload(query) {
  const payloadText = readSsoParam(query, 'payload')
  if (payloadText) {
    return JSON.parse(safeDecode(payloadText))
  }
  const token = readSsoParam(query, 'token')
  const refreshToken = readSsoParam(query, 'refresh_token')
  const expiresIn = Number(readSsoParam(query, 'expires_in') || 0)
  const userText = readSsoParam(query, 'user')
  const user = userText ? JSON.parse(safeDecode(userText)) : null
  return { token, refresh_token: refreshToken, expires_in: expiresIn, user }
}

function decodeJwtPayload(token) {
  try {
    const parts = String(token || '').split('.')
    if (parts.length < 2) return null
    let base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/')
    while (base64.length % 4) base64 += '='
    const binary = atob(base64)
    const json = decodeURIComponent(Array.prototype.map.call(binary, c => {
      return `%${(`00${c.charCodeAt(0).toString(16)}`).slice(-2)}`
    }).join(''))
    return JSON.parse(json)
  } catch (e) {
    return null
  }
}

function resolveSsoUser(payload) {
  if (payload && payload.user) return payload.user
  const claims = decodeJwtPayload(payload && payload.token)
  if (!claims || !claims.user_id) return null
  const username = claims.username || String(claims.user_id)
  return {
    id: claims.user_id,
    user_id: claims.user_id,
    username,
    nickname: username,
    roles: Array.isArray(claims.roles) ? claims.roles : []
  }
}

function resolveRedirect(query) {
  const rawRedirect = readSsoParam(query || {}, 'redirect')
  const decoded = rawRedirect ? safeDecode(rawRedirect) : '/pages/meeting/index'
  const cleaned = String(decoded || '').trim().replace(/^["']+|["']+$/g, '')
  return cleaned || '/pages/meeting/index'
}

function markCloudLawEmbed() {
  try {
    if (typeof window === 'undefined') return
    window.sessionStorage.setItem('echo_cloud_law_meeting_embed', '1')
  } catch (e) {}
}

function bootstrapAfterSso(token) {
  // 模拟 App.onLaunch 的初始化路径：先重连 WS（顶掉旧 token 连接），再注册各 store 的 ws 监听并拉初始数据
  try {
    const wsStore = useWebSocketStore()
    wsStore.disconnect()
    wsStore.connect(token)
  } catch (wsErr) {
    console.warn('[SSO] WebSocket 重连失败', wsErr)
  }
  try {
    const chatStore = useChatStore()
    const contactStore = useContactStore()
    const groupStore = useGroupStore()
    const notifyStore = useNotifyStore()
    chatStore.initWsListeners()
    contactStore.initWsListeners()
    groupStore.initWsListeners()
    notifyStore.initWsListeners()
    contactStore.fetchPendingRequests().catch(() => {})
    notifyStore.fetchUnreadCount().catch(() => {})
  } catch (storeErr) {
    console.warn('[SSO] 全局 store 初始化异常', storeErr)
  }
}

onLoad((query) => {
  try {
    try {
      console.log('[SSO] location:', {
        search: typeof window !== 'undefined' ? window.location.search : '',
        hash: typeof window !== 'undefined' ? window.location.hash : '',
        query
      })
    } catch (logErr) {}
    const payload = resolveSsoPayload(query || {})
    const ssoUser = resolveSsoUser(payload)
    const redirect = resolveRedirect(query || {})
    console.log('[SSO] resolved params:', {
      hasToken: !!(payload && payload.token),
      hasPayloadUser: !!(payload && payload.user),
      hasSsoUser: !!ssoUser,
      userId: ssoUser && (ssoUser.id || ssoUser.user_id),
      redirect
    })
    if (!payload || !payload.token || !ssoUser) {
      statusText.value = '缺少 payload 参数'
      hasError.value = true
      return
    }
    markCloudLawEmbed()
    // 写入持久化存储
    saveToken(payload.token, payload.refresh_token || '', payload.expires_in || 0)
    saveUserInfo(ssoUser)
    // 同步 pinia store
    const userStore = useUserStore()
    userStore.token = payload.token
    userStore.userInfo = ssoUser

    bootstrapAfterSso(payload.token)

    statusText.value = '登录成功，跳转中…'
    console.log('[SSO] redirectTo:', redirect)
    // redirectTo 不保留历史，避免返回到 sso 页造成循环
    // 此前曾延迟 200ms 跳转，导致拉起会议时中间出现白底"正在登录…"过渡页；
    // saveToken/saveUserInfo 已是同步 storage 写入，无需额外等待。
    uni.redirectTo({ url: redirect })
  } catch (e) {
    console.error('[SSO] 解析失败', e)
    statusText.value = `SSO 失败：${e.message || e}`
    hasError.value = true
  }
})
</script>

<style scoped>
.sso {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 与进入后的会议页背景一致，跳转闪烁不可见 */
  background: #050b1d;
}
.sso-title {
  font-size: 30rpx;
  color: rgba(255,255,255,0.78);
}
</style>
