<script setup lang="ts">
// Full portfolio list. Strict port of CustomersScreen in partner-screens.jsx
// (lines 366-494). Table + cards view toggle, status/plan filters, search.
// Click a row → confirm enter customer modal → partnerMode.enter() + /admin.



import type { CustomerOrg, CustomerStatus, PartnerTenantDoc } from '~/types/partner'

const toast = useToast()
const router = useRouter()
const { request } = useApiFetch()
const partnerMode = usePartnerMode()

const view = ref<'table' | 'cards'>('table')
const query = ref('')
const statusFilter = ref<'all' | CustomerStatus>('all')
const planFilter = ref<'all' | 'starter' | 'business' | 'enterprise'>('all')

const wizardOpen = ref(false)
const entryCustomer = ref<CustomerOrg | null>(null)

// Real tenants attached to this partner, via the shared composable which owns
// the canonical PartnerTenantDoc and the 'partner-tenants' cache key (dashboard
// + customers reuse one fetch). Health score, industry, and brand colour now
// come from real fields on the response.
const { tenants: rawTenants, refresh: refreshTenants } = usePartnerTenants()

// Per-tenant MRR from the shared composable (same 'partner-mrr' cache key as the
// dashboard). mrrByTenant is the tenantId → breakdown-row lookup the table reads.
const { mrrByTenant, refresh: refreshMrr } = usePartnerMrr()

function mapTenantStatus(s: PartnerTenantDoc['status']): CustomerStatus {
  // Tenant.status values overlap partially with the fixture's CustomerStatus.
  // Best-effort map: deleted/suspended → suspended badge, pending → trial,
  // active stays active (rendered as 'healthy').
  if (s === 'active') return 'healthy'
  if (s === 'pending') return 'trial'
  return 'suspended'
}

// Backend plan enum (mvp/pro/enterprise) → fixture-friendly slug + label.
// Same mapping mirrored in CustomerCreateWizard.vue; keep both in sync if
// the backend enum ever changes.
const PLAN_INFO: Record<
  'mvp' | 'pro' | 'enterprise',
  { slug: CustomerOrg['plan']; label: CustomerOrg['planLabel'] }
> = {
  mvp:        { slug: 'starter',    label: 'Starter' },
  pro:        { slug: 'business',   label: 'Business' },
  enterprise: { slug: 'enterprise', label: 'Enterprise' },
}

// Type extension on the row so the table can show the currency next to
// the amount (the original fixture only had a DKK number, but real data
// can be in DKK/EUR/USD).
interface CustomerRow extends CustomerOrg {
  slug: string
  mrrCurrency: 'DKK' | 'EUR' | 'USD'
  mrrCustom: boolean
}

const customers = computed<CustomerRow[]>(() =>
  (rawTenants.value ?? []).map((t) => {
    const info = PLAN_INFO[t.plan ?? 'pro']
    const subMrr = mrrByTenant.value.get(t._id)
    return {
      id: t._id,
      slug: t.slug,
      name: t.name,
      domain: t.domains?.[0] ?? `${t.slug}.dezky.com`,
      plan: info.slug,
      planLabel: info.label,
      // Real seat utilisation: count of active User docs attached to this
      // tenant vs the contractual seat total from provisioning.
      seats: { used: t.userCount ?? 0, total: t.seats ?? 0 },
      health: t.healthScore ?? 100,
      status: mapTenantStatus(t.status),
      // MRR for this tenant, in major units. From /api/partner/mrr; 0 when
      // the sub has no priced amount (Enterprise / pre-catalog tenants).
      mrrDkk: subMrr ? Math.round(subMrr.monthlyMinor / 100) : 0,
      mrrCurrency: subMrr?.currency ?? 'DKK',
      mrrCustom: subMrr?.custom ?? false,
      brandColor: t.brandColor || '#D4FF3A',
      industry: t.industry ?? '—',
      createdOn: t.createdAt ?? '',
      since: t.createdAt ?? '',
    }
  }),
)

const filtered = computed(() => {
  return customers.value.filter((c) => {
    if (statusFilter.value !== 'all' && c.status !== statusFilter.value) return false
    if (planFilter.value !== 'all' && c.plan !== planFilter.value) return false
    if (query.value) {
      const q = query.value.toLowerCase()
      if (!(c.name + ' ' + c.domain).toLowerCase().includes(q)) return false
    }
    return true
  })
})

const statusOpts = [
  { value: 'all', label: 'All' },
  { value: 'healthy', label: 'Healthy' },
  { value: 'attention', label: 'Attention' },
  { value: 'past_due', label: 'Past due' },
  { value: 'trial', label: 'Trial' },
] as const

const planOpts = [
  { value: 'all', label: 'All' },
  { value: 'starter', label: 'Starter' },
  { value: 'business', label: 'Business' },
  { value: 'enterprise', label: 'Enterprise' },
] as const

function statusBadge(s: CustomerStatus): { tone: 'ok' | 'warn' | 'bad' | 'info' | 'neutral'; label: string } {
  switch (s) {
    case 'healthy':   return { tone: 'ok',   label: 'healthy' }
    case 'attention': return { tone: 'warn', label: 'attention' }
    case 'past_due':  return { tone: 'bad',  label: 'past-due' }
    case 'trial':     return { tone: 'info', label: 'trial' }
    case 'suspended': return { tone: 'neutral', label: 'suspended' }
  }
}

function startEnter(c: CustomerOrg) {
  entryCustomer.value = c
}

async function onProvisioned() {
  toast.ok('Customer provisioned', 'Tenant created — provisioning runs in the background')
  // Refetch so the new tenant + its subscription's MRR show up without a
  // full reload. refreshNuxtData also nudges the dashboard's cached
  // MRR card the next time the user navigates back to /partner.
  await Promise.all([
    refreshTenants(),
    refreshMrr(),
    refreshNuxtData('partner-tenants'),
    refreshNuxtData('partner-mrr'),
  ])
}

function confirmEnter(reason: string) {
  if (!entryCustomer.value) return
  const c = entryCustomer.value
  partnerMode.enter(c.id)
  entryCustomer.value = null
  toast.info(`Entered ${c.name}`, reason ? `Reason: ${reason}` : 'No reason captured')
  router.push('/admin')
}

// ── Edit / suspend a customer ─────────────────────────────────────────────
const editCustomer = ref<CustomerRow | null>(null)
const editForm = reactive({ name: '', industry: '', brandColor: '#D4FF3A', seats: 0 })
const savingEdit = ref(false)

function startEdit(c: CustomerRow) {
  editCustomer.value = c
  editForm.name = c.name
  editForm.industry = c.industry === '—' ? '' : c.industry
  editForm.brandColor = c.brandColor
  editForm.seats = c.seats.total
}

async function refreshAll() {
  await Promise.all([
    refreshTenants(),
    refreshMrr(),
    refreshNuxtData('partner-tenants'),
    refreshNuxtData('partner-mrr'),
  ])
}

async function saveEdit() {
  if (!editCustomer.value) return
  if (!editForm.name.trim()) {
    toast.bad('Name required', 'Customer name cannot be empty')
    return
  }
  savingEdit.value = true
  try {
    await request(`/api/partner/tenants/${editCustomer.value.slug}`, {
      method: 'PATCH',
      body: {
        name: editForm.name,
        industry: editForm.industry,
        brandColor: editForm.brandColor,
        seats: editForm.seats,
      },
    })
    toast.ok('Saved', `${editForm.name} updated`)
    editCustomer.value = null
    await refreshAll()
  } catch (e: unknown) {
    const err = e as { data?: { message?: string }; statusMessage?: string }
    toast.bad('Save failed', err.data?.message || err.statusMessage || 'Could not save customer')
  } finally {
    savingEdit.value = false
  }
}

async function toggleSuspend(c: CustomerRow) {
  const action = c.status === 'suspended' ? 'resume' : 'suspend'
  try {
    await request(`/api/partner/tenants/${c.slug}/${action}`, { method: 'POST' })
    toast.ok(action === 'suspend' ? 'Suspended' : 'Resumed', c.name)
    editCustomer.value = null
    await refreshAll()
  } catch (e: unknown) {
    const err = e as { data?: { message?: string }; statusMessage?: string }
    toast.bad('Action failed', err.data?.message || err.statusMessage || 'Could not update customer')
  }
}
</script>

<template>
  <div>
    <PageHeader
      eyebrow="Portfolio"
      title="Customer organizations"
      subtitle="Every customer org under your reseller agreement. Click to manage as partner."
    >
      <template #actions>
        <UiButton variant="secondary" @click="toast.ok('Exporting CSV', `${customers.length} customers`)">
          <template #leading><UiIcon name="download" :size="14" /></template>
          Export CSV
        </UiButton>
        <UiButton variant="primary" @click="wizardOpen = true">
          <template #leading><UiIcon name="plus" :size="14" /></template>
          New customer
        </UiButton>
      </template>
    </PageHeader>

    <div class="content">
      <!-- Filter bar -->
      <div class="filters">
        <div class="search">
          <UiIcon name="search" :size="14" />
          <input v-model="query" placeholder="Search customer or domain…" />
        </div>

        <div class="seg">
          <span class="seg-label">Status</span>
          <select v-model="statusFilter">
            <option v-for="o in statusOpts" :key="o.value" :value="o.value">{{ o.label }}</option>
          </select>
        </div>

        <div class="seg">
          <span class="seg-label">Plan</span>
          <select v-model="planFilter">
            <option v-for="o in planOpts" :key="o.value" :value="o.value">{{ o.label }}</option>
          </select>
        </div>

        <div class="spacer" />

        <Mono dim>{{ filtered.length }} of {{ customers.length }}</Mono>

        <div class="view-toggle">
          <button
            v-for="v in (['table','cards'] as const)"
            :key="v"
            :class="{ active: view === v }"
            @click="view = v"
          >{{ v }}</button>
        </div>
      </div>

      <!-- Table view -->
      <Card v-if="view === 'table'" :pad="0">
        <div class="table-wrap">
          <table class="dtable">
            <thead>
              <tr>
                <th class="sortable">Customer <UiIcon name="chevUpDown" :size="11" /></th>
                <th class="sortable">Plan <UiIcon name="chevUpDown" :size="11" /></th>
                <th class="sortable">Seats <UiIcon name="chevUpDown" :size="11" /></th>
                <th class="sortable num">MRR <UiIcon name="chevUpDown" :size="11" /></th>
                <th class="sortable">Status <UiIcon name="chevUpDown" :size="11" /></th>
                <th>Customer since</th>
                <th class="action-col" />
              </tr>
            </thead>
            <tbody>
              <tr v-for="c in filtered" :key="c.id" @click="startEnter(c)">
                <td>
                  <div class="cust-cell">
                    <div class="cust-swatch" :style="{ background: c.brandColor }" />
                    <div>
                      <div class="cust-name">{{ c.name }}</div>
                      <Mono dim>{{ c.domain }}</Mono>
                    </div>
                  </div>
                </td>
                <td>
                  <Badge :tone="c.plan === 'enterprise' ? 'invert' : 'neutral'">{{ c.planLabel }}</Badge>
                </td>
                <td>
                  <Mono>{{ c.seats.used }}/{{ c.seats.total }}</Mono>
                </td>
                <td class="num">
                  <span class="mrr">{{ c.mrrDkk > 0 ? c.mrrDkk.toLocaleString('da-DK') + ' ' + c.mrrCurrency : (c.mrrCustom ? 'custom' : '—') }}</span>
                </td>
                <td>
                  <Badge :tone="statusBadge(c.status).tone" dot>{{ statusBadge(c.status).label }}</Badge>
                </td>
                <td><Mono dim>{{ c.since }}</Mono></td>
                <td class="action-col" @click.stop>
                  <div class="row-actions">
                    <UiButton size="sm" variant="ghost" @click="startEdit(c)">Edit</UiButton>
                    <UiButton size="sm" variant="secondary" @click="startEnter(c)">
                      Manage
                      <template #trailing><UiIcon name="chevRight" :size="12" /></template>
                    </UiButton>
                  </div>
                </td>
              </tr>
              <tr v-if="filtered.length === 0">
                <td colspan="7" class="empty">No customers match these filters.</td>
              </tr>
            </tbody>
          </table>
        </div>
      </Card>

      <!-- Cards view -->
      <div v-else class="cards-grid">
        <button
          v-for="c in filtered"
          :key="c.id"
          class="ccard"
          @click="startEnter(c)"
        >
          <div class="ccard-stripe" :style="{ background: c.brandColor }" />
          <div class="ccard-body">
            <div class="ccard-head">
              <div class="ccard-id">
                <div class="ccard-name">{{ c.name }}</div>
                <Mono dim>{{ c.domain }}</Mono>
              </div>
              <Badge :tone="statusBadge(c.status).tone" dot>{{ statusBadge(c.status).label }}</Badge>
            </div>
            <div class="ccard-meta">
              <div>
                <Eyebrow>Plan</Eyebrow>
                <div class="cm-val">{{ c.planLabel }}</div>
              </div>
              <div>
                <Eyebrow>Seats</Eyebrow>
                <div class="cm-val mono">{{ c.seats.used }} / {{ c.seats.total }}</div>
              </div>
              <div>
                <Eyebrow>MRR</Eyebrow>
                <div class="cm-val mono">{{ c.mrrDkk > 0 ? c.mrrDkk.toLocaleString('da-DK') + ' ' + c.mrrCurrency : (c.mrrCustom ? 'custom' : '—') }}</div>
              </div>
              <div>
                <Eyebrow>Since</Eyebrow>
                <div class="cm-val">{{ c.since }}</div>
              </div>
            </div>
          </div>
        </button>
      </div>
    </div>

    <PartnerCustomerCreateWizard
      :open="wizardOpen"
      @close="wizardOpen = false"
      @done="onProvisioned"
    />
    <PartnerEnterCustomerConfirmModal
      :customer="entryCustomer"
      @close="entryCustomer = null"
      @confirm="confirmEnter"
    />

    <Modal
      :open="!!editCustomer"
      eyebrow="Customer"
      :title="`Edit ${editCustomer?.name ?? ''}`"
      size="md"
      @close="editCustomer = null"
    >
      <div class="edit-form">
        <label class="field"><Eyebrow>Name</Eyebrow><input v-model="editForm.name" /></label>
        <label class="field"><Eyebrow>Industry</Eyebrow><input v-model="editForm.industry" placeholder="e.g. Logistics" /></label>
        <div class="row-2">
          <label class="field"><Eyebrow>Brand color</Eyebrow><input v-model="editForm.brandColor" placeholder="#3F6BFF" /></label>
          <label class="field"><Eyebrow>Seats</Eyebrow><input v-model.number="editForm.seats" type="number" min="0" /></label>
        </div>
      </div>
      <template #footer>
        <UiButton
          v-if="editCustomer"
          :variant="editCustomer.status === 'suspended' ? 'secondary' : 'danger'"
          @click="toggleSuspend(editCustomer)"
        >{{ editCustomer.status === 'suspended' ? 'Resume customer' : 'Suspend customer' }}</UiButton>
        <div style="flex: 1" />
        <UiButton variant="ghost" @click="editCustomer = null">Cancel</UiButton>
        <UiButton variant="primary" :disabled="savingEdit" @click="saveEdit">{{ savingEdit ? 'Saving…' : 'Save changes' }}</UiButton>
      </template>
    </Modal>
  </div>
</template>

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

.filters {
  display: flex;
  align-items: center;
  gap: 12px;
  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; }

.view-toggle {
  display: flex;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 2px;
  background: var(--surface);
}
.view-toggle button {
  padding: 6px 12px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--text-mute);
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
}
.view-toggle button.active { background: var(--text); color: var(--bg); }

/* Table */
.table-wrap { overflow-x: auto; }
.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.sortable :deep(svg) { opacity: 0.5; margin-left: 4px; vertical-align: middle; }
.dtable th.num, .dtable td.num { text-align: right; }
.dtable th.action-col, .dtable td.action-col { width: 170px; text-align: right; }
.row-actions { display: flex; gap: 6px; justify-content: flex-end; align-items: center; }

.edit-form { display: flex; flex-direction: column; gap: 14px; }
.edit-form .field { display: flex; flex-direction: column; gap: 6px; }
.edit-form .row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.edit-form input {
  padding: 9px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: inherit;
  font-size: 13px;
  color: var(--text);
}
.edit-form input:focus { outline: none; border-color: var(--border-hi); }

.dtable td {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  color: var(--text);
  vertical-align: middle;
}
.dtable tbody tr { cursor: pointer; transition: background 80ms; }
.dtable tbody tr:hover { background: var(--row-hover); }

.cust-cell { display: flex; align-items: center; gap: 12px; }
.cust-swatch { width: 28px; height: 28px; border-radius: 6px; flex-shrink: 0; }
.cust-name { font-size: 13px; font-weight: 500; }

.mrr {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
}

.empty {
  text-align: center;
  color: var(--text-mute);
  font-size: 13px;
  padding: 48px 0;
}

/* Cards */
.cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
}

.ccard {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
  padding: 0;
  transition: border-color 120ms;
  display: flex;
  flex-direction: column;
}
.ccard:hover { border-color: var(--text); }
.ccard-stripe { height: 6px; }
.ccard-body { padding: 16px; }
.ccard-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
}
.ccard-id { min-width: 0; }
.ccard-name {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.015em;
}
.ccard-meta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.cm-val {
  font-size: 13px;
  font-weight: 500;
  margin-top: 4px;
}
.cm-val.mono { font-family: var(--font-mono); }
</style>
