<script setup lang="ts">
// <!-- ld-v2 --> L'établi de l'Atelier — porté du FormulaEditor v1 (sliders,
// exposants Forgeron/Comité) et du FormulaDisplay v1 (rendu KaTeX), branché sur
// l'UNIQUE moteur ~/engine (wotThreshold, smithThreshold, techcommThreshold).
// La seule maison des lettres : W, T, M, B, G, C n'apparaissent qu'ici.
import { wotThreshold, smithThreshold, techcommThreshold } from '~/engine'
import { INERTIA_LABELS, thresholdSentence } from '~/lexicon'
import type { AtelierInit } from './textsModel'
import { INERTIA_COLORS, INERTIA_ORDER, INERTIA_PARAMS, formatInt } from './textsModel'

const props = defineProps<{ initial?: AtelierInit }>()

// ── L'état de l'établi ───────────────────────────────────────
const W = ref(Math.max(1, Math.round(props.initial?.W ?? 100)))
const T = ref(Math.max(0, Math.round(props.initial?.T ?? Math.max(1, Math.round(W.value / 3)))))
const M = ref(props.initial?.M ?? 50)
const B = ref(props.initial?.B ?? 0.1)
const G = ref(props.initial?.G ?? 0.2)
const C = ref(props.initial?.C ?? 0)
const withSmith = ref(props.initial?.S !== undefined)
const S = ref(props.initial?.S ?? 0.1)
const smithW = ref(12)
const withTech = ref(false)
const techExp = ref(0.1)
const techW = ref(6)

watch(W, (w) => { if (T.value > w) T.value = w })

/** Cas Forgeron 2026 — un clic : W=7224, T=120 ⇒ 94 pour requis. */
function loadForgeron2026(): void {
  W.value = 7224
  T.value = 120
  M.value = 50
  B.value = 0.1
  G.value = 0.2
  C.value = 0
  withSmith.value = true
  S.value = 0.1
  withTech.value = false
}

// ── Les seuils — source unique ~/engine ──────────────────────
const threshold = computed(() => wotThreshold(W.value, T.value, M.value, B.value, G.value, C.value))
const thresholdPct = computed(() =>
  T.value > 0 ? Math.round((threshold.value / T.value) * 100) : null)
const sentence = computed(() =>
  T.value > 0 ? thresholdSentence(W.value, T.value, threshold.value) : null)
const smithRequired = computed(() =>
  withSmith.value ? smithThreshold(Math.max(1, smithW.value), S.value) : null)
const techRequired = computed(() =>
  withTech.value ? techcommThreshold(Math.max(1, techW.value), techExp.value) : null)

// ── KaTeX (chargé globalement — repli <code> sinon) ──────────
const MAIN_TEX = 'Seuil = C + B^{W} + \\left(M + (1-M)\\cdot\\left(1 - \\left(\\tfrac{T}{W}\\right)^{G}\\right)\\right)\\cdot\\max(0,\\,T - C)'
const katexTick = ref(0)
onMounted(() => {
  const w = window as unknown as { katex?: unknown }
  if (w.katex) return
  const timer = setInterval(() => {
    if (w.katex) { katexTick.value++; clearInterval(timer) }
  }, 200)
  setTimeout(() => clearInterval(timer), 6000)
})
function renderTex(tex: string): string {
  const w = window as unknown as {
    katex?: { renderToString: (t: string, o: object) => string }
  }
  if (typeof window !== 'undefined' && w.katex) {
    return w.katex.renderToString(tex, { throwOnError: false, displayMode: true })
  }
  return `<code class="lab__tex-fallback">${tex}</code>`
}
const mainFormulaHtml = computed(() => { void katexTick.value; return renderTex(MAIN_TEX) })
const smithFormulaHtml = computed(() => {
  void katexTick.value
  return withSmith.value ? renderTex(`Seuil_{forgerons} = \\lceil ${smithW.value}^{${S.value}} \\rceil = ${smithRequired.value}`) : null
})
const techFormulaHtml = computed(() => {
  void katexTick.value
  return withTech.value ? renderTex(`Seuil_{comit\\acute{e}} = \\lceil ${techW.value}^{${techExp.value}} \\rceil = ${techRequired.value}`) : null
})

// ── Table de participation : T croissant sur W donné ─────────
const PARTICIPATION_STEPS = [1, 2, 5, 10, 25, 50, 75, 100]
const participationRows = computed(() => {
  const seen = new Set<number>()
  return PARTICIPATION_STEPS.flatMap((pct) => {
    const votes = Math.max(1, Math.round((W.value * pct) / 100))
    if (seen.has(votes)) return []
    seen.add(votes)
    const required = wotThreshold(W.value, votes, M.value, B.value, G.value, C.value)
    return [{
      pct,
      votes,
      required,
      ratio: Math.round((required / votes) * 100),
      isCurrent: Math.abs(votes - T.value) === Math.min(
        ...PARTICIPATION_STEPS.map(p => Math.abs(Math.max(1, Math.round((W.value * p) / 100)) - T.value)),
      ),
    }]
  })
})

// ── Presets d'inertie comparés (câblage réel du domaine) ─────
const presetRows = computed(() => INERTIA_ORDER.map((preset) => {
  const params = INERTIA_PARAMS[preset]
  const required = T.value > 0
    ? wotThreshold(W.value, T.value, params.majorityPct, 0.1, params.gradientExponent, 0)
    : 0
  return {
    preset,
    label: INERTIA_LABELS[preset],
    color: INERTIA_COLORS[preset],
    majorityPct: params.majorityPct,
    gradient: params.gradientExponent,
    required,
    ratio: T.value > 0 ? Math.round((required / T.value) * 100) : 0,
    active: params.majorityPct === M.value && params.gradientExponent === G.value,
  }
}))

/** Courbes seuil (%) / participation — portées de l'InertiaSlider v1. */
function curvePath(majorityPct: number, gradient: number): string {
  const m = majorityPct / 100
  const points: string[] = []
  for (let i = 0; i <= 40; i++) {
    const participation = i / 40
    const ratio = m + (1 - m) * (1 - participation ** gradient)
    points.push(`${(30 + participation * 170).toFixed(1)},${(10 + (1 - ratio) * 70).toFixed(1)}`)
  }
  return `M ${points.join(' L ')}`
}
const presetCurves = computed(() => presetRows.value.map(row => ({
  ...row,
  path: curvePath(row.majorityPct, row.gradient),
})))
const currentCurve = computed(() => curvePath(M.value, G.value))
</script>

<template>
  <!-- ld-v2 -->
  <section class="lab">
    <!-- La formule, rendue -->
    <div class="lab__formula ld-card">
      <div class="lab__tex" v-html="mainFormulaHtml" />
      <div class="lab__legend">
        <span><strong>W</strong> membres éligibles</span>
        <span><strong>T</strong> votes exprimés</span>
        <span><strong>M</strong> majorité cible</span>
        <span><strong>B</strong> plancher dynamique</span>
        <span><strong>G</strong> gradient d'inertie</span>
        <span><strong>C</strong> plancher fixe</span>
      </div>
    </div>

    <div class="lab__grid">
      <!-- Les réglages -->
      <div class="lab__controls ld-card">
        <div class="lab__scenario">
          <label class="lab__field">
            <span class="lab__field-label">W — membres éligibles</span>
            <input v-model.number="W" type="number" min="1" max="1000000" class="lab__number">
          </label>
          <label class="lab__field">
            <span class="lab__field-label">T — votes exprimés</span>
            <input v-model.number="T" type="number" min="0" :max="W" class="lab__number">
          </label>
          <button type="button" class="ld-btn ld-btn--ghost lab__forgeron" @click="loadForgeron2026">
            <UIcon name="i-lucide-hammer" />
            Cas Forgeron 2026
          </button>
        </div>

        <label class="lab__slider">
          <span class="lab__slider-head">
            <span>M — majorité cible</span><strong>{{ M }} %</strong>
          </span>
          <input v-model.number="M" type="range" min="0" max="100" step="1">
        </label>
        <label class="lab__slider">
          <span class="lab__slider-head">
            <span>B — plancher dynamique</span><strong>{{ B }}</strong>
          </span>
          <input v-model.number="B" type="range" min="0.01" max="1" step="0.01">
        </label>
        <label class="lab__slider">
          <span class="lab__slider-head">
            <span>G — gradient d'inertie</span><strong>{{ G }}</strong>
          </span>
          <input v-model.number="G" type="range" min="0.01" max="2" step="0.01">
        </label>
        <label class="lab__slider">
          <span class="lab__slider-head">
            <span>C — plancher fixe</span><strong>{{ C }}</strong>
          </span>
          <input v-model.number="C" type="range" min="0" max="100" step="1">
        </label>

        <div class="lab__optional">
          <label class="lab__check">
            <input v-model="withSmith" type="checkbox">
            <span>Critère Forgeron</span>
          </label>
          <div v-if="withSmith" class="lab__sub">
            <label class="lab__slider">
              <span class="lab__slider-head"><span>S — exposant</span><strong>{{ S }}</strong></span>
              <input v-model.number="S" type="range" min="0.01" max="1" step="0.01">
            </label>
            <label class="lab__field lab__field--inline">
              <span class="lab__field-label">forgerons actifs</span>
              <input v-model.number="smithW" type="number" min="1" max="10000" class="lab__number">
            </label>
          </div>
          <label class="lab__check">
            <input v-model="withTech" type="checkbox">
            <span>Critère Comité technique</span>
          </label>
          <div v-if="withTech" class="lab__sub">
            <label class="lab__slider">
              <span class="lab__slider-head"><span>exposant</span><strong>{{ techExp }}</strong></span>
              <input v-model.number="techExp" type="range" min="0.01" max="1" step="0.01">
            </label>
            <label class="lab__field lab__field--inline">
              <span class="lab__field-label">membres du comité</span>
              <input v-model.number="techW" type="number" min="1" max="1000" class="lab__number">
            </label>
          </div>
        </div>
      </div>

      <!-- Le résultat -->
      <div class="lab__result ld-card">
        <p class="lab__result-heading">Le seuil, ici et maintenant</p>
        <p class="lab__result-figure">
          <span class="lab__result-number">{{ formatInt(threshold) }}</span>
          <span class="lab__result-unit">pour requis</span>
        </p>
        <p v-if="thresholdPct !== null" class="lab__result-pct">
          soit {{ thresholdPct }} % des {{ formatInt(T) }} votes exprimés
        </p>
        <p v-if="sentence" class="lab__result-sentence">{{ sentence }}</p>
        <div v-if="smithFormulaHtml" class="lab__criterion" v-html="smithFormulaHtml" />
        <div v-if="techFormulaHtml" class="lab__criterion" v-html="techFormulaHtml" />
      </div>
    </div>

    <!-- Table de participation -->
    <div class="lab__table-card ld-card">
      <p class="lab__block-title">Le seuil descend quand la participation monte</p>
      <p class="lab__block-sub">T croissant, sur une toile de {{ formatInt(W) }} membres</p>
      <div class="lab__table-scroll">
        <table class="lab__table">
          <thead>
            <tr>
              <th>participation</th>
              <th>T</th>
              <th>seuil</th>
              <th>% des exprimés</th>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="row in participationRows"
              :key="row.pct"
              :class="{ 'lab__row--current': row.isCurrent }"
            >
              <td>{{ row.pct }} %</td>
              <td>{{ formatInt(row.votes) }}</td>
              <td class="lab__cell-strong">{{ formatInt(row.required) }}</td>
              <td>{{ row.ratio }} %</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>

    <!-- Presets d'inertie comparés -->
    <div class="lab__presets ld-card">
      <p class="lab__block-title">Les quatre inerties, comparées</p>
      <p class="lab__block-sub">
        mêmes W et T — seule l'inertie change ; ce sont les presets réels des clauses
      </p>
      <svg viewBox="0 0 230 100" class="lab__curves" role="img" aria-label="Courbes de seuil par inertie">
        <line x1="30" y1="10" x2="30" y2="80" class="lab__axis" />
        <line x1="30" y1="80" x2="200" y2="80" class="lab__axis" />
        <path
          v-for="curve in presetCurves"
          :key="curve.preset"
          :d="curve.path"
          fill="none"
          :style="{ stroke: curve.color }"
          :stroke-width="curve.active ? 2.6 : 1.4"
          :opacity="curve.active ? 1 : 0.55"
          stroke-linecap="round"
        />
        <path
          v-if="!presetCurves.some(curve => curve.active)"
          :d="currentCurve"
          fill="none"
          class="lab__curve-current"
          stroke-width="2.2"
          stroke-dasharray="5 4"
        />
        <text x="14" y="14" class="lab__axis-label">100%</text>
        <text x="18" y="84" class="lab__axis-label">M</text>
        <text x="30" y="94" class="lab__axis-label">0%</text>
        <text x="180" y="94" class="lab__axis-label">100%</text>
        <text x="110" y="99" class="lab__axis-title">participation T/W</text>
        <text x="4" y="52" class="lab__axis-title" transform="rotate(-90, 8, 52)">seuil</text>
      </svg>
      <div class="lab__preset-rows">
        <button
          v-for="row in presetRows"
          :key="row.preset"
          type="button"
          class="lab__preset"
          :class="{ 'lab__preset--active': row.active }"
          :style="{ '--preset-color': row.color }"
          @click="M = row.majorityPct; G = row.gradient; B = 0.1; C = 0"
        >
          <span class="lab__preset-dot" />
          <span class="lab__preset-label">{{ row.label }}</span>
          <span class="lab__preset-params">M{{ row.majorityPct }} · G{{ row.gradient }}</span>
          <span class="lab__preset-required">{{ formatInt(row.required) }} pour ({{ row.ratio }} %)</span>
        </button>
      </div>
    </div>
  </section>
</template>

<style scoped>
.lab { display: flex; flex-direction: column; gap: 1rem; }

.lab__formula { padding: clamp(0.9rem, 3vw, 1.4rem); overflow-x: auto; }
.lab__tex { text-align: center; }
.lab__tex :deep(.lab__tex-fallback) {
  font-family: monospace;
  font-size: 0.8125rem;
  color: var(--mood-text);
}
.lab__legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 1rem;
  margin-top: 0.6rem;
  font-size: 0.6875rem;
  color: var(--mood-text-muted);
}
.lab__legend strong { color: var(--mood-accent); font-family: monospace; }

.lab__grid { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 768px) { .lab__grid { grid-template-columns: 3fr 2fr; } }

.lab__controls {
  padding: clamp(0.9rem, 3vw, 1.3rem);
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}
.lab__scenario { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: flex-end; }
.lab__field { display: flex; flex-direction: column; gap: 0.25rem; }
.lab__field--inline { flex-direction: row; align-items: center; gap: 0.5rem; }
.lab__field-label {
  font-size: 0.71875rem;
  font-weight: 700;
  color: var(--mood-text-muted);
}
.lab__number {
  width: 7.5rem;
  padding: 0.4rem 0.7rem;
  font-size: 0.9375rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  box-shadow: inset 0 0 0 1.5px var(--mood-input-border);
}
.lab__forgeron { font-size: 0.8125rem; }

.lab__slider { display: flex; flex-direction: column; gap: 0.3rem; }
.lab__slider-head {
  display: flex;
  justify-content: space-between;
  font-size: 0.8125rem;
  color: var(--mood-text-muted);
}
.lab__slider-head strong {
  color: var(--mood-accent);
  font-variant-numeric: tabular-nums;
  font-family: monospace;
}
.lab__slider input[type='range'] {
  width: 100%;
  accent-color: var(--mood-accent);
  background: transparent;
  min-height: 1.4rem;
}

.lab__optional {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding-top: 0.75rem;
  box-shadow: 0 -1px 0 color-mix(in srgb, var(--mood-text) 8%, transparent);
}
.lab__check {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--mood-text);
  cursor: pointer;
}
.lab__check input { accent-color: var(--mood-accent); width: 1rem; height: 1rem; }
.lab__sub {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding-left: 1rem;
}

.lab__result {
  padding: clamp(0.9rem, 3vw, 1.3rem);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  background:
    linear-gradient(150deg, var(--mood-accent-soft), transparent 60%),
    var(--mood-surface);
}
.lab__result-heading {
  font-size: 0.6875rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--mood-text-muted);
}
.lab__result-figure { display: flex; align-items: baseline; gap: 0.5rem; }
.lab__result-number {
  font-size: clamp(2.2rem, 7vw, 3rem);
  font-weight: 800;
  color: var(--mood-accent);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.lab__result-unit { font-size: 0.9375rem; font-weight: 700; color: var(--mood-text); }
.lab__result-pct { font-size: 0.875rem; color: var(--mood-text-muted); }
.lab__result-sentence {
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--mood-text);
  padding: 0.6rem 0.8rem;
  border-radius: var(--r-input);
  background: color-mix(in srgb, var(--mood-text) 4%, transparent);
}
.lab__criterion { overflow-x: auto; font-size: 0.875rem; }

.lab__table-card, .lab__presets { padding: clamp(0.9rem, 3vw, 1.3rem); }
.lab__block-title { font-size: 0.9375rem; font-weight: 800; color: var(--mood-text); }
.lab__block-sub { font-size: 0.75rem; color: var(--mood-text-muted); margin-bottom: 0.7rem; }
.lab__table-scroll { overflow-x: auto; }
.lab__table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
.lab__table th {
  text-align: left;
  font-size: 0.6875rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--mood-text-muted);
  padding: 0.35rem 0.6rem;
}
.lab__table td {
  padding: 0.35rem 0.6rem;
  font-variant-numeric: tabular-nums;
  color: var(--mood-text);
}
.lab__table tbody tr:nth-child(odd) td {
  background: color-mix(in srgb, var(--mood-text) 3%, transparent);
}
.lab__row--current td { background: var(--mood-accent-soft) !important; font-weight: 700; }
.lab__cell-strong { font-weight: 800; color: var(--mood-accent); }

.lab__curves { width: 100%; max-width: 26rem; height: auto; margin: 0 auto 0.5rem; display: block; }
.lab__axis { stroke: color-mix(in srgb, var(--mood-text) 25%, transparent); stroke-width: 1; }
.lab__axis-label { font-size: 5.5px; fill: var(--mood-text-muted); font-family: monospace; }
.lab__axis-title { font-size: 5.5px; fill: var(--mood-text-muted); font-weight: 600; }
.lab__curve-current { stroke: var(--mood-text); }

.lab__preset-rows { display: flex; flex-direction: column; gap: 0.4rem; }
.lab__preset {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  padding: 0.55rem 0.8rem;
  border-radius: var(--r-input);
  background: color-mix(in srgb, var(--preset-color) 6%, transparent);
  cursor: pointer;
  text-align: left;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.lab__preset:hover { transform: translateY(-1px); box-shadow: 0 3px 10px var(--mood-shadow); }
.lab__preset--active { box-shadow: 0 0 0 2px var(--preset-color); }
.lab__preset-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--preset-color);
  flex-shrink: 0;
}
.lab__preset-label { font-size: 0.8125rem; font-weight: 800; color: var(--mood-text); }
.lab__preset-params {
  font-size: 0.6875rem;
  font-family: monospace;
  color: var(--mood-text-muted);
}
.lab__preset-required {
  margin-left: auto;
  font-size: 0.8125rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--preset-color);
}
</style>
