<template>
  <div>
    <div class="page-header">
      <h2>API Tokens</h2>
      <button class="btn btn-primary" @click="openCreate()">+ New Token</button>
    </div>

    <div class="card">
      <p class="tokens-intro">
        Personal access tokens let scripts and integrations authenticate as you
        without an hourly-expiring login session. Send the token as
        <code>Authorization: Bearer shopdb_pat_...</code>. Ideal for long-running
        imports that would otherwise die when the login JWT expires. A token may
        be restricted to a subset of your permissions; a restricted token cannot
        reach admin-only (role-gated) endpoints or import mode.
      </p>

      <div v-if="loading" class="loading">Loading...</div>

      <template v-else>
        <div class="table-container">
          <table>
            <thead>
              <tr>
                <th>Name</th>
                <th>Token</th>
                <th>Access</th>
                <th>Created</th>
                <th>Expires</th>
                <th>Last Used</th>
                <th>Status</th>
                <th>Actions</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="token in myTokens" :key="token.tokenid">
                <td>{{ token.name }}</td>
                <td><code :title="token.displayprefix + '...'">{{ token.tokenprefix }}...</code></td>
                <td><span class="badge" :class="scopeBadgeClass(token)">{{ scopeSummary(token) }}</span></td>
                <td>{{ formatDate(token.createddate) }}</td>
                <td>{{ token.expiresat ? formatDate(token.expiresat) : 'Never' }}</td>
                <td>{{ token.lastusedat ? formatDate(token.lastusedat) : 'Never' }}</td>
                <td>
                  <span v-if="!token.isactive" class="badge badge-danger">Revoked</span>
                  <span v-else-if="token.isexpired" class="badge badge-warning">Expired</span>
                  <span v-else class="badge badge-success">Active</span>
                </td>
                <td class="actions">
                  <button v-if="token.isactive" class="btn btn-secondary btn-sm"
                          @click="openEdit(token)">Edit</button>
                  <button v-if="token.isactive" class="btn btn-danger btn-sm"
                          @click="confirmRevoke(token)">Revoke</button>
                </td>
              </tr>
              <tr v-if="myTokens.length === 0">
                <td colspan="8" style="text-align: center; color: var(--text-light);">
                  No tokens yet
                </td>
              </tr>
            </tbody>
          </table>
        </div>
      </template>
    </div>

    <!-- Admin: all tokens across every user -->
    <div v-if="isAdmin" class="card admin-tokens">
      <h3 class="section-subtitle">All Tokens (admin)</h3>
      <div class="table-container">
        <table>
          <thead>
            <tr>
              <th>Owner</th>
              <th>Name</th>
              <th>Token</th>
              <th>Access</th>
              <th>Expires</th>
              <th>Last Used</th>
              <th>Status</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="token in allTokens" :key="token.tokenid">
              <td>{{ token.username || '-' }}</td>
              <td>{{ token.name }}</td>
              <td><code :title="token.displayprefix + '...'">{{ token.tokenprefix }}...</code></td>
              <td><span class="badge" :class="scopeBadgeClass(token)">{{ scopeSummary(token) }}</span></td>
              <td>{{ token.expiresat ? formatDate(token.expiresat) : 'Never' }}</td>
              <td>{{ token.lastusedat ? formatDate(token.lastusedat) : 'Never' }}</td>
              <td>
                <span v-if="!token.isactive" class="badge badge-danger">Revoked</span>
                <span v-else-if="token.isexpired" class="badge badge-warning">Expired</span>
                <span v-else class="badge badge-success">Active</span>
              </td>
              <td class="actions">
                <button v-if="token.isactive" class="btn btn-danger btn-sm"
                        @click="confirmRevoke(token)">Revoke</button>
              </td>
            </tr>
            <tr v-if="allTokens.length === 0">
              <td colspan="8" style="text-align: center; color: var(--text-light);">
                No tokens
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>

    <!-- Create modal -->
    <div v-if="showCreate" class="modal-overlay">
      <div class="modal modal-lg">
        <div class="modal-header"><h3>New API Token</h3></div>
        <form @submit.prevent="createToken">
          <div class="modal-body">
            <div class="form-group">
              <label for="tokenname">Name *</label>
              <input id="tokenname" v-model="form.name" type="text" class="form-control"
                     placeholder="e.g. legacy import runner" required />
            </div>
            <div class="form-group">
              <label for="tokenexpiry">Expiry (optional)</label>
              <input id="tokenexpiry" v-model="form.expiresat" type="date" class="form-control" />
              <small class="form-hint">Leave blank for a token that never expires.</small>
            </div>

            <div class="form-group">
              <label class="checkbox-label">
                <input type="checkbox" v-model="form.restrict" />
                Restrict permissions
              </label>
              <small class="form-hint">
                Default is full access (the token acts as you). Restrict to grant
                only the checked permissions. A restricted token cannot use
                admin-only endpoints or import mode.
              </small>
            </div>

            <div v-if="form.restrict" class="form-group">
              <label>Allowed permissions</label>
              <div class="permissions-grid">
                <div v-for="(perms, category) in availableGrouped" :key="category"
                     class="permission-category">
                  <div class="category-header">
                    <label class="checkbox-label">
                      <input type="checkbox"
                             :checked="isCategoryFullySelected(category)"
                             :indeterminate.prop="isCategoryPartiallySelected(category)"
                             @change="toggleCategory(category, $event.target.checked)" />
                      <strong>{{ formatCategory(category) }}</strong>
                    </label>
                  </div>
                  <div class="category-perms">
                    <label v-for="p in perms" :key="p.name" class="checkbox-label perm-item">
                      <input type="checkbox" :value="p.name" v-model="form.scopes" />
                      {{ p.description }}
                    </label>
                  </div>
                </div>
              </div>
            </div>

            <div v-if="error" class="error-message">{{ error }}</div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" @click="closeCreate">Cancel</button>
            <button type="submit" class="btn btn-primary" :disabled="saving">
              {{ saving ? 'Creating...' : 'Create' }}
            </button>
          </div>
        </form>
      </div>
    </div>

    <!-- Edit modal (scopes) -->
    <div v-if="editing" class="modal-overlay">
      <div class="modal modal-lg">
        <div class="modal-header"><h3>Edit token access</h3></div>
        <form @submit.prevent="saveEdit">
          <div class="modal-body">
            <p class="tokens-intro">Editing <strong>{{ editing.name }}</strong>.</p>
            <div class="form-group">
              <label class="checkbox-label">
                <input type="checkbox" v-model="editForm.restrict" />
                Restrict permissions
              </label>
              <small class="form-hint">
                Uncheck for full access (acts as the owner).
              </small>
            </div>
            <div v-if="editForm.restrict" class="form-group">
              <label>Allowed permissions</label>
              <div class="permissions-grid">
                <div v-for="(perms, category) in availableGrouped" :key="category"
                     class="permission-category">
                  <div class="category-header">
                    <label class="checkbox-label">
                      <input type="checkbox"
                             :checked="isEditCategoryFullySelected(category)"
                             :indeterminate.prop="isEditCategoryPartiallySelected(category)"
                             @change="toggleEditCategory(category, $event.target.checked)" />
                      <strong>{{ formatCategory(category) }}</strong>
                    </label>
                  </div>
                  <div class="category-perms">
                    <label v-for="p in perms" :key="p.name" class="checkbox-label perm-item">
                      <input type="checkbox" :value="p.name" v-model="editForm.scopes" />
                      {{ p.description }}
                    </label>
                  </div>
                </div>
              </div>
            </div>
            <div v-if="editError" class="error-message">{{ editError }}</div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" @click="closeEdit">Cancel</button>
            <button type="submit" class="btn btn-primary" :disabled="saving">
              {{ saving ? 'Saving...' : 'Save' }}
            </button>
          </div>
        </form>
      </div>
    </div>

    <!-- Secret reveal modal (shown once) -->
    <div v-if="newSecret" class="modal-overlay" @click.self="dismissSecret">
      <div class="modal">
        <div class="modal-header"><h3>Copy your new token</h3></div>
        <div class="modal-body">
          <p class="secret-warning">
            This is the only time the token is shown. Copy it now and store it
            somewhere safe. You will not be able to see it again.
          </p>
          <div class="secret-box">
            <code class="secret-value">{{ newSecret }}</code>
            <button class="btn btn-secondary btn-sm" @click="copySecret">
              {{ copied ? 'Copied' : 'Copy' }}
            </button>
          </div>
        </div>
        <div class="modal-footer">
          <button class="btn btn-primary" @click="dismissSecret">Done</button>
        </div>
      </div>
    </div>

    <!-- Revoke confirm -->
    <div v-if="toRevoke" class="modal-overlay" @click.self="toRevoke = null">
      <div class="modal">
        <div class="modal-header"><h3>Revoke Token</h3></div>
        <div class="modal-body">
          <p>Revoke <strong>{{ toRevoke.name }}</strong>? Any script using it will
            immediately lose access.</p>
        </div>
        <div class="modal-footer">
          <button class="btn btn-secondary" @click="toRevoke = null">Cancel</button>
          <button class="btn btn-danger" @click="revokeToken">Revoke</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, computed } from 'vue'
import { apitokensApi, usersApi, authApi } from '../../api'
import { useAuthStore } from '../../stores/auth'
import { useToast } from '../../composables/toast'
import { apiError } from '../../utils/apiError'

const auth = useAuthStore()
const toast = useToast()

const isAdmin = computed(() => auth.isAdmin)

const myTokens = ref([])
const allTokens = ref([])
const loading = ref(true)

// Permission catalog grouped by category, plus the permissions the current
// user actually holds (the create/edit grid never offers more than these).
const permissionsGrouped = ref({})
const myPermissions = ref([])

const showCreate = ref(false)
const saving = ref(false)
const error = ref('')
const form = ref({ name: '', expiresat: '', restrict: false, scopes: [] })

const editing = ref(null)
const editError = ref('')
const editForm = ref({ restrict: false, scopes: [] })

const newSecret = ref('')
const copied = ref(false)
const toRevoke = ref(null)

// Grid limited to permissions the current user holds. Admins see everything.
const availableGrouped = computed(() => {
  const held = new Set(myPermissions.value)
  const result = {}
  for (const [category, perms] of Object.entries(permissionsGrouped.value)) {
    const usable = isAdmin.value ? perms : perms.filter(p => held.has(p.name))
    if (usable.length) result[category] = usable
  }
  return result
})

onMounted(() => loadData())

async function loadData() {
  loading.value = true
  try {
    const [tokensRes, permsRes, meRes] = await Promise.all([
      apitokensApi.list(),
      usersApi.permissions.list(),
      authApi.me()
    ])
    myTokens.value = tokensRes.data.data || []
    permissionsGrouped.value = permsRes.data.data.grouped || {}
    myPermissions.value = meRes.data.data.permissions || []
    if (isAdmin.value) {
      const all = await apitokensApi.list({ all: true })
      allTokens.value = all.data.data || []
    }
  } catch (err) {
    console.error('Error loading API tokens:', err)
  } finally {
    loading.value = false
  }
}

function formatDate(value) {
  if (!value) return '-'
  return new Date(value).toLocaleDateString()
}

function formatCategory(category) {
  return category.charAt(0).toUpperCase() + category.slice(1)
}

function scopeSummary(token) {
  if (!token.scopes) return 'Full access'
  const count = token.scopes.length
  return count === 1 ? '1 permission' : `${count} permissions`
}

function scopeBadgeClass(token) {
  return token.scopes ? 'badge-warning' : 'badge-success'
}

// --- Create grid helpers ---
function isCategoryFullySelected(category) {
  const perms = availableGrouped.value[category] || []
  return perms.length > 0 && perms.every(p => form.value.scopes.includes(p.name))
}
function isCategoryPartiallySelected(category) {
  const perms = availableGrouped.value[category] || []
  const selected = perms.filter(p => form.value.scopes.includes(p.name))
  return selected.length > 0 && selected.length < perms.length
}
function toggleCategory(category, checked) {
  const names = (availableGrouped.value[category] || []).map(p => p.name)
  if (checked) {
    for (const name of names) {
      if (!form.value.scopes.includes(name)) form.value.scopes.push(name)
    }
  } else {
    form.value.scopes = form.value.scopes.filter(n => !names.includes(n))
  }
}

// --- Edit grid helpers ---
function isEditCategoryFullySelected(category) {
  const perms = availableGrouped.value[category] || []
  return perms.length > 0 && perms.every(p => editForm.value.scopes.includes(p.name))
}
function isEditCategoryPartiallySelected(category) {
  const perms = availableGrouped.value[category] || []
  const selected = perms.filter(p => editForm.value.scopes.includes(p.name))
  return selected.length > 0 && selected.length < perms.length
}
function toggleEditCategory(category, checked) {
  const names = (availableGrouped.value[category] || []).map(p => p.name)
  if (checked) {
    for (const name of names) {
      if (!editForm.value.scopes.includes(name)) editForm.value.scopes.push(name)
    }
  } else {
    editForm.value.scopes = editForm.value.scopes.filter(n => !names.includes(n))
  }
}

function openCreate() {
  form.value = { name: '', expiresat: '', restrict: false, scopes: [] }
  error.value = ''
  showCreate.value = true
}

function closeCreate() { showCreate.value = false }

async function createToken() {
  error.value = ''
  if (form.value.restrict && form.value.scopes.length === 0) {
    error.value = 'Select at least one permission, or turn off Restrict permissions.'
    return
  }
  saving.value = true
  try {
    const payload = { name: form.value.name }
    if (form.value.expiresat) payload.expiresat = form.value.expiresat
    if (form.value.restrict) payload.scopes = form.value.scopes
    const response = await apitokensApi.create(payload)
    showCreate.value = false
    newSecret.value = response.data.data.secret
    copied.value = false
    loadData()
  } catch (err) {
    error.value = apiError(err, 'Failed to create token')
  } finally {
    saving.value = false
  }
}

function openEdit(token) {
  editing.value = token
  editError.value = ''
  editForm.value = {
    restrict: !!token.scopes,
    scopes: token.scopes ? [...token.scopes] : []
  }
}

function closeEdit() { editing.value = null }

async function saveEdit() {
  editError.value = ''
  if (editForm.value.restrict && editForm.value.scopes.length === 0) {
    editError.value = 'Select at least one permission, or turn off Restrict permissions.'
    return
  }
  saving.value = true
  try {
    const payload = { scopes: editForm.value.restrict ? editForm.value.scopes : null }
    await apitokensApi.update(editing.value.tokenid, payload)
    editing.value = null
    loadData()
  } catch (err) {
    editError.value = apiError(err, 'Failed to update token')
  } finally {
    saving.value = false
  }
}

async function copySecret() {
  try {
    await navigator.clipboard.writeText(newSecret.value)
    copied.value = true
  } catch {
    toast.error('Copy failed. Select the token and copy manually.')
  }
}

function dismissSecret() { newSecret.value = ''; copied.value = false }

function confirmRevoke(token) { toRevoke.value = token }

async function revokeToken() {
  try {
    await apitokensApi.remove(toRevoke.value.tokenid)
    toRevoke.value = null
    loadData()
  } catch (err) {
    toast.error('Failed to revoke token')
  }
}
</script>

<style scoped>
.tokens-intro {
  color: var(--text-light);
  margin-bottom: 1rem;
}
.tokens-intro code {
  background: var(--bg);
  padding: 0.1rem 0.3rem;
  border-radius: 3px;
}
.admin-tokens {
  margin-top: 1.5rem;
}
.section-subtitle {
  margin-bottom: 1rem;
}
.form-hint {
  display: block;
  color: var(--text-light);
  margin-top: 0.25rem;
}
.secret-warning {
  color: var(--danger);
  margin-bottom: 1rem;
}
.secret-box {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.5rem;
}
.secret-value {
  flex: 1;
  word-break: break-all;
  font-size: 0.95rem;
}
.permissions-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
  max-height: 300px;
  overflow-y: auto;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg);
}
.permission-category {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.5rem;
}
.category-header {
  border-bottom: 1px solid var(--border);
  padding-bottom: 0.5rem;
  margin-bottom: 0.5rem;
}
.category-perms {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.perm-item {
  font-size: 0.85rem;
  padding: 0.25rem 0;
}
</style>
