<template>
  <v-container fluid class="agent-page pa-6">
    <div class="page-head mb-5">
      <div>
        <h1 class="text-h4 font-weight-bold mb-2">Agent 治理</h1>
        <p class="text-body-1 text--secondary mb-0">
          统一管理平台内部 Agent 的机器身份、最小授权、短期凭证和决策证据。
        </p>
      </div>
      <div class="head-actions">
        <v-btn outlined color="primary" :loading="loading" @click="loadAll">
          <v-icon left>mdi-refresh</v-icon>刷新
        </v-btn>
        <v-btn v-if="canManage" color="primary" depressed @click="registerDialog = true">
          <v-icon left>mdi-robot-outline</v-icon>登记 Agent
        </v-btn>
      </div>
    </div>

    <v-alert outlined color="deep-orange" icon="mdi-shield-alert-outline" class="mb-6">
      <strong>执行边界：</strong>高风险和关键风险操作即使通过双人审批，也只转为人工执行；
      平台不会自动执行。凭证最长 15 分钟、仅签发时显示一次，数据库只保存摘要。
    </v-alert>

    <v-row class="mb-4">
      <v-col v-for="item in metrics" :key="item.label" cols="6" md="3">
        <div class="metric-block">
          <div class="text-caption text--secondary">{{ item.label }}</div>
          <div class="metric-value">{{ item.value }}</div>
        </div>
      </v-col>
    </v-row>

    <v-card outlined class="mb-6">
      <v-card-title class="d-flex justify-space-between align-center px-5">
        <span>身份与授权台账</span>
        <v-chip small outlined color="primary">版本化登记</v-chip>
      </v-card-title>
      <v-data-table :headers="agentHeaders" :items="agents" :loading="loading" :items-per-page="10">
        <template v-slot:[`item.identity`]="{ item }">
          <div class="font-weight-medium">{{ item.name }}</div>
          <div class="caption mono text--secondary">{{ item.code }}</div>
        </template>
        <template v-slot:[`item.autonomy_level`]="{ item }">
          <v-chip small outlined :color="autonomy(item.autonomy_level).color">
            {{ autonomy(item.autonomy_level).label }}
          </v-chip>
        </template>
        <template v-slot:[`item.scope`]="{ item }">
          <div>{{ (item.environments || []).join(' / ') }}</div>
          <div class="caption text--secondary">{{ (item.business_domain_uids || []).length }} 个业务域</div>
        </template>
        <template v-slot:[`item.status`]="{ item }">
          <v-chip x-small dark :color="statusColor(item.status)">{{ item.status }}</v-chip>
        </template>
        <template v-slot:[`item.actions`]="{ item }">
          <v-btn text x-small color="primary" @click="openDetail(item)">授权</v-btn>
          <v-btn v-if="canOperate && item.status === 'active'" text x-small color="primary" @click="issueCredential(item)">凭证</v-btn>
          <v-btn v-if="canOperate && item.status === 'draft'" text x-small color="success" @click="transition(item, 'activate')">启用</v-btn>
          <v-btn v-if="canOperate && item.status === 'active'" text x-small color="warning" @click="transition(item, 'suspend')">暂停</v-btn>
        </template>
        <template v-slot:no-data>
          <div class="empty-state py-10">
            <v-icon size="38" color="grey lighten-1">mdi-robot-off-outline</v-icon>
            <div class="mt-3">尚未登记受治理的 Agent</div>
          </div>
        </template>
      </v-data-table>
    </v-card>

    <v-card outlined>
      <v-card-title class="px-5">最近策略判定</v-card-title>
      <v-data-table :headers="actionHeaders" :items="actions" :loading="loading" :items-per-page="10">
        <template v-slot:[`item.tool`]="{ item }">
          <div class="mono">{{ item.tool_name }}</div>
          <div class="caption text--secondary">{{ item.interface_type }} · {{ item.action }}</div>
        </template>
        <template v-slot:[`item.decision`]="{ item }">
          <v-chip x-small outlined :color="decisionColor(item.decision)">{{ item.decision }}</v-chip>
          <div class="caption mt-1">{{ item.reason_code }}</div>
        </template>
        <template v-slot:[`item.safety`]="{ item }">
          <span>{{ item.risk_level }}</span>
          <div class="caption text--secondary">
            {{ item.automatic_execution_allowed ? '仅低风险自动' : '不自动执行' }}
          </div>
        </template>
        <template v-slot:[`item.actions`]="{ item }">
          <v-btn text x-small color="primary" @click="showReplay(item)">回放证据</v-btn>
          <v-btn v-if="canManage && item.decision === 'pending_approval'" text x-small color="primary" @click="reconcile(item)">同步审批</v-btn>
        </template>
      </v-data-table>
    </v-card>

    <v-dialog v-model="registerDialog" max-width="680">
      <v-card>
        <v-card-title>登记受治理 Agent</v-card-title>
        <v-card-text>
          <v-text-field v-model.trim="form.code" label="Agent 编码" outlined dense />
          <v-text-field v-model.trim="form.name" label="名称" outlined dense />
          <v-textarea v-model.trim="form.purpose" label="用途说明" outlined dense rows="2" />
          <v-text-field v-model.trim="form.owner_uid" label="责任人 UID" outlined dense />
          <v-text-field v-model.trim="form.domain_uid" label="业务域 UID" outlined dense />
          <v-select v-model="form.autonomy_level" :items="autonomyOptions" label="自主等级" outlined dense />
          <v-select v-model="form.environment" :items="environmentOptions" label="环境" outlined dense />
          <div class="caption text--secondary">建议型 Agent 强制携带证据引用；首批界面不提供自动执行登记。</div>
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn text @click="registerDialog = false">取消</v-btn>
          <v-btn color="primary" depressed :loading="saving" @click="saveAgent">保存</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <v-dialog v-model="grantDialog" max-width="720">
      <v-card>
        <v-card-title>工具授权 · {{ selectedAgent && selectedAgent.name }}</v-card-title>
        <v-card-text>
          <v-alert dense outlined type="info">授权严格绑定接口、工具、动作、业务域和环境。</v-alert>
          <v-data-table :headers="grantHeaders" :items="selectedGrants" dense hide-default-footer />
          <template v-if="canOperate">
            <v-divider class="my-4" />
            <v-row dense>
              <v-col cols="12" md="4"><v-select v-model="grant.interface_type" :items="['api', 'mcp']" label="接口" outlined dense /></v-col>
              <v-col cols="12" md="8"><v-text-field v-model.trim="grant.tool_name" label="工具名" outlined dense /></v-col>
              <v-col cols="12" md="4"><v-select v-model="grant.action" :items="allowedActions" label="动作" outlined dense /></v-col>
              <v-col cols="12" md="4"><v-select v-model="grant.risk_level" :items="['low', 'medium', 'high', 'critical']" label="风险" outlined dense /></v-col>
              <v-col cols="12" md="4"><v-switch v-model="grant.requires_approval" label="需要审批" inset /></v-col>
            </v-row>
          </template>
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn text @click="grantDialog = false">关闭</v-btn>
          <v-btn v-if="canOperate" color="primary" depressed :loading="saving" @click="saveGrant">新增授权</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <v-dialog v-model="credentialDialog" max-width="720" persistent>
      <v-card>
        <v-card-title>一次性机器凭证</v-card-title>
        <v-card-text>
          <v-alert type="warning" outlined>关闭后无法再次查看。请使用企业密钥系统安全保存，禁止写入日志或源码。</v-alert>
          <v-textarea :value="issuedCredential.token" readonly outlined rows="5" class="mono" label="X-Agent-Credential" />
          <div class="caption">失效时间：{{ formatTime(issuedCredential.expires_at) }}</div>
        </v-card-text>
        <v-card-actions><v-spacer /><v-btn color="primary" depressed @click="closeCredential">我已安全保存</v-btn></v-card-actions>
      </v-card>
    </v-dialog>

    <v-dialog v-model="replayDialog" max-width="800">
      <v-card>
        <v-card-title>决策证据回放</v-card-title>
        <v-card-text><pre class="replay-box">{{ replayText }}</pre></v-card-text>
        <v-card-actions><v-spacer /><v-btn text @click="replayDialog = false">关闭</v-btn></v-card-actions>
      </v-card>
    </v-dialog>
  </v-container>
</template>

<script>
import {
  createAgentToolGrant,
  getAgentGovernanceDashboard,
  getGovernedAgent,
  issueAgentCredential,
  listAgentActions,
  listGovernedAgents,
  reconcileAgentAction,
  registerGovernedAgent,
  replayAgentAction,
  transitionGovernedAgent
} from '@/api/agentGovernance'

const unwrap = response => response && response.data && response.data.data !== undefined ? response.data.data : (response && response.data) || response

export default {
  name: 'AgentGovernance',
  data: () => ({
    loading: false,
    saving: false,
    registerDialog: false,
    grantDialog: false,
    credentialDialog: false,
    replayDialog: false,
    dashboard: {},
    agents: [],
    actions: [],
    selectedAgent: null,
    selectedGrants: [],
    issuedCredential: {},
    replayText: '',
    form: { code: '', name: '', purpose: '', owner_uid: '', domain_uid: '', autonomy_level: 'read_only', environment: 'test' },
    grant: { interface_type: 'mcp', tool_name: 'knowledge.search', action: 'read', risk_level: 'low', requires_approval: false },
    autonomyOptions: [{ text: '只读', value: 'read_only' }, { text: '建议', value: 'suggestion' }],
    environmentOptions: [{ text: '开发', value: 'development' }, { text: '测试', value: 'test' }, { text: '生产', value: 'production' }],
    agentHeaders: [{ text: 'Agent', value: 'identity' }, { text: '自主等级', value: 'autonomy_level' }, { text: '范围', value: 'scope' }, { text: '版本', value: 'current_version' }, { text: '状态', value: 'status' }, { text: '操作', value: 'actions', sortable: false }],
    actionHeaders: [{ text: '工具与动作', value: 'tool' }, { text: '环境', value: 'environment' }, { text: '判定', value: 'decision' }, { text: '安全边界', value: 'safety' }, { text: '证据', value: 'actions', sortable: false }],
    grantHeaders: [{ text: '接口', value: 'interface_type' }, { text: '工具', value: 'tool_name' }, { text: '动作', value: 'action' }, { text: '环境', value: 'environment' }, { text: '风险', value: 'risk_level' }]
  }),
  computed: {
    permissions () { return (this.$store.state.user && this.$store.state.user.permissions) || [] },
    canOperate () { return this.permissions.includes('agents:operate') },
    canManage () { return this.permissions.includes('agents:manage') },
    metrics () {
      return [
        { label: '登记总数', value: this.dashboard.agent_count || 0 },
        { label: '当前启用', value: this.dashboard.active_count || 0 },
        { label: '已拒绝越权', value: this.dashboard.denied_count || 0 },
        { label: '等待审批', value: this.dashboard.pending_approval_count || 0 }
      ]
    },
    allowedActions () { return this.selectedAgent && this.selectedAgent.autonomy_level === 'suggestion' ? ['read', 'suggest'] : ['read'] }
  },
  created () { this.loadAll() },
  methods: {
    autonomy (value) { return ({ read_only: { label: '只读', color: 'blue-grey' }, suggestion: { label: '建议', color: 'primary' }, approval_execution: { label: '审批执行', color: 'warning' }, low_risk_automatic: { label: '低风险自动', color: 'deep-orange' } })[value] || { label: value, color: 'grey' } },
    statusColor (value) { return ({ active: 'success', suspended: 'warning', retired: 'grey', draft: 'blue-grey' })[value] || 'grey' },
    decisionColor (value) { return value === 'denied' ? 'error' : value === 'pending_approval' ? 'warning' : 'success' },
    formatTime (value) { return value ? new Date(value).toLocaleString() : '-' },
    async loadAll () { this.loading = true; try { const [d, a, r] = await Promise.all([getAgentGovernanceDashboard(), listGovernedAgents(), listAgentActions()]); this.dashboard = unwrap(d) || {}; this.agents = unwrap(a) || []; this.actions = unwrap(r) || [] } finally { this.loading = false } },
    async saveAgent () { this.saving = true; try { await registerGovernedAgent({ code: this.form.code, name: this.form.name, purpose: this.form.purpose, owner_uid: this.form.owner_uid, business_domain_uids: [this.form.domain_uid], environments: [this.form.environment], autonomy_level: this.form.autonomy_level, prompt_policy: { trusted_instruction_sources: ['platform_system'], untrusted_context_mode: 'quote_only', citation_required: this.form.autonomy_level === 'suggestion' } }); this.registerDialog = false; await this.loadAll() } finally { this.saving = false } },
    async openDetail (item) { this.selectedAgent = item; const response = await getGovernedAgent(item.uid); const detail = unwrap(response); this.selectedAgent = detail; this.selectedGrants = detail.grants || []; this.grantDialog = true },
    async saveGrant () { this.saving = true; try { await createAgentToolGrant(this.selectedAgent.uid, { ...this.grant, business_domain_uid: this.selectedAgent.business_domain_uids[0], environment: this.selectedAgent.environments[0] }); await this.openDetail(this.selectedAgent); await this.loadAll() } finally { this.saving = false } },
    async transition (item, action) { await transitionGovernedAgent(item.uid, { action, reason: 'Agent 治理台账操作' }, item.current_version); await this.loadAll() },
    async issueCredential (item) { const response = await issueAgentCredential(item.uid, 300); this.issuedCredential = unwrap(response) || {}; this.credentialDialog = true },
    closeCredential () { this.issuedCredential = {}; this.credentialDialog = false },
    async reconcile (item) { await reconcileAgentAction(item.uid, item.current_version); await this.loadAll() },
    async showReplay (item) { const response = await replayAgentAction(item.uid); this.replayText = JSON.stringify(unwrap(response), null, 2); this.replayDialog = true }
  }
}
</script>

<style scoped>
.agent-page { max-width: 1500px; margin: 0 auto; }
.page-head { display: flex; justify-content: space-between; gap: 24px; align-items: flex-start; }
.head-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.metric-block { border-top: 3px solid #1565c0; padding: 16px 4px 8px; }
.metric-value { font-size: 28px; font-weight: 700; line-height: 1.2; margin-top: 5px; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; overflow-wrap: anywhere; }
.empty-state { text-align: center; color: #607d8b; }
.replay-box { padding: 16px; max-height: 440px; overflow: auto; background: #f5f7f9; border: 1px solid #dce3e8; border-radius: 8px; white-space: pre-wrap; overflow-wrap: anywhere; }
@media (max-width: 767px) { .page-head { flex-direction: column; } .head-actions { width: 100%; } }
</style>
