<script setup lang="ts">
import {
  CheckCircle2,
  CircleAlert,
  Cookie,
  Fingerprint,
  Gauge,
  KeyRound,
  Loader2,
  Lock,
  RefreshCw,
  ServerCog,
  Shield,
  ShieldCheck,
  Timer,
  XCircle,
} from '@lucide/vue'
import { computed } from 'vue'
import { RouterLink } from 'vue-router'
import {
  useOpenClawCapabilitiesQuery,
  useOpenClawOverviewQuery,
} from '../api/openclawRuntime'
import { useSecurityStatusQuery } from '../api/security'
import AsyncStatePanel from '../components/mission-control/AsyncStatePanel.vue'

const statusQuery = useSecurityStatusQuery()
const status = computed(() => statusQuery.data.value ?? null)
const loading = computed(() => statusQuery.isPending.value)
const error = computed(() => {
  const cause = statusQuery.error.value
  return cause instanceof Error ? cause.message : ''
})
const overviewQuery = useOpenClawOverviewQuery()
const capabilitiesQuery = useOpenClawCapabilitiesQuery()

const connection = computed(() => overviewQuery.data.value?.connection ?? null)
const capabilities = computed(() => capabilitiesQuery.data.value ?? [])
const availableCapabilities = computed(() =>
  capabilities.value.filter(item => item.available).length,
)
const totalCapabilities = computed(() => capabilities.value.length)
const approvalCapability = computed(() =>
  capabilities.value.find(item => item.id === 'approvals-resolve') ?? null,
)

async function refresh() {
  await Promise.allSettled([
    statusQuery.refetch(),
    overviewQuery.refetch(),
    capabilitiesQuery.refetch(),
  ])
}
</script>

<template>
  <div class="security-page nexus-page">
    <header class="nexus-page-header">
      <div class="nexus-page-header__identity">
        <div class="nexus-page-header__icon"><Shield :size="20" aria-hidden="true" /></div>
        <div>
          <span class="eyebrow">TRUST &amp; POLICY</span>
          <h1>Security Center</h1>
          <p class="page-subtitle">Nexus authentication plus the effective OpenClaw operator boundary.</p>
        </div>
      </div>
      <button
        type="button"
        class="nexus-button"
        :disabled="loading || overviewQuery.isFetching.value || capabilitiesQuery.isFetching.value"
        @click="refresh"
      >
        <Loader2
          v-if="loading || overviewQuery.isFetching.value || capabilitiesQuery.isFetching.value"
          :size="15"
          class="spin"
          aria-hidden="true"
        />
        <RefreshCw v-else :size="15" aria-hidden="true" />
        Refresh
      </button>
    </header>

    <section class="gateway-security nexus-panel" aria-labelledby="gateway-security-title">
      <header class="gateway-security__head">
        <div>
          <span class="eyebrow">OPENCLAW CONTROL PLANE</span>
          <h2 id="gateway-security-title">Effective backend trust boundary</h2>
          <p>Credentials stay server-side. Browser actions pass through Nexus authentication, role checks, and typed gateway operations.</p>
        </div>
        <span
          class="nexus-status"
          :class="connection?.connected ? 'nexus-status--success' : 'nexus-status--danger'"
        >
          <CheckCircle2 v-if="connection?.connected" :size="13" aria-hidden="true" />
          <CircleAlert v-else :size="13" aria-hidden="true" />
          {{ connection?.connected ? 'Connected' : connection?.state || 'Unknown' }}
        </span>
      </header>

      <div class="trust-flow" aria-label="Browser through Nexus to OpenClaw">
        <span>Authenticated browser</span>
        <strong>→</strong>
        <span>Nexus RBAC + façade</span>
        <strong>→</strong>
        <span>OpenClaw Gateway</span>
      </div>

      <div class="gateway-facts">
        <article>
          <span>Endpoint</span>
          <code>{{ connection?.endpoint || 'Not configured' }}</code>
        </article>
        <article>
          <span>Credential</span>
          <strong>{{ connection?.credentialConfigured ? 'Configured server-side' : 'Missing' }}</strong>
        </article>
        <article>
          <span>Protocol</span>
          <strong>{{ connection?.protocolVersion ? `v${connection.protocolVersion}` : 'Not negotiated' }}</strong>
        </article>
        <article>
          <span>Gateway version</span>
          <strong>{{ connection?.gatewayVersion || 'Not reported' }}</strong>
        </article>
        <article>
          <span>Version pin</span>
          <strong>{{ connection?.versionPinned ? connection.requiredVersion : 'Not pinned' }}</strong>
        </article>
        <article>
          <span>Capabilities</span>
          <strong>{{ availableCapabilities }} / {{ totalCapabilities }} available</strong>
        </article>
      </div>

      <div class="security-split">
        <div>
          <h3>Granted operator scopes</h3>
          <div v-if="connection?.grantedScopes.length" class="scope-list">
            <code v-for="scope in connection.grantedScopes" :key="scope">{{ scope }}</code>
          </div>
          <p v-else class="security-muted">No scopes have been negotiated.</p>
        </div>
        <div>
          <h3>High-authority approvals</h3>
          <p>
            Approval resolution requires <code>operator.approvals</code> at OpenClaw and the
            <code>owner</code> role in Nexus.
          </p>
          <span
            class="nexus-status"
            :class="approvalCapability?.available ? 'nexus-status--success' : 'nexus-status--warning'"
          >
            {{ approvalCapability?.available ? 'Available' : approvalCapability?.reason || 'Unavailable' }}
          </span>
        </div>
      </div>

      <div v-if="connection?.recovery" class="gateway-recovery">
        <CircleAlert :size="17" aria-hidden="true" />
        <div>
          <strong>Recovery guidance</strong>
          <p>{{ connection.recovery }}</p>
        </div>
        <RouterLink class="nexus-button" to="/settings">Diagnostics</RouterLink>
      </div>
    </section>

    <AsyncStatePanel
      v-if="loading && !status"
      state="loading"
      title="Security-Konfiguration wird geladen"
    />
    <AsyncStatePanel
      v-else-if="error && !status"
      state="error"
      title="Nexus Security-Status nicht verfügbar"
      :problem="statusQuery.error.value"
      @action="refresh"
    />

    <section v-else-if="status" class="security-grid" aria-label="Nexus security controls">
      <article class="security-card nexus-card">
        <div class="security-card-icon"><KeyRound :size="20" aria-hidden="true" /></div>
        <h2>Authentication</h2>
        <strong class="security-value">{{ status.authMethod }}</strong>
        <p>JWT authentication with PBKDF2 password hashing and refresh-token rotation.</p>
      </article>

      <article class="security-card nexus-card">
        <div class="security-card-icon"><Timer :size="20" aria-hidden="true" /></div>
        <h2>Token configuration</h2>
        <dl>
          <div><dt>Issuer</dt><dd><code>{{ status.tokenConfig.issuer }}</code></dd></div>
          <div><dt>Audience</dt><dd><code>{{ status.tokenConfig.audience }}</code></dd></div>
          <div><dt>Access token</dt><dd>{{ status.tokenConfig.accessTokenMinutes }} min</dd></div>
          <div><dt>Refresh token</dt><dd>{{ status.tokenConfig.refreshTokenDays }} days</dd></div>
        </dl>
      </article>

      <article class="security-card nexus-card">
        <div class="security-card-icon"><Gauge :size="20" aria-hidden="true" /></div>
        <h2>Rate limiting</h2>
        <strong class="security-value">{{ status.rateLimit }}</strong>
        <p>Requests are throttled per IP and endpoint to reduce brute-force and mutation abuse.</p>
      </article>

      <article class="security-card nexus-card">
        <div class="security-card-icon"><Lock :size="20" aria-hidden="true" /></div>
        <h2>Password policy</h2>
        <strong class="security-value">{{ status.passwordPolicy }}</strong>
        <p>Applied to account creation and password changes.</p>
      </article>

      <article class="security-card nexus-card">
        <div class="security-card-icon"><Cookie :size="20" aria-hidden="true" /></div>
        <h2>Refresh cookie</h2>
        <dl>
          <div><dt>HttpOnly</dt><dd>{{ status.cookieConfig.httpOnly ? 'Yes' : 'No' }}</dd></div>
          <div><dt>Secure</dt><dd>{{ status.cookieConfig.secure ? 'Yes' : 'No' }}</dd></div>
          <div><dt>SameSite</dt><dd>{{ status.cookieConfig.sameSite }}</dd></div>
        </dl>
      </article>

      <article class="security-card nexus-card">
        <div class="security-card-icon"><Fingerprint :size="20" aria-hidden="true" /></div>
        <h2>Two-factor authentication</h2>
        <span
          class="nexus-status"
          :class="status.twoFactorEnabled ? 'nexus-status--success' : 'nexus-status--warning'"
        >
          <CheckCircle2 v-if="status.twoFactorEnabled" :size="13" aria-hidden="true" />
          <XCircle v-else :size="13" aria-hidden="true" />
          {{ status.twoFactorEnabled ? 'Enabled' : 'Not configured' }}
        </span>
        <p>Account-level second factor for privileged Nexus access.</p>
      </article>

      <article class="security-card nexus-card">
        <div class="security-card-icon"><ShieldCheck :size="20" aria-hidden="true" /></div>
        <h2>Passkey authentication</h2>
        <span
          class="nexus-status"
          :class="status.passkeyEnabled ? 'nexus-status--success' : 'nexus-status--warning'"
        >
          <CheckCircle2 v-if="status.passkeyEnabled" :size="13" aria-hidden="true" />
          <XCircle v-else :size="13" aria-hidden="true" />
          {{ status.passkeyEnabled ? 'Enabled' : 'Not configured' }}
        </span>
        <p>WebAuthn-based sign-in for phishing-resistant authentication.</p>
      </article>
    </section>
  </div>
</template>

<style scoped>
.security-page { padding-bottom: 30px; }
.gateway-security { display: grid; gap: 16px; background: linear-gradient(145deg, var(--glass), var(--grad-soft)); }
.gateway-security__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; }
.gateway-security__head h2 { margin: 3px 0 6px; font-size: 18px; }
.gateway-security__head p { max-width: 720px; margin: 0; color: var(--tx-2); line-height: 1.55; }
.gateway-security__head > .nexus-status { flex: 0 0 auto; }

.trust-flow { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 12px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--accent-wash); color: var(--tx-3); }
.trust-flow span { padding: 7px 10px; border: 1px solid var(--line-2); border-radius: 999px; background: var(--glass); color: var(--tx-2); }
.trust-flow strong { color: var(--a-mid); }

.gateway-facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.gateway-facts article { display: grid; gap: 5px; padding: 12px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--accent-wash); }
.gateway-facts span { color: var(--tx-3); font-family: var(--font-mono-v2); font-size: 11px; text-transform: uppercase; }
.gateway-facts strong, .gateway-facts code { overflow: hidden; color: var(--tx-2); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
.gateway-facts code { font-family: var(--font-mono-v2); font-size: 11px; }

.security-split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.security-split > div { padding: 14px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--accent-wash); }
.security-split h3 { margin: 0 0 9px; font-family: var(--font-display); font-size: 14px; }
.security-split p { margin: 0 0 10px; color: var(--tx-2); line-height: 1.55; }
.security-split p code { color: var(--tx); font-family: var(--font-mono-v2); font-size: 11px; }
.scope-list { display: flex; flex-wrap: wrap; gap: 6px; }
.scope-list code { padding: 5px 8px; border: 1px solid var(--line-2); border-radius: 999px; background: var(--glass); color: var(--tx-2); font-family: var(--font-mono-v2); font-size: 11px; }
.security-muted { margin: 0; color: var(--tx-3); }

.gateway-recovery { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 11px; padding: 12px; border: 1px solid var(--status-queue-line); border-radius: var(--r-sm); background: var(--status-queue-bg); color: var(--st-queue); }
.gateway-recovery strong { color: var(--tx); }
.gateway-recovery p { margin: 3px 0 0; color: var(--tx-2); line-height: 1.45; }

.security-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.security-card { display: flex; flex-direction: column; gap: 10px; padding: 18px; }
.security-card-icon { width: 40px; height: 40px; display: grid; place-items: center; border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--grad-soft); color: var(--a-mid); }
.security-card h2 { margin: 0; font-size: 15px; }
.security-card p { margin: 0; color: var(--tx-3); line-height: 1.55; }
.security-value { color: var(--tx); }
.security-card dl { display: grid; gap: 7px; margin: 0; }
.security-card dl div { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.security-card dt { color: var(--tx-3); font-size: 11px; text-transform: uppercase; }
.security-card dd { margin: 0; color: var(--tx-2); text-align: right; }
.security-card code { font-family: var(--font-mono-v2); font-size: 11px; }
.spin { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

@media (max-width: 1050px) {
  .security-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 760px) {
  .gateway-security__head { flex-direction: column; }
  .gateway-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .security-split { grid-template-columns: 1fr; }
  .trust-flow { align-items: stretch; flex-direction: column; }
  .trust-flow strong { align-self: center; transform: rotate(90deg); }
  .gateway-recovery { grid-template-columns: auto minmax(0, 1fr); }
  .gateway-recovery .nexus-button { grid-column: 1 / -1; justify-self: start; }
}

@media (max-width: 520px) {
  .security-grid, .gateway-facts { grid-template-columns: 1fr; }
}
</style>
