<template>
  <div class="full-table">
    <h2 class="section-title">Full Table Injection</h2>
    <p class="section-desc">
      Inject a realistic IPv4 routing table into ExaBGP for stress testing.
      Routes are generated with varied AS paths, prefix lengths, and communities matching real DFZ distribution.
    </p>

    <div class="config-card">
      <!-- Level selector -->
      <div class="form-group">
        <label>Table Size</label>
        <div class="level-grid">
          <button
            v-for="level in levels"
            :key="level.count"
            class="level-btn"
            :class="{ selected: selectedCount === level.count }"
            :disabled="injecting"
            @click="selectedCount = level.count"
          >
            <span class="level-count">{{ level.label }}</span>
            <span class="level-desc">{{ level.desc }}</span>
          </button>
        </div>
      </div>

      <!-- Custom count -->
      <div class="form-group">
        <label>Custom Count</label>
        <input
          v-model.number="selectedCount"
          type="number"
          min="100"
          max="950000"
          step="1000"
          :disabled="injecting"
          class="mono-input"
        />
      </div>

      <!-- Action buttons -->
      <div class="action-row">
        <button v-if="!injecting" class="btn-start" @click="startInjection" :disabled="!selectedCount">
          <span>&#9654;</span> Inject {{ formatNum(selectedCount) }} Routes
        </button>
        <button v-else class="btn-stop" @click="stopInjection">
          <span>&#9632;</span> Stop Injection
        </button>
        <button
          v-if="!injecting && lastCompleted"
          class="btn-withdraw"
          @click="withdrawAll"
          :disabled="withdrawing"
        >
          {{ withdrawing ? 'Withdrawing...' : 'Withdraw All' }}
        </button>
      </div>
    </div>

    <!-- Status display -->
    <div v-if="injecting || statusMsg" class="status-card">
      <div class="status-header">
        <span class="status-dot" :class="injecting ? 'dot-active' : 'dot-idle'"></span>
        <span class="status-text">{{ statusMsg || 'Idle' }}</span>
      </div>

      <!-- Progress bar -->
      <div v-if="state.total > 0" class="progress-section">
        <div class="progress-labels">
          <span>{{ formatNum(state.injected) }} / {{ formatNum(state.total) }}</span>
          <span>{{ state.progress_pct || 0 }}%</span>
        </div>
        <div class="progress-track">
          <div class="progress-fill" :style="{ width: (state.progress_pct || 0) + '%' }"></div>
        </div>
      </div>

      <!-- Stats row -->
      <div v-if="state.total > 0" class="stats-row">
        <div class="stat-item">
          <span class="stat-label">Rate</span>
          <span class="stat-val">{{ formatNum(state.rate_pps || 0) }}/s</span>
        </div>
        <div class="stat-item">
          <span class="stat-label">Elapsed</span>
          <span class="stat-val">{{ state.elapsed_sec || 0 }}s</span>
        </div>
        <div class="stat-item">
          <span class="stat-label">Active Routes</span>
          <span class="stat-val">{{ formatNum(state.active_routes || 0) }}</span>
        </div>
      </div>

      <!-- Error -->
      <div v-if="state.error" class="inject-error">{{ state.error }}</div>
    </div>
  </div>
</template>

<script setup>
import { ref, onUnmounted } from 'vue'
import { api } from '../api.js'

const emit = defineEmits(['routes-changed'])

const levels = [
  { count: 1000,   label: '1K',   desc: 'Quick test' },
  { count: 10000,  label: '10K',  desc: 'Light load' },
  { count: 50000,  label: '50K',  desc: 'Medium load' },
  { count: 100000, label: '100K', desc: 'Stress test' },
  { count: 500000, label: '500K', desc: 'Heavy load' },
  { count: 900000, label: '900K', desc: 'Full DFZ' },
]

const selectedCount = ref(10000)
const injecting = ref(false)
const statusMsg = ref('')
const lastCompleted = ref(false)
const withdrawing = ref(false)
const state = ref({})

let pollTimer = null

function formatNum(n) {
  if (n == null) return '0'
  return Number(n).toLocaleString()
}

async function startInjection() {
  try {
    statusMsg.value = 'Starting injection...'
    injecting.value = true
    lastCompleted.value = false
    state.value = {}
    await api.fullTableStart(selectedCount.value, 1000)
    startPolling()
  } catch (e) {
    statusMsg.value = `Start failed: ${e.message}`
    injecting.value = false
  }
}

async function stopInjection() {
  try {
    await api.fullTableStop()
    statusMsg.value = 'Stop requested...'
  } catch (e) {
    statusMsg.value = `Stop failed: ${e.message}`
  }
}

async function withdrawAll() {
  withdrawing.value = true
  try {
    const data = await api.withdrawAll()
    statusMsg.value = `Withdrew ${data.count} routes`
    lastCompleted.value = false
    state.value = {}
    emit('routes-changed')
  } catch (e) {
    statusMsg.value = `Withdraw failed: ${e.message}`
  } finally {
    withdrawing.value = false
  }
}

function startPolling() {
  stopPolling()
  pollStatus()
  pollTimer = setInterval(pollStatus, 2000)
}

function stopPolling() {
  if (pollTimer) {
    clearInterval(pollTimer)
    pollTimer = null
  }
}

async function pollStatus() {
  try {
    const data = await api.fullTableStatus()
    state.value = data

    if (data.active) {
      statusMsg.value = `Injecting: ${formatNum(data.injected)} / ${formatNum(data.total)} (${data.rate_pps || 0}/s)`
    } else if (data.error) {
      statusMsg.value = `Error: ${data.error}`
      injecting.value = false
      stopPolling()
    } else if (data.injected > 0) {
      statusMsg.value = `Complete: ${formatNum(data.injected)} routes in ${data.elapsed_sec}s (${data.rate_pps}/s)`
      injecting.value = false
      lastCompleted.value = true
      stopPolling()
      emit('routes-changed')
    }
  } catch (e) {
    // keep polling
  }
}

onUnmounted(() => {
  stopPolling()
})
</script>

<style scoped>
.full-table {
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: 680px;
}

.section-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.section-desc {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
  margin-top: -8px;
}

.config-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.level-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}

.level-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 12px 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  transition: all 0.15s;
}

.level-btn:hover:not(:disabled) {
  border-color: var(--accent);
  background: rgba(79, 156, 249, 0.08);
}

.level-btn.selected {
  border-color: var(--accent);
  background: rgba(79, 156, 249, 0.15);
  box-shadow: 0 0 0 1px var(--accent);
}

.level-count {
  font-size: 18px;
  font-weight: 700;
  font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
  color: var(--accent);
}

.level-desc {
  font-size: 11px;
  color: var(--muted);
}

.mono-input {
  font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 7px 10px;
  font-size: 13px;
  outline: none;
  max-width: 200px;
}

.mono-input:focus {
  border-color: var(--accent);
}

.action-row {
  display: flex;
  gap: 10px;
  padding-top: 4px;
  border-top: 1px solid var(--border);
}

.btn-start {
  padding: 9px 22px;
  background: rgba(72, 187, 120, 0.15);
  color: #48bb78;
  border: 1px solid rgba(72, 187, 120, 0.3);
  font-weight: 700;
  font-size: 14px;
  display: flex;
  align-items: center;
  gap: 7px;
}

.btn-start:hover:not(:disabled) {
  background: rgba(72, 187, 120, 0.25);
}

.btn-stop {
  padding: 9px 22px;
  background: rgba(252, 129, 129, 0.15);
  color: #fc8181;
  border: 1px solid rgba(252, 129, 129, 0.3);
  font-weight: 700;
  font-size: 14px;
  display: flex;
  align-items: center;
  gap: 7px;
  animation: pulse-border 1.5s ease-in-out infinite;
}

.btn-stop:hover {
  background: rgba(252, 129, 129, 0.25);
}

.btn-withdraw {
  padding: 9px 18px;
  background: rgba(246, 173, 85, 0.15);
  color: #f6ad55;
  border: 1px solid rgba(246, 173, 85, 0.3);
  font-weight: 600;
  font-size: 13px;
}

.btn-withdraw:hover:not(:disabled) {
  background: rgba(246, 173, 85, 0.25);
}

.status-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.status-header {
  display: flex;
  align-items: center;
  gap: 10px;
}

.status-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.dot-active {
  background: #48bb78;
  box-shadow: 0 0 8px #48bb78;
  animation: pulse-dot 1s ease-in-out infinite;
}

.dot-idle {
  background: var(--muted);
}

.status-text {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
}

.progress-section {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.progress-labels {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--muted);
}

.progress-track {
  height: 6px;
  background: var(--border);
  border-radius: 3px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  transition: width 0.5s ease;
}

.stats-row {
  display: flex;
  gap: 24px;
}

.stat-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.stat-label {
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.stat-val {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
}

.inject-error {
  font-size: 12px;
  color: #fc8181;
  padding: 6px 10px;
  background: rgba(252, 129, 129, 0.08);
  border-radius: 4px;
  border: 1px solid rgba(252, 129, 129, 0.2);
}

@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

@keyframes pulse-border {
  0%, 100% { border-color: rgba(252, 129, 129, 0.3); }
  50% { border-color: rgba(252, 129, 129, 0.6); }
}
</style>
