<script setup lang="ts">
// Partner audit log. Strict port of PartnerAuditScreen
// (platform-partner-depth.jsx lines 1042-1098). Filter bar (search + Actor /
// Customer / Action / Last) + cross-customer audit log table + footer note.
// Click a row to open a detail SidePanel with before/after diff and origin.



const toast = useToast()

// AuditRow shape the template + side panel render against. Built from the
// real /api/partner/activity feed (see `rows` below).
interface AuditRow {
  id: string
  when: string                 // formatted timestamp for the table
  whenIso: string              // raw ISO for period filtering
  actor: string                // actor email
  customer: string             // tenant name resolved from tenantSlug, or '—'
  customerColor: string        // tile colour for the cust swatch
  action: string               // dotted verb e.g. 'partner.user_invited'
  target: string               // resourceName from the audit event
  tone: 'info' | 'warn' | 'ok' | 'bad'
}

interface PartnerTenant { _id: string; slug: string; name: string }
interface ActivityEvent {
  _id: string
  at: string
  action: string
  resourceName?: string
  tenantSlug?: string
  outcome?: 'success' | 'failure' | 'pending'
  actor?: { email?: string; userId?: string }
}

// Pull the partner's tenants (for slug→name + colour lookup) and recent
// audit events. Limit 200 — generous compared to the dashboard's 8 — so
// filters meaningfully shrink the visible set client-side. Pagination via
// `?before` lands when 200 is regularly hit.
const { data: tenants } = await useFetch<PartnerTenant[]>('/api/partner/tenants', {
  key: 'partner-tenants',
  default: () => [],
})
const { data: events } = await useFetch<ActivityEvent[]>('/api/partner/activity', {
  key: 'partner-activity-full',
  query: { limit: 200 },
  default: () => [],
})

function tenantNameFromSlug(slug?: string): string {
  if (!slug) return '—'
  return tenants.value?.find((t) => t.slug === slug)?.name ?? slug
}

// Deterministic colour per tenant slug so the swatch stays stable across
// reloads even though we don't store brand colours on Tenant yet.
const PALETTE = ['#D4FF3A', '#4D8BE8', '#34C77B', '#F0B14A', '#F05858', '#A78BFA']
function tenantColor(slug?: string): string {
  if (!slug) return 'var(--text-mute)'
  let h = 0
  for (let i = 0; i < slug.length; i++) h = (h * 31 + slug.charCodeAt(i)) | 0
  return PALETTE[Math.abs(h) % PALETTE.length]
}

function eventTone(e: ActivityEvent): AuditRow['tone'] {
  if (e.outcome === 'failure') return 'bad'
  if (e.outcome === 'pending') return 'warn'
  if (/\.(deleted|suspended|terminated|removed)$/.test(e.action)) return 'bad'
  return 'info'
}

function fmtTime(iso: string): string {
  // Always full date + time. The "today shows time only" shortcut made it
  // unclear whether a bare "08.35" was this morning or yesterday morning;
  // for an audit log, consistency beats brevity.
  return new Date(iso).toLocaleString('da-DK', { dateStyle: 'short', timeStyle: 'short' })
}

const rows = computed<AuditRow[]>(() =>
  (events.value ?? []).map((e) => ({
    id: e._id,
    when: fmtTime(e.at),
    whenIso: e.at,
    actor: e.actor?.email ?? 'system',
    customer: tenantNameFromSlug(e.tenantSlug),
    customerColor: tenantColor(e.tenantSlug),
    action: e.action,
    target: e.resourceName ?? '—',
    tone: eventTone(e),
  })),
)

const query = ref('')
const actorFilter = ref<string>('all')
const customerFilter = ref<string>('all')
const actionFilter = ref<string>('all')
const periodFilter = ref<'24h' | '7d' | '30d'>('7d')

const actors = computed(() => Array.from(new Set(rows.value.map((r) => r.actor))))
const actions = computed(() => Array.from(new Set(rows.value.map((r) => r.action))).sort())
// Distinct customer list for the dropdown — replaces the fixture customers
// array. '—' (partner-scoped events) shows up as a special "Partner-level"
// option so filtering to those is easy.
const customerOptions = computed(() => {
  const names = new Set<string>()
  for (const r of rows.value) names.add(r.customer)
  return Array.from(names).sort()
})

const PERIOD_MS: Record<typeof periodFilter.value, number> = {
  '24h': 24 * 60 * 60 * 1000,
  '7d': 7 * 24 * 60 * 60 * 1000,
  '30d': 30 * 24 * 60 * 60 * 1000,
}

const filtered = computed(() => {
  const cutoff = Date.now() - PERIOD_MS[periodFilter.value]
  return rows.value.filter((r) => {
    if (new Date(r.whenIso).getTime() < cutoff) return false
    if (actorFilter.value !== 'all' && r.actor !== actorFilter.value) return false
    if (actionFilter.value !== 'all' && r.action !== actionFilter.value) return false
    if (customerFilter.value !== 'all' && r.customer !== customerFilter.value) return false
    if (query.value) {
      const q = query.value.toLowerCase()
      if (!(r.actor + ' ' + r.customer + ' ' + r.action + ' ' + r.target).toLowerCase().includes(q)) return false
    }
    return true
  })
})

function customerColor(name: string) {
  if (name === '—') return 'var(--text-mute)'
  // Look up tenant by name to find the slug, then derive colour.
  const t = tenants.value?.find((x) => x.name === name)
  return tenantColor(t?.slug)
}

const detail = ref<AuditRow | null>(null)
</script>

<template>
  <div>
    <PageHeader
      eyebrow="Compliance"
      title="Partner audit log"
      subtitle="Every action your team has taken across your customer portfolio. Customer admins see this in their own audit log too."
    />

    <div class="content">
      <div class="filters">
        <div class="search">
          <UiIcon name="search" :size="14" />
          <input v-model="query" placeholder="actor, customer, action…" />
        </div>

        <div class="seg">
          <span class="seg-label">Actor</span>
          <select v-model="actorFilter">
            <option value="all">Anyone</option>
            <option v-for="a in actors" :key="a" :value="a">{{ a }}</option>
          </select>
        </div>

        <div class="seg">
          <span class="seg-label">Customer</span>
          <select v-model="customerFilter">
            <option value="all">All customers</option>
            <option v-for="name in customerOptions" :key="name" :value="name">{{ name }}</option>
          </select>
        </div>

        <div class="seg">
          <span class="seg-label">Action</span>
          <select v-model="actionFilter">
            <option value="all">All actions</option>
            <option v-for="a in actions" :key="a" :value="a">{{ a }}</option>
          </select>
        </div>

        <div class="seg">
          <span class="seg-label">Last</span>
          <select v-model="periodFilter">
            <option value="24h">24 hours</option>
            <option value="7d">7 days</option>
            <option value="30d">30 days</option>
          </select>
        </div>

        <div class="spacer" />
        <UiButton variant="secondary" @click="toast.ok('Exporting CSV', `${filtered.length} entries`)">
          <template #leading><UiIcon name="download" :size="14" /></template>
          Export CSV
        </UiButton>
      </div>

      <Card :pad="0">
        <table class="dtable">
          <thead>
            <tr>
              <th>Time</th>
              <th>Actor</th>
              <th>Customer</th>
              <th>Action</th>
              <th>Target</th>
              <th class="tone-col" />
            </tr>
          </thead>
          <tbody>
            <tr v-for="r in filtered" :key="r.id" @click="detail = r">
              <td><Mono>{{ r.when }}</Mono></td>
              <td>
                <div class="actor-cell">
                  <Avatar :name="r.actor" :size="22" />
                  <div>
                    <div class="actor-name">{{ r.actor }}</div>
                    <Mono dim>partner</Mono>
                  </div>
                </div>
              </td>
              <td>
                <Mono v-if="r.customer === '—'" dim>—</Mono>
                <div v-else class="cust-cell">
                  <div class="cust-swatch" :style="{ background: customerColor(r.customer) }" />
                  <span>{{ r.customer }}</span>
                </div>
              </td>
              <td><Mono class="action-text">{{ r.action }}</Mono></td>
              <td><span class="target-text">{{ r.target }}</span></td>
              <td class="tone-col">
                <Badge :tone="r.tone" dot>{{ r.tone === 'bad' ? 'fail' : r.tone }}</Badge>
              </td>
            </tr>
          </tbody>
        </table>
      </Card>

      <Mono dim class="footer-note">// retention 365 days · write-once · visible to customer admins on their own audit log</Mono>
    </div>

    <!-- Detail side panel -->
    <SidePanel
      :open="!!detail"
      width="md"
      eyebrow="Audit event"
      :title="detail?.action || ''"
      @close="detail = null"
    >
      <template v-if="detail">
        <div class="detail-head">
          <Mono dim>{{ detail.when }}</Mono>
          <Badge :tone="detail.tone" dot>{{ detail.tone === 'bad' ? 'fail' : detail.tone }}</Badge>
        </div>

        <div class="detail-section">
          <Eyebrow>Actor</Eyebrow>
          <div class="actor-row">
            <Avatar :name="detail.actor" :size="32" />
            <div>
              <div class="dn">{{ detail.actor }}</div>
              <Mono dim>partner staff</Mono>
            </div>
          </div>
        </div>

        <div class="detail-section">
          <Eyebrow>Target</Eyebrow>
          <div class="target-row">
            <div v-if="detail.customer !== '—'" class="cust-cell">
              <div class="cust-swatch" :style="{ background: customerColor(detail.customer) }" />
              <span>{{ detail.customer }}</span>
            </div>
            <Mono>{{ detail.target }}</Mono>
          </div>
        </div>

        <div class="detail-section">
          <Eyebrow>Event ID</Eyebrow>
          <div class="eid"><Mono>{{ detail.id }}</Mono></div>
        </div>
      </template>

      <template #footer>
        <div class="audit-footer">
          <UiIcon name="shield" :size="12" />
          <Mono dim>tamper-evident · retention 365 days</Mono>
        </div>
      </template>
    </SidePanel>
  </div>
</template>

<style scoped>
.content { padding: 20px 40px 64px; display: flex; flex-direction: column; gap: 12px; }

.filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  width: 320px;
  color: var(--text-mute);
}
.search input {
  flex: 1;
  border: none;
  background: transparent;
  font-family: inherit;
  font-size: 13px;
  padding: 9px 0;
  color: var(--text);
}
.search input:focus { outline: none; }

.seg {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.seg-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.seg select {
  border: none;
  background: transparent;
  font-family: inherit;
  font-size: 13px;
  color: var(--text);
  padding: 8px 4px;
  cursor: pointer;
}
.seg select:focus { outline: none; }
.spacer { flex: 1; }

.dtable { width: 100%; border-collapse: collapse; }
.dtable th {
  text-align: left;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-mute);
  font-weight: 500;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}
.dtable th.tone-col, .dtable td.tone-col { width: 80px; text-align: right; }
.dtable td {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  vertical-align: middle;
}
.dtable tbody tr { cursor: pointer; transition: background 80ms; }
.dtable tbody tr:hover { background: var(--row-hover); }

.actor-cell { display: flex; align-items: center; gap: 8px; }
.actor-name { font-size: 12px; font-weight: 500; }

.cust-cell { display: flex; align-items: center; gap: 6px; }
.cust-swatch { width: 12px; height: 12px; border-radius: 2px; flex-shrink: 0; }

.action-text { font-weight: 500; }
.target-text { font-size: 12px; color: var(--text-dim); }

.footer-note { display: block; margin-top: 4px; }

/* Side panel detail */
.detail-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: 14px;
  margin-bottom: 18px;
  border-bottom: 1px solid var(--border);
}
.detail-section { margin-bottom: 20px; }
.detail-section + .detail-section { padding-top: 20px; border-top: 1px solid var(--border); }

.actor-row { display: flex; align-items: center; gap: 12px; margin-top: 8px; }
.dn { font-size: 14px; font-weight: 500; }

.target-row { display: flex; align-items: center; gap: 10px; margin-top: 8px; font-size: 13px; }

.eid { margin-top: 8px; }

.audit-footer {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  width: 100%;
}
.audit-footer :deep(svg) { color: var(--text-mute); }
</style>
