<template>
  <div class="churn-control">
    <h2 class="section-title">Churn Control</h2>
    <p class="section-desc">
      Repeatedly load and unload a scenario to simulate BGP route churn.
      Runs entirely in the browser via timed API calls.
    </p>

    <div class="config-card">
      <!-- Scenario selector -->
      <div class="form-group">
        <label>Scenario Name</label>
        <input
          v-model="scenarioName"
          type="text"
          placeholder="churn"
          :disabled="running"
          class="mono-input"
        />
      </div>

      <!-- Cycle count -->
      <div class="form-group">
        <label>Cycles: <span class="slider-val">{{ cycleCount === 0 ? '&#8734; (infinite)' : cycleCount }}</span></label>
        <input
          v-model.number="cycleCount"
          type="range"
          min="0"
          max="20"
          step="1"
          :disabled="running"
          class="slider"
        />
        <div class="slider-labels">
          <span>0 (&#8734;)</span>
          <span>5</span>
          <span>10</span>
          <span>15</span>
          <span>20</span>
        </div>
      </div>

      <!-- Announce duration -->
      <div class="form-group">
        <label>Announce Duration: <span class="slider-val">{{ announceSecs }}s</span></label>
        <input
          v-model.number="announceSecs"
          type="range"
          min="5"
          max="120"
          step="5"
          :disabled="running"
          class="slider"
        />
        <div class="slider-labels">
          <span>5s</span>
          <span>30s</span>
          <span>60s</span>
          <span>90s</span>
          <span>120s</span>
        </div>
      </div>

      <!-- Withdraw duration -->
      <div class="form-group">
        <label>Withdraw Duration: <span class="slider-val">{{ withdrawSecs }}s</span></label>
        <input
          v-model.number="withdrawSecs"
          type="range"
          min="5"
          max="120"
          step="5"
          :disabled="running"
          class="slider"
        />
        <div class="slider-labels">
          <span>5s</span>
          <span>30s</span>
          <span>60s</span>
          <span>90s</span>
          <span>120s</span>
        </div>
      </div>

      <!-- Action buttons -->
      <div class="action-row">
        <button v-if="!running" class="btn-start" @click="startChurn" :disabled="!scenarioName.trim()">
          <span>&#9654;</span> Start Churn
        </button>
        <button v-else class="btn-stop" @click="stopChurn">
          <span>&#9632;</span> Stop
        </button>
      </div>
    </div>

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

      <!-- Progress bar (only when cycling with fixed count) -->
      <div v-if="running && cycleCount > 0" class="progress-section">
        <div class="progress-labels">
          <span>Cycle {{ currentCycle }} / {{ cycleCount }}</span>
          <span>{{ progressPct }}%</span>
        </div>
        <div class="progress-track">
          <div class="progress-fill" :style="{ width: progressPct + '%' }"></div>
        </div>
      </div>

      <!-- Phase progress bar -->
      <div v-if="running && phaseTotal > 0" class="progress-section">
        <div class="progress-labels">
          <span>{{ phaseLabel }} — {{ phaseElapsed }}s / {{ phaseTotal }}s</span>
          <span>{{ phasePct }}%</span>
        </div>
        <div class="progress-track">
          <div class="progress-fill phase-fill" :style="{ width: phasePct + '%' }"></div>
        </div>
      </div>

      <!-- Error -->
      <div v-if="churnError" class="churn-error">{{ churnError }}</div>
    </div>
  </div>
</template>

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

const scenarioName = ref('churn')
const cycleCount = ref(5)
const announceSecs = ref(30)
const withdrawSecs = ref(15)

const running = ref(false)
const currentCycle = ref(0)
const statusMsg = ref('')
const churnError = ref(null)
const phaseLabel = ref('')
const phaseElapsed = ref(0)
const phaseTotal = ref(0)

let stopFlag = false
let phaseTimer = null

const progressPct = computed(() => {
  if (!cycleCount.value || currentCycle.value === 0) return 0
  return Math.round(((currentCycle.value - 1) / cycleCount.value) * 100)
})

const phasePct = computed(() => {
  if (!phaseTotal.value) return 0
  return Math.min(100, Math.round((phaseElapsed.value / phaseTotal.value) * 100))
})

function sleep(ms) {
  return new Promise(resolve => {
    const start = Date.now()
    const tick = () => {
      if (stopFlag) return resolve()
      const elapsed = (Date.now() - start) / 1000
      phaseElapsed.value = Math.round(elapsed)
      if (Date.now() - start >= ms) {
        resolve()
      } else {
        phaseTimer = setTimeout(tick, 500)
      }
    }
    tick()
  })
}

async function startChurn() {
  if (!scenarioName.value.trim()) return
  running.value = true
  stopFlag = false
  currentCycle.value = 0
  churnError.value = null
  statusMsg.value = 'Starting...'

  const maxCycles = cycleCount.value === 0 ? Infinity : cycleCount.value

  try {
    for (let i = 1; i <= maxCycles; i++) {
      if (stopFlag) break

      currentCycle.value = i
      statusMsg.value = `Cycle ${cycleCount.value > 0 ? i + '/' + cycleCount.value : i} — Announcing routes...`
      phaseLabel.value = 'Announcing'
      phaseTotal.value = announceSecs.value
      phaseElapsed.value = 0

      try {
        await api.loadScenario(scenarioName.value.trim())
      } catch (e) {
        churnError.value = `Load failed: ${e.message}`
      }

      await sleep(announceSecs.value * 1000)
      if (stopFlag) break

      statusMsg.value = `Cycle ${cycleCount.value > 0 ? i + '/' + cycleCount.value : i} — Withdrawing routes...`
      phaseLabel.value = 'Withdrawing'
      phaseTotal.value = withdrawSecs.value
      phaseElapsed.value = 0

      try {
        await api.unloadScenario(scenarioName.value.trim())
      } catch (e) {
        churnError.value = `Unload failed: ${e.message}`
      }

      await sleep(withdrawSecs.value * 1000)
    }
  } catch (e) {
    churnError.value = `Churn error: ${e.message}`
  } finally {
    running.value = false
    phaseTotal.value = 0
    phaseElapsed.value = 0
    if (!stopFlag) {
      statusMsg.value = `Churn complete — ${currentCycle.value} cycle(s) finished`
    } else {
      statusMsg.value = `Stopped after ${currentCycle.value} cycle(s)`
    }
  }
}

function stopChurn() {
  stopFlag = true
  if (phaseTimer) clearTimeout(phaseTimer)
  statusMsg.value = 'Stopping...'
}

onUnmounted(() => {
  stopFlag = true
  if (phaseTimer) clearTimeout(phaseTimer)
})
</script>

<style scoped>
.churn-control {
  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;
}

.slider-val {
  color: var(--accent);
  font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
  font-size: 13px;
  text-transform: none;
  letter-spacing: 0;
}

.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: 300px;
}

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

.slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 5px;
  border-radius: 3px;
  background: var(--border);
  outline: none;
  cursor: pointer;
}

.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: none;
}

.slider:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.slider-labels {
  display: flex;
  justify-content: space-between;
  font-size: 10px;
  color: #4a5568;
  padding: 0 2px;
}

.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);
}

.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;
}

.phase-fill {
  background: #48bb78;
}

.churn-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>
