<template>
  <div class="user-sessions-panel">
    <div class="user-sessions-panel__header">
      <a-space :size="8" align="center" wrap>
        <strong>用户：</strong>
        <span class="user-sessions-panel__user-id">{{ userId }}</span>
        <a-switch
          v-model:checked="includeRevoked"
          checked-children="含已撤销"
          un-checked-children="仅活跃"
          size="small"
          @change="loadSessions"
        />
        <a-button size="small" @click="loadSessions">刷新</a-button>
      </a-space>
    </div>

    <ActiveSessionsPanel
      :sessions="sessions"
      :loading="loading"
      :revoking-id="revokingId"
      :admin-mode="true"
      @refresh="loadSessions"
      @revoke="handleRevoke"
    />
  </div>
</template>

<script setup lang="ts">
/**
 * Admin: see and revoke any user's active sessions (U9).
 *
 * Wraps the shared :class:`ActiveSessionsPanel` in ``adminMode`` so the
 * same table layout is reused (no copy-paste of the table, formatTime,
 * revoked-strikethrough, etc.).  The panel itself is data-agnostic —
 * we hand it the sessions array and listen for the ``revoke`` event.
 *
 * The header (above the table) carries the "include revoked" toggle so
 * admins can audit past kicked sessions.
 */
import { ref, onMounted, watch } from 'vue'
import { message } from 'ant-design-vue'
import ActiveSessionsPanel from '@/components/settings/ActiveSessionsPanel.vue'
import { adminApi } from '@/api/admin'
import type { ISessionInfo } from '@/api/auth'

const props = defineProps<{
  /** The user whose sessions to manage. */
  userId: string
}>()

const sessions = ref<ISessionInfo[]>([])
const loading = ref(false)
const revokingId = ref<string | null>(null)
const includeRevoked = ref(false)

async function loadSessions(): Promise<void> {
  loading.value = true
  try {
    sessions.value = await adminApi.listUserSessions(
      props.userId,
      includeRevoked.value,
    )
  } catch (err) {
    const msg = _extractMessage(err, '加载会话列表失败')
    message.error(msg)
  } finally {
    loading.value = false
  }
}

async function handleRevoke(sid: string): Promise<void> {
  revokingId.value = sid
  try {
    const result = await adminApi.revokeUserSession(props.userId, sid)
    if (result.revoked) {
      message.success('已撤销该会话')
    } else {
      message.info('该会话已是撤销状态')
    }
    // Optimistic UI: drop the row, then re-fetch (cheap; list is small).
    sessions.value = sessions.value.filter((s) => s.id !== sid)
    await loadSessions()
  } catch (err) {
    const msg = _extractMessage(err, '撤销会话失败')
    message.error(msg)
  } finally {
    revokingId.value = null
  }
}

function _extractMessage(err: unknown, fallback: string): string {
  if (err && typeof err === 'object') {
    const obj = err as { detail?: unknown; message?: unknown }
    if (typeof obj.detail === 'string' && obj.detail) return obj.detail
    if (typeof obj.message === 'string' && obj.message) return obj.message
  }
  return fallback
}

onMounted(() => {
  loadSessions()
})

// Reload when the user id prop changes (e.g. admin switches between
// users in a parent UsersView).
watch(
  () => props.userId,
  () => {
    loadSessions()
  },
)
</script>

<style scoped>
.user-sessions-panel {
  width: 100%;
}

.user-sessions-panel__header {
  margin-bottom: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
}

.user-sessions-panel__user-id {
  font-family: var(--font-mono, monospace);
  font-size: var(--font-sm);
  color: var(--text-secondary);
}
</style>
