<script setup lang="ts">
// Right-anchored side panel for editing a single flag. Opens from a row click
// on /flags. Mirrors the NotificationDrawer/IncidentModal dismissal pattern
// (Teleport scrim + Escape + route change) and the segmented-state UI from
// the operator design.

import type { Flag, FlagState } from '~/types/flag'
import type { Tenant } from '~/types/tenant'

const props = defineProps<{ flag: Flag | null; tenants: Tenant[] }>()
const emit = defineEmits<{
  close: []
  saved: [Flag]
  deleted: [string]
}>()

const route = useRoute()

// Local working copy so unsaved edits aren't visible elsewhere. Reset every
// time `flag` changes (opening a different row, or re-opening after save).
const draft = ref({
  description: '',
  state: 'off' as FlagState,
  pct: 0,
  plans: [] as string[],
  tenantSlugs: [] as string[],
  partnerSlugs: [] as string[],
  environments: [] as ('prod' | 'staging' | 'dev')[],
  note: '',
})

watch(
  () => props.flag,
  (f) => {
    if (!f) return
    draft.value = {
      description: f.description,
      state: f.state,
      pct: f.pct,
      plans: [...f.scope.plans],
      tenantSlugs: [...f.scope.tenantSlugs],
      partnerSlugs: [...f.scope.partnerSlugs],
      environments: [...f.scope.environments],
      note: '',
    }
  },
  { immediate: true },
)

watch(() => route.path, () => {
  if (props.flag) emit('close')
})

onMounted(() => {
  const onKey = (e: KeyboardEvent) => {
    if (e.key === 'Escape' && props.flag) emit('close')
  }
  document.addEventListener('keydown', onKey)
  onBeforeUnmount(() => document.removeEventListener('keydown', onKey))
})

const STATES: FlagState[] = ['off', 'targeted', 'rollout', 'on']
const ALL_PLANS = ['mvp', 'pro', 'enterprise']
const ALL_ENVS: ('prod' | 'staging' | 'dev')[] = ['prod', 'staging', 'dev']

const totalTenants = computed(() => props.tenants.length)
const rolloutCount = computed(() => Math.round((totalTenants.value * draft.value.pct) / 100))

const dirty = computed(() => {
  if (!props.flag) return false
  const f = props.flag
  const d = draft.value
  return (
    d.description !== f.description ||
    d.state !== f.state ||
    d.pct !== f.pct ||
    !arrEq(d.plans, f.scope.plans) ||
    !arrEq(d.tenantSlugs, f.scope.tenantSlugs) ||
    !arrEq(d.partnerSlugs, f.scope.partnerSlugs) ||
    !arrEq(d.environments, f.scope.environments)
  )
})

function arrEq(a: string[], b: string[]) {
  if (a.length !== b.length) return false
  const sa = [...a].sort()
  const sb = [...b].sort()
  return sa.every((v, i) => v === sb[i])
}

const busy = ref(false)
const error = ref<string | null>(null)

function togglePlan(p: string) {
  draft.value.plans = draft.value.plans.includes(p)
    ? draft.value.plans.filter((x) => x !== p)
    : [...draft.value.plans, p]
}
function toggleEnv(e: 'prod' | 'staging' | 'dev') {
  draft.value.environments = draft.value.environments.includes(e)
    ? draft.value.environments.filter((x) => x !== e)
    : [...draft.value.environments, e]
}
function toggleTenant(slug: string) {
  draft.value.tenantSlugs = draft.value.tenantSlugs.includes(slug)
    ? draft.value.tenantSlugs.filter((x) => x !== slug)
    : [...draft.value.tenantSlugs, slug]
}

async function save() {
  if (!props.flag || !dirty.value) return
  busy.value = true
  error.value = null
  try {
    const updated = await $fetch<Flag>(`/api/flags/${props.flag.key}`, {
      method: 'PATCH',
      body: {
        description: draft.value.description,
        state: draft.value.state,
        pct: draft.value.pct,
        scope: {
          plans: draft.value.plans,
          tenantSlugs: draft.value.tenantSlugs,
          partnerSlugs: draft.value.partnerSlugs,
          environments: draft.value.environments,
        },
        note: draft.value.note || undefined,
      },
    })
    emit('saved', updated)
  } catch (e) {
    const err = e as { data?: { data?: { message?: string }; message?: string } }
    error.value = err.data?.data?.message || err.data?.message || 'Save failed'
  } finally {
    busy.value = false
  }
}

async function killSwitch() {
  if (!props.flag) return
  busy.value = true
  error.value = null
  try {
    const updated = await $fetch<Flag>(`/api/flags/${props.flag.key}`, {
      method: 'PATCH',
      body: { state: 'off', pct: 0, note: 'kill-switch' },
    })
    emit('saved', updated)
  } catch (e) {
    const err = e as { data?: { message?: string } }
    error.value = err.data?.message || 'Kill-switch failed'
  } finally {
    busy.value = false
  }
}

function fmtDate(s: string) {
  return new Date(s).toLocaleString('da-DK', { dateStyle: 'short', timeStyle: 'short' })
}
</script>

<template>
  <Teleport to="body">
    <Transition name="drawer-fade">
      <div v-if="flag" class="backdrop" @click="emit('close')" />
    </Transition>
    <Transition name="drawer-slide">
      <aside v-if="flag" class="drawer" role="dialog" :aria-label="flag.key" @click.stop>
        <header>
          <div>
            <Eyebrow>Feature flag</Eyebrow>
            <h2><Mono>{{ flag.key }}</Mono></h2>
          </div>
          <button class="x" type="button" aria-label="Close" @click="emit('close')">
            <UiIcon name="x" :size="13" />
          </button>
        </header>

        <div class="body">
          <section>
            <label class="label">Description</label>
            <input v-model="draft.description" type="text" />
          </section>

          <section>
            <label class="label">State</label>
            <div class="seg four">
              <button
                v-for="s in STATES"
                :key="s"
                :class="{ on: draft.state === s }"
                type="button"
                @click="draft.state = s"
              >{{ s }}</button>
            </div>
          </section>

          <section v-if="draft.state === 'rollout'">
            <label class="label">Rollout percentage</label>
            <div class="rollout-row">
              <input v-model.number="draft.pct" type="range" min="0" max="100" />
              <Mono class="pct">{{ draft.pct }}%</Mono>
            </div>
            <Mono dim>~{{ rolloutCount }} of {{ totalTenants }} tenants will see this flag enabled</Mono>
          </section>

          <section v-if="draft.state === 'targeted' || draft.state === 'rollout'">
            <label class="label">Plans</label>
            <div class="chips">
              <button
                v-for="p in ALL_PLANS"
                :key="p"
                :class="['chip', { on: draft.plans.includes(p) }]"
                type="button"
                @click="togglePlan(p)"
              >{{ p }}</button>
            </div>
            <Mono dim>empty = any plan</Mono>
          </section>

          <section v-if="draft.state === 'targeted' || draft.state === 'rollout'">
            <label class="label">Tenant allowlist</label>
            <div v-if="tenants.length" class="chips wrap">
              <button
                v-for="t in tenants"
                :key="t.slug"
                :class="['chip', { on: draft.tenantSlugs.includes(t.slug) }]"
                type="button"
                :title="t.name"
                @click="toggleTenant(t.slug)"
              >{{ t.slug }}</button>
            </div>
            <Mono dim>empty = any tenant</Mono>
          </section>

          <section v-if="draft.state === 'targeted' || draft.state === 'rollout'">
            <label class="label">Environments</label>
            <div class="chips">
              <button
                v-for="e in ALL_ENVS"
                :key="e"
                :class="['chip', { on: draft.environments.includes(e) }]"
                type="button"
                @click="toggleEnv(e)"
              >{{ e }}</button>
            </div>
            <Mono dim>empty = any environment</Mono>
          </section>

          <section v-if="dirty">
            <label class="label">Change note (optional)</label>
            <input v-model="draft.note" type="text" placeholder="why are you changing this?" />
          </section>

          <section>
            <label class="label">Change history</label>
            <div class="history">
              <div v-for="(h, i) in [...flag.history].reverse()" :key="i" class="hist-row">
                <Mono dim>{{ fmtDate(h.at) }}</Mono>
                <Mono>{{ h.byEmail || 'system' }}</Mono>
                <span>{{ h.action }}</span>
                <Mono v-if="h.note" dim class="hist-note">— {{ h.note }}</Mono>
              </div>
              <Mono v-if="!flag.history.length" dim>no history</Mono>
            </div>
          </section>

          <p v-if="error" class="err">{{ error }}</p>
        </div>

        <footer>
          <UiButton variant="danger" :disabled="busy || flag.state === 'off'" @click="killSwitch">
            <template #leading><UiIcon name="x" :size="13" /></template>
            Kill-switch
          </UiButton>
          <div class="spacer" />
          <UiButton variant="ghost" @click="emit('close')">Cancel</UiButton>
          <UiButton variant="primary" :disabled="!dirty || busy" @click="save">
            {{ busy ? 'Saving…' : 'Save changes' }}
          </UiButton>
        </footer>
      </aside>
    </Transition>
  </Teleport>
</template>

<style scoped>
.backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); z-index: 190; }

.drawer {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: min(560px, 100vw);
  background: var(--elevated);
  border-left: 1px solid var(--border);
  box-shadow: -16px 0 48px rgba(0, 0, 0, 0.35);
  z-index: 200;
  display: flex; flex-direction: column;
  overflow: hidden;
}

header {
  padding: 18px 22px 14px 22px;
  border-bottom: 1px solid var(--border);
  display: flex; justify-content: space-between; align-items: flex-start;
}
h2 {
  margin: 4px 0 0 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
}
.x {
  width: 28px; height: 28px;
  border: 0; border-radius: 6px; background: transparent;
  color: var(--text-mute); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.x:hover { background: var(--surface); color: var(--text); }

.body {
  flex: 1; overflow-y: auto;
  padding: 20px 22px;
  display: flex; flex-direction: column; gap: 18px;
}

section { display: flex; flex-direction: column; gap: 8px; }
.label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-mute);
  font-weight: 500;
}

input[type='text'] {
  height: 34px;
  padding: 0 12px;
  background: var(--input-bg);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  font-family: inherit;
  font-size: 13px;
  outline: 0;
}
input[type='text']:focus { border-color: var(--border-hi); }

.seg {
  display: grid;
  gap: 4px;
  padding: 3px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 7px;
  width: fit-content;
}
.seg.four { grid-template-columns: repeat(4, minmax(72px, 1fr)); }
.seg button {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  padding: 6px 12px;
  border-radius: 5px;
  cursor: pointer;
}
.seg button:hover { color: var(--text); }
.seg button.on { background: var(--text); color: var(--bg); }

.rollout-row { display: flex; align-items: center; gap: 14px; }
.rollout-row input { flex: 1; accent-color: var(--accent); }
.pct { font-size: 14px; font-weight: 600; min-width: 50px; text-align: right; }

.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chips.wrap { max-height: 140px; overflow-y: auto; padding: 4px 0; }
.chip {
  appearance: none;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 4px 10px;
  border-radius: 999px;
  cursor: pointer;
}
.chip:hover { color: var(--text); border-color: var(--border-hi); }
.chip.on { background: var(--text); color: var(--bg); border-color: var(--text); }

.history {
  display: flex; flex-direction: column; gap: 6px;
  border-left: 2px solid var(--border);
  padding-left: 12px;
  max-height: 200px;
  overflow-y: auto;
}
.hist-row {
  display: grid;
  grid-template-columns: 110px 160px 1fr;
  gap: 10px;
  align-items: baseline;
  font-size: 12px;
}
.hist-note { grid-column: 1 / -1; padding-left: 0; }

.err {
  margin: 0;
  padding: 10px 12px;
  background: rgba(240, 88, 88, 0.08);
  border: 1px solid rgba(240, 88, 88, 0.24);
  color: var(--bad);
  border-radius: 6px;
  font-size: 12px;
}

footer {
  border-top: 1px solid var(--border);
  background: var(--surface);
  padding: 12px 18px;
  display: flex; gap: 8px; align-items: center;
}
.spacer { flex: 1; }

.drawer-fade-enter-active, .drawer-fade-leave-active { transition: opacity 0.18s ease; }
.drawer-fade-enter-from, .drawer-fade-leave-to { opacity: 0; }
.drawer-slide-enter-active, .drawer-slide-leave-active { transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1); }
.drawer-slide-enter-from, .drawer-slide-leave-to { transform: translateX(100%); }
</style>
