<script setup lang="ts">
// <!-- ld-v2 --> Perimeter panel: first-place concerned (computed, full dot,
// tap → inclusion reason), second-place (declared, raised hand, public note),
// « Ça me concerne », arrested-list countdown, NON-IGNORABLE influx banner
// (widen one notch / keep with a public note), boundary objection.
import type { Concern, Decision, Id, Person } from '~/types/domain'
import {
  CONCERN_FIRST, CONCERN_ME, CONCERN_SECOND, PERIMETER_OVERFLOW,
  SCOPE_KEEP, SCOPE_WIDEN,
} from '~/lexicon'
import { computeConcerned } from '~/engine'
import { useCollectiveStore } from '~/stores/collective'
import { useDecisionsStore } from '~/stores/decisions'

const props = defineProps<{ decision: Decision }>()

const col = useCollectiveStore()
const store = useDecisionsStore()

const concerns = computed(() =>
  col.concerns.filter(c => c.decisionId === props.decision.id))

function entriesOf(origin: Concern['origin']) {
  return concerns.value
    .filter(c => c.origin === origin)
    .map((c) => {
      const person = col.people.find(p => p.id === c.personId)
      return person ? { person, origin, reason: c.reason, concern: c } : null
    })
    .filter((e): e is { person: Person; origin: Concern['origin']; reason: string; concern: Concern } => e !== null)
}

const firstPlace = computed(() => entriesOf('computed'))
const secondPlace = computed(() => entriesOf('declared'))

// ── Popover : raison d'inclusion en un tap ──
const selected = ref<{ name: string; title: string; reason: string; note?: string; consultative: boolean } | null>(null)

function onTap(entry: { person: Person; origin?: string; reason?: string }) {
  const concern = concerns.value.find(c => c.personId === entry.person.id)
  const parts: string[] = []
  if (concern?.reason) parts.push(concern.reason)
  selected.value = {
    name: entry.person.displayName,
    title: concern?.origin === 'declared' ? CONCERN_SECOND : CONCERN_FIRST,
    reason: parts.join(' — '),
    ...(concern?.declaredNote ? { note: concern.declaredNote } : {}),
    consultative: concern?.origin === 'declared' && concern.beforeSnapshot === false,
  }
}

// ── « Ça me concerne » ──
const meId = computed(() => col.me?.id ?? null)
const alreadyConcerned = computed(() =>
  meId.value !== null
  && (props.decision.authorId === meId.value
    || concerns.value.some(c => c.personId === meId.value)))

function declareMe() {
  if (meId.value) store.declareConcern(props.decision.id, meId.value)
}

// ── Compte à rebours de la liste arrêtée (session à venir) ──
const arrestAt = computed(() =>
  props.decision.status === 'framing' ? props.decision.windowEndsAt : undefined)

// ── Bannière d'affluence — non-ignorable ──
const ACTIVE = ['draft', 'advice', 'objection', 'framing', 'voting']
const overflow = computed(() => {
  if (!ACTIVE.includes(props.decision.status) || props.decision.scopeKeptNote) return false
  const computedCount = firstPlace.value.length
  const declaredCount = secondPlace.value.length
  const ratio = col.settings?.triage.concernEscalateRatio ?? 0.5
  return computedCount > 0 && declaredCount >= ratio * computedCount
})

function widen() {
  const d = props.decision
  if (!col.current) return
  const next = new Set<Id>()
  for (const id of d.scope.circleIds) {
    const circle = col.circles.find(c => c.id === id)
    next.add(circle?.parentCircleId ?? id)
  }
  if (next.size === 0) next.add(col.current.collective.rootCircleId)
  d.scope.circleIds = [...next]
  // Re-persist the widened computation — every inclusion keeps its reason.
  const activeMandates = col.mandates.filter(m => m.status === 'active')
  const known = new Set(concerns.value.map(c => c.personId))
  const now = col.now()
  for (const entry of computeConcerned(d.scope, col.circles, activeMandates, d.authorId)) {
    if (known.has(entry.personId)) continue
    col.current.concerns.push({
      id: col.newId(),
      collectiveId: d.collectiveId,
      createdAt: now,
      updatedAt: now,
      decisionId: d.id,
      personId: entry.personId,
      origin: 'computed',
      reason: entry.reason,
      beforeSnapshot: !col.sessions.some(s => s.decisionId === d.id),
    })
  }
  col.stamp(d)
  col.persist()
}

const keepOpen = ref(false)
const keepNote = ref('')
function keepScope() {
  const note = keepNote.value.trim()
  if (note.length === 0) return
  props.decision.scopeKeptNote = note
  col.stamp(props.decision)
  col.persist()
  keepOpen.value = false
}

// ── Objection de frontière ──
const boundaryOpen = ref(false)
const boundaryArg = ref('')
const boundaryError = ref('')
function sendBoundary() {
  const result = store.objectTo(props.decision.id, 'boundary', boundaryArg.value)
  if ('ok' in result) { boundaryError.value = result.reason; return }
  boundaryOpen.value = false
  boundaryArg.value = ''
  boundaryError.value = ''
}
</script>

<template>
  <!-- ld-v2 -->
  <section class="peri">
    <h2 class="peri__title">Périmètre</h2>

    <div v-if="overflow" class="peri__overflow no-print">
      <p class="peri__overflow-text">
        <UIcon name="i-lucide-waves" />
        <span>{{ PERIMETER_OVERFLOW }}</span>
      </p>
      <div class="peri__overflow-actions">
        <button type="button" class="ld-btn" @click="widen()">{{ SCOPE_WIDEN }}</button>
        <button type="button" class="ld-btn ld-btn--ghost" @click="keepOpen = !keepOpen">
          {{ SCOPE_KEEP }}
        </button>
      </div>
      <div v-if="keepOpen" class="peri__keep">
        <textarea
          v-model="keepNote"
          rows="2"
          placeholder="Pourquoi le périmètre reste-t-il ainsi ? Cette note sera publique."
        />
        <button
          type="button"
          class="ld-btn"
          :disabled="keepNote.trim().length === 0"
          @click="keepScope()"
        >
          Publier la note et maintenir
        </button>
      </div>
    </div>

    <div class="peri__group">
      <p class="peri__label">{{ CONCERN_FIRST }}</p>
      <LdAvatarStack
        v-if="firstPlace.length > 0"
        :people="firstPlace"
        :max="8"
        @tap="onTap"
      />
      <p v-else class="peri__none">Personne d'autre — décision sur soi.</p>
    </div>

    <div class="peri__group">
      <p class="peri__label">{{ CONCERN_SECOND }}</p>
      <LdAvatarStack
        v-if="secondPlace.length > 0"
        :people="secondPlace"
        :max="8"
        @tap="onTap"
      />
      <p v-else class="peri__none">Personne ne s'est déclaré·e pour l'instant.</p>
    </div>

    <div v-if="selected" class="peri__popover" @click="selected = null">
      <p class="peri__popover-name">{{ selected.name }}</p>
      <p class="peri__popover-origin">{{ selected.title }}</p>
      <p v-if="selected.reason" class="peri__popover-reason">{{ selected.reason }}</p>
      <p v-if="selected.note" class="peri__popover-note">« {{ selected.note }} »</p>
      <p v-if="selected.consultative" class="peri__popover-consult">
        Déclaré·e après l'arrêt de la liste — voix consultative.
      </p>
    </div>

    <div v-if="arrestAt" class="peri__arrest">
      <LdCountdown :ends-at="arrestAt" />
      <p class="peri__arrest-rule">
        Déclaré·e avant l'arrêt de la liste : tu votes. Après : voix consultative.
      </p>
    </div>

    <div class="peri__actions no-print">
      <button
        v-if="!alreadyConcerned"
        type="button"
        class="ld-btn ld-btn--ghost"
        @click="declareMe()"
      >
        <UIcon name="i-lucide-hand" />
        <span>{{ CONCERN_ME }}</span>
      </button>
      <button
        type="button"
        class="ld-btn ld-btn--quiet"
        @click="boundaryOpen = !boundaryOpen"
      >
        <UIcon name="i-lucide-user-plus" />
        <span>J'ai été oublié·e / il manque quelqu'un</span>
      </button>
    </div>

    <div v-if="boundaryOpen" class="peri__keep no-print">
      <textarea
        v-model="boundaryArg"
        rows="2"
        placeholder="Qui manque, et pourquoi cette personne est concernée ?"
      />
      <button
        type="button"
        class="ld-btn"
        :disabled="boundaryArg.trim().length === 0"
        @click="sendBoundary()"
      >
        Contester la frontière
      </button>
      <p v-if="boundaryError" class="peri__error">{{ boundaryError }}</p>
    </div>
  </section>
</template>

<style scoped>
.peri {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}
.peri__title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.peri__group {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.peri__label {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--mood-text-muted);
}
.peri__none {
  margin: 0;
  font-size: 0.875rem;
  color: var(--mood-text-muted);
  font-style: italic;
}
.peri__popover {
  padding: 0.75rem 1rem;
  border-radius: var(--r-input);
  background: var(--mood-accent-soft);
  cursor: pointer;
}
.peri__popover-name { margin: 0; font-weight: 800; font-size: 0.9375rem; }
.peri__popover-origin {
  margin: 0.125rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--mood-accent);
}
.peri__popover-reason { margin: 0.25rem 0 0; font-size: 0.875rem; }
.peri__popover-note {
  margin: 0.25rem 0 0;
  font-size: 0.875rem;
  font-style: italic;
  color: var(--mood-text-muted);
}
.peri__popover-consult {
  margin: 0.25rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--mood-status-fenetre);
}
.peri__arrest {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.peri__arrest-rule {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--mood-text-muted);
}
.peri__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.peri__overflow {
  padding: 1rem 1.125rem;
  border-radius: var(--r-input);
  background: color-mix(in srgb, var(--mood-status-fenetre) 14%, transparent);
  box-shadow: inset 0 0 0 2px var(--mood-status-fenetre);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.peri__overflow-text {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 800;
  color: var(--mood-status-fenetre);
}
.peri__overflow-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.peri__keep {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.peri__keep textarea {
  width: 100%;
  padding: 0.625rem 0.875rem;
  font-size: 0.9375rem;
  resize: vertical;
}
.peri__error {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--mood-error);
}
</style>
