<script setup lang="ts">
// Mirror of InviteOperatorModal but scoped to a partner. POSTs to
// /api/partners/:slug/users which proxies platform-api's
// /partners/:slug/users — the server resolves the partner, creates the
// Authentik user, adds them to the dezky-partner-staff group, sets
// User.partnerId, and returns the same recovery-link/temp-password
// handoff shape as the operator invite. UI text differs to match the
// partner-staff context.

interface InviteResult {
  subject: string
  userId: string
  // True if the user already existed in Authentik and we just attached them.
  // When set, link/tempPassword are absent and the UI hides the credential
  // row (the user already has a password from their original signup).
  attached?: boolean
  link?: string
  tempPassword?: string
}

const props = defineProps<{ open: boolean; partnerSlug: string; partnerName: string }>()
const emit = defineEmits<{ close: []; invited: [InviteResult] }>()

const name = ref('')
const email = ref('')
const busy = ref(false)
const error = ref<string | null>(null)
const result = ref<InviteResult | null>(null)
const copied = ref(false)

watch(
  () => props.open,
  (v) => {
    if (v) {
      name.value = ''
      email.value = ''
      busy.value = false
      error.value = null
      result.value = null
      copied.value = false
    }
  },
)

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

const canSubmit = computed(() => {
  return (
    !busy.value &&
    name.value.trim().length >= 2 &&
    /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value.trim())
  )
})

async function submit() {
  if (!canSubmit.value) return
  busy.value = true
  error.value = null
  try {
    result.value = await $fetch<InviteResult>(`/api/partners/${props.partnerSlug}/users`, {
      method: 'POST',
      body: { name: name.value.trim(), email: email.value.trim() },
    })
    emit('invited', result.value)
  } catch (e) {
    const err = e as { data?: { data?: { message?: string }; message?: string; statusMessage?: string } }
    error.value =
      err.data?.data?.message ||
      err.data?.message ||
      err.data?.statusMessage ||
      'Invite failed'
  } finally {
    busy.value = false
  }
}

async function copyToClipboard(value: string) {
  try {
    await navigator.clipboard.writeText(value)
    copied.value = true
    setTimeout(() => (copied.value = false), 2000)
  } catch {
    // Non-secure context — user can still select the readonly input.
  }
}

function done() {
  emit('close')
}
</script>

<template>
  <Teleport to="body">
    <div v-if="open" class="backdrop" @click="!busy && emit('close')">
      <div class="modal" role="dialog" aria-label="Invite team member" @click.stop>
        <header>
          <div>
            <Eyebrow>{{ partnerName }}</Eyebrow>
            <h2>Invite team member</h2>
          </div>
          <button class="x" type="button" aria-label="Close" :disabled="busy" @click="emit('close')">
            <UiIcon name="x" :size="12" />
          </button>
        </header>

        <!-- Step 1: collect details -->
        <div v-if="!result" class="body">
          <section>
            <label class="label">Name</label>
            <input v-model="name" type="text" placeholder="Ronni Baslund" :disabled="busy" />
          </section>
          <section>
            <label class="label">Email</label>
            <input v-model="email" type="email" placeholder="ronni@baslund.com" :disabled="busy" />
          </section>

          <div class="note">
            <UiIcon name="shield" :size="13" />
            <Mono dim>
              Adds the user to the <strong>dezky-partner-staff</strong> Authentik group and
              attaches them to <strong>{{ partnerName }}</strong>. They'll receive a
              single-use recovery link to set their password + enroll MFA.
            </Mono>
          </div>

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

        <!-- Step 2: show the credential to share -->
        <div v-else class="body result">
          <Badge tone="ok" dot>{{ result.attached ? 'attached' : 'invited' }}</Badge>

          <!-- Existing-user path: no credential, just confirm attach -->
          <template v-if="result.attached">
            <p class="success">
              <Mono>{{ email }}</Mono> already existed in Authentik. They're now
              part of <Mono>{{ partnerName }}</Mono> — no new password needed;
              they sign in with their existing credentials and will see the
              partner workspace on next login.
            </p>
          </template>

          <template v-else-if="result.link">
            <p class="success">
              {{ name }} (<Mono>{{ email }}</Mono>) was added to
              <Mono>{{ partnerName }}</Mono>. Share the link below — it's single-use
              and they'll set their own password + MFA.
            </p>
            <div class="cred-row">
              <input :value="result.link" readonly @focus="($event.target as HTMLInputElement).select()" />
              <UiButton variant="secondary" @click="copyToClipboard(result.link!)">
                {{ copied ? 'Copied' : 'Copy' }}
              </UiButton>
            </div>
          </template>

          <template v-else-if="result.tempPassword">
            <p class="success">
              {{ name }} (<Mono>{{ email }}</Mono>) was added to
              <Mono>{{ partnerName }}</Mono>. Authentik doesn't have a recovery
              flow configured yet, so we set a temporary password — share it with
              them out-of-band, they'll be prompted to change it on first login.
            </p>
            <section>
              <label class="label">Username / email</label>
              <div class="cred-row">
                <input :value="email" readonly @focus="($event.target as HTMLInputElement).select()" />
                <UiButton variant="secondary" @click="copyToClipboard(email)">
                  Copy
                </UiButton>
              </div>
            </section>
            <section>
              <label class="label">Temporary password</label>
              <div class="cred-row">
                <input :value="result.tempPassword" readonly @focus="($event.target as HTMLInputElement).select()" />
                <UiButton variant="secondary" @click="copyToClipboard(result.tempPassword!)">
                  {{ copied ? 'Copied' : 'Copy' }}
                </UiButton>
              </div>
            </section>
            <Mono dim>
              // configure a recovery flow in Authentik (Flows → recovery) to
              switch this to a self-service link · once SMTP is wired the
              credential gets emailed automatically
            </Mono>
          </template>
        </div>

        <footer v-if="!result">
          <UiButton variant="ghost" :disabled="busy" @click="emit('close')">Cancel</UiButton>
          <UiButton variant="primary" :disabled="!canSubmit" @click="submit">
            {{ busy ? 'Inviting…' : 'Send invite' }}
          </UiButton>
        </footer>
        <footer v-else>
          <UiButton variant="primary" @click="done">Done</UiButton>
        </footer>
      </div>
    </div>
  </Teleport>
</template>

<style scoped>
.backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  z-index: 180;
}
.modal {
  width: 100%; max-width: 520px;
  background: var(--elevated);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.5);
  display: flex; flex-direction: column;
  overflow: hidden;
}
header {
  padding: 16px 20px;
  display: flex; justify-content: space-between; align-items: flex-start;
  border-bottom: 1px solid var(--border);
}
h2 { margin: 4px 0 0 0; font-family: var(--font-display); font-weight: 600; font-size: 18px; }
.x {
  width: 26px; height: 26px;
  border: 0; border-radius: 6px; background: transparent;
  color: var(--text-mute); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.x:hover:not(:disabled) { background: var(--surface); color: var(--text); }
.x:disabled { opacity: 0.4; cursor: not-allowed; }

.body {
  padding: 16px 20px;
  display: flex; flex-direction: column; gap: 14px;
}
section { display: flex; flex-direction: column; gap: 6px; }
.label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-mute);
  font-weight: 500;
}
input {
  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:focus { border-color: var(--border-hi); }
input:disabled { opacity: 0.6; }

.note {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-mute);
}
.note strong { color: var(--text); font-family: var(--font-mono); font-weight: 600; }

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

.result .success {
  margin: 4px 0 0 0;
  font-size: 13px;
  color: var(--text-dim);
  line-height: 1.55;
}
.cred-row { display: flex; gap: 8px; align-items: center; }
.cred-row input {
  flex: 1;
  font-family: var(--font-mono);
  font-size: 11px;
}

footer {
  padding: 12px 20px;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  border-top: 1px solid var(--border);
  background: var(--surface);
}
</style>
