<template>
  <div class="bezier-editor">
    <div class="editor-layout">
      <!-- SVG Canvas -->
      <div class="editor-canvas card">
        <svg
          ref="svgRef"
          :viewBox="`0 0 ${svgW} ${svgH}`"
          preserveAspectRatio="xMidYMid meet"
          @mousemove="onMouseMove"
          @mouseup="onMouseUp"
          @mouseleave="onMouseUp"
          @touchmove.prevent="onTouchMove"
          @touchend="onMouseUp"
        >
          <!-- Grid -->
          <g class="grid-lines">
            <line
              v-for="v in gridVolumes"
              :key="'gv' + v"
              :x1="toSvgX(v)" :y1="toSvgY(0)" :x2="toSvgX(v)" :y2="toSvgY(pmax)"
              stroke="#e2e8f0" stroke-width="0.5"
            />
            <line
              v-for="p in gridPrices"
              :key="'gp' + p"
              :x1="toSvgX(0)" :y1="toSvgY(p)" :x2="toSvgX(vmax)" :y2="toSvgY(p)"
              stroke="#e2e8f0" stroke-width="0.5"
            />
            <!-- Axis labels -->
            <text
              v-for="v in gridVolumes"
              :key="'lv' + v"
              :x="toSvgX(v)" :y="svgH - 2"
              text-anchor="middle" font-size="10" fill="#94a3b8"
            >{{ v }}</text>
            <text
              v-for="p in gridPrices"
              :key="'lp' + p"
              :x="4" :y="toSvgY(p) + 3"
              font-size="10" fill="#94a3b8"
            >{{ p }}</text>
          </g>

          <!-- Control point tangent lines -->
          <g class="tangent-lines">
            <line :x1="toSvgX(cp.p1.x)" :y1="toSvgY(cp.p1.y)" :x2="toSvgX(cp.p2.x)" :y2="toSvgY(cp.p2.y)"
              stroke="#93c5fd" stroke-width="1" stroke-dasharray="4" />
            <line :x1="toSvgX(cp.p3.x)" :y1="toSvgY(cp.p3.y)" :x2="toSvgX(cp.p4.x)" :y2="toSvgY(cp.p4.y)"
              stroke="#93c5fd" stroke-width="1" stroke-dasharray="4" />
            <line :x1="toSvgX(cp.p4.x)" :y1="toSvgY(cp.p4.y)" :x2="toSvgX(cp.p5.x)" :y2="toSvgY(cp.p5.y)"
              stroke="#fca5a5" stroke-width="1" stroke-dasharray="4" />
            <line :x1="toSvgX(cp.p6.x)" :y1="toSvgY(cp.p6.y)" :x2="toSvgX(cp.p7.x)" :y2="toSvgY(cp.p7.y)"
              stroke="#fca5a5" stroke-width="1" stroke-dasharray="4" />
          </g>

          <!-- Bézier curves -->
          <path :d="tier1Path" fill="none" stroke="#2563eb" stroke-width="2.5" />
          <path :d="tier2Path" fill="none" stroke="#dc2626" stroke-width="2.5" />

          <!-- Inflection point lines -->
          <line :x1="toSvgX(params.vinf)" :y1="toSvgY(0)" :x2="toSvgX(params.vinf)" :y2="toSvgY(localP0)"
            stroke="#94a3b8" stroke-width="1" stroke-dasharray="4" />
          <line :x1="toSvgX(0)" :y1="toSvgY(localP0)" :x2="toSvgX(params.vinf)" :y2="toSvgY(localP0)"
            stroke="#94a3b8" stroke-width="1" stroke-dasharray="4" />

          <!-- p0 label -->
          <text :x="toSvgX(0) + 25" :y="toSvgY(localP0) - 6" font-size="12" fill="#1e293b" font-weight="600">
            p₀ = {{ localP0.toFixed(2) }} €/m³
          </text>

          <!-- Draggable control points -->
          <circle
            v-for="(point, key) in draggablePoints"
            :key="key"
            :cx="toSvgX(point.x)"
            :cy="toSvgY(point.y)"
            :r="dragging === key ? 8 : 6"
            :fill="pointColors[key]"
            stroke="white"
            stroke-width="2"
            style="cursor: grab;"
            @mousedown.prevent="startDrag(key, $event)"
            @touchstart.prevent="startDragTouch(key, $event)"
          />

          <!-- Point labels -->
          <text
            v-for="(point, key) in draggablePoints"
            :key="'label-' + key"
            :x="toSvgX(point.x) + 10"
            :y="toSvgY(point.y) - 10"
            font-size="11"
            :fill="pointColors[key]"
            font-weight="500"
          >{{ pointLabels[key] }}</text>
        </svg>
      </div>

      <!-- Right panel -->
      <div class="editor-panel">
        <!-- Parameters display -->
        <div class="card" style="margin-bottom: 1rem;">
          <h3 style="margin-bottom: 0.75rem;">Paramètres</h3>
          <div class="param-grid">
            <div class="param-item">
              <span class="param-label">vinf</span>
              <span class="param-value">{{ params.vinf.toFixed(0) }} m³</span>
            </div>
            <div class="param-item">
              <span class="param-label">a</span>
              <span class="param-value">{{ params.a.toFixed(3) }}</span>
            </div>
            <div class="param-item">
              <span class="param-label">b</span>
              <span class="param-value">{{ params.b.toFixed(3) }}</span>
            </div>
            <div class="param-item">
              <span class="param-label">c</span>
              <span class="param-value">{{ params.c.toFixed(3) }}</span>
            </div>
            <div class="param-item">
              <span class="param-label">d</span>
              <span class="param-value">{{ params.d.toFixed(3) }}</span>
            </div>
            <div class="param-item">
              <span class="param-label">e</span>
              <span class="param-value">{{ params.e.toFixed(3) }}</span>
            </div>
            <div class="param-item" style="grid-column: span 2;">
              <span class="param-label">p₀ (prix inflexion)</span>
              <span class="param-value" style="font-size: 1.25rem;">{{ localP0.toFixed(2) }} €/m³</span>
            </div>
          </div>
        </div>

        <!-- Impact table -->
        <div class="card" style="margin-bottom: 1rem;">
          <h3 style="margin-bottom: 0.75rem;">Impact par volume</h3>
          <table class="table">
            <thead>
              <tr>
                <th>Volume</th>
                <th>Ancien prix</th>
                <th>Nouveau (RP)</th>
                <th>Nouveau (RS)</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="imp in impacts" :key="imp.volume">
                <td>{{ imp.volume }} m³</td>
                <td>{{ imp.oldPrice.toFixed(2) }} €</td>
                <td :class="imp.newPriceRP > imp.oldPrice ? 'text-up' : 'text-down'">
                  {{ imp.newPriceRP.toFixed(2) }} €
                </td>
                <td :class="imp.newPriceRS > imp.oldPrice ? 'text-up' : 'text-down'">
                  {{ imp.newPriceRS.toFixed(2) }} €
                </td>
              </tr>
            </tbody>
          </table>
        </div>

        <!-- Submit vote -->
        <button class="btn btn-primary" style="width: 100%;" @click="submitVote" :disabled="submitting">
          <span v-if="submitting" class="spinner" style="width: 1rem; height: 1rem;"></span>
          Soumettre mon vote
        </button>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  computeP0, generateCurve, computeImpacts,
  paramsToControlPoints, controlPointsToParams,
  type HouseholdData, type ImpactRow, type ControlPoints,
} from '~/utils/bezier-math'

const props = defineProps<{ communeSlug: string }>()
const emit = defineEmits<{ 'vote-submitted': [] }>()
const api = useApi()

// SVG dimensions
const svgW = 600
const svgH = 400
const margin = { top: 20, right: 20, bottom: 30, left: 35 }
const plotW = svgW - margin.left - margin.right
const plotH = svgH - margin.top - margin.bottom

// Commune tariff params (fixed by admin)
const vmax = ref(2100)
const pmax = ref(20)
const recettes = ref(75000)
const abop = ref(100)
const abos = ref(100)
const households = ref<HouseholdData[]>([])

// Citizen-adjustable params
const params = reactive({
  vinf: 1050,
  a: 0.5,
  b: 0.5,
  c: 0.5,
  d: 0.5,
  e: 0.5,
})

// Computed
const localP0 = ref(0)
const impacts = ref<ImpactRow[]>([])
const submitting = ref(false)

const cp = computed<ControlPoints>(() =>
  paramsToControlPoints(params.vinf, vmax.value, pmax.value, localP0.value, params.a, params.b, params.c, params.d, params.e)
)

const draggablePoints = computed(() => ({
  p2: cp.value.p2,
  p3: cp.value.p3,
  p4: cp.value.p4,
  p5: cp.value.p5,
  p6: cp.value.p6,
}))

const pointColors: Record<string, string> = {
  p2: '#3b82f6',
  p3: '#3b82f6',
  p4: '#8b5cf6',
  p5: '#ef4444',
  p6: '#ef4444',
}

const pointLabels: Record<string, string> = {
  p2: 'P₂ (a)',
  p3: 'P₃ (b)',
  p4: 'P₄ (vinf)',
  p5: 'P₅ (c)',
  p6: 'P₆ (d,e)',
}

// Grid
const gridVolumes = computed(() => {
  const step = Math.ceil(vmax.value / 7 / 100) * 100
  const arr = []
  for (let v = step; v < vmax.value; v += step) arr.push(v)
  return arr
})

const gridPrices = computed(() => {
  const step = Math.ceil(pmax.value / 5)
  const arr = []
  for (let p = step; p < pmax.value; p += step) arr.push(p)
  return arr
})

// Coordinate transforms
function toSvgX(v: number): number {
  return margin.left + (v / vmax.value) * plotW
}

function toSvgY(p: number): number {
  return margin.top + plotH - (p / pmax.value) * plotH
}

function fromSvgX(sx: number): number {
  return ((sx - margin.left) / plotW) * vmax.value
}

function fromSvgY(sy: number): number {
  return ((margin.top + plotH - sy) / plotH) * pmax.value
}

// Bézier path generation
const tier1Path = computed(() => {
  const c = cp.value
  return `M ${toSvgX(c.p1.x)} ${toSvgY(c.p1.y)} C ${toSvgX(c.p2.x)} ${toSvgY(c.p2.y)}, ${toSvgX(c.p3.x)} ${toSvgY(c.p3.y)}, ${toSvgX(c.p4.x)} ${toSvgY(c.p4.y)}`
})

const tier2Path = computed(() => {
  const c = cp.value
  return `M ${toSvgX(c.p4.x)} ${toSvgY(c.p4.y)} C ${toSvgX(c.p5.x)} ${toSvgY(c.p5.y)}, ${toSvgX(c.p6.x)} ${toSvgY(c.p6.y)}, ${toSvgX(c.p7.x)} ${toSvgY(c.p7.y)}`
})

// Drag handling
const svgRef = ref<SVGSVGElement | null>(null)
const dragging = ref<string | null>(null)

function getSvgPoint(event: MouseEvent | Touch): { x: number; y: number } {
  if (!svgRef.value) return { x: 0, y: 0 }
  const rect = svgRef.value.getBoundingClientRect()
  const scaleX = svgW / rect.width
  const scaleY = svgH / rect.height
  return {
    x: (event.clientX - rect.left) * scaleX,
    y: (event.clientY - rect.top) * scaleY,
  }
}

function startDrag(key: string, event: MouseEvent) {
  dragging.value = key
}

function startDragTouch(key: string, event: TouchEvent) {
  dragging.value = key
}

function onMouseMove(event: MouseEvent) {
  if (!dragging.value) return
  handleDrag(getSvgPoint(event))
}

function onTouchMove(event: TouchEvent) {
  if (!dragging.value || !event.touches[0]) return
  handleDrag(getSvgPoint(event.touches[0]))
}

function handleDrag(svgPoint: { x: number; y: number }) {
  const v = Math.max(0, Math.min(vmax.value, fromSvgX(svgPoint.x)))
  const p = Math.max(0, Math.min(pmax.value, fromSvgY(svgPoint.y)))

  switch (dragging.value) {
    case 'p2': // vertical only → a
      params.a = localP0.value > 0 ? Math.max(0, Math.min(1, p / localP0.value)) : 0.5
      break
    case 'p3': // horizontal only → b
      params.b = params.vinf > 0 ? Math.max(0, Math.min(1, v / params.vinf)) : 0.5
      break
    case 'p4': // horizontal → vinf
      params.vinf = Math.max(1, Math.min(vmax.value - 1, v))
      break
    case 'p5': { // horizontal only → c
      const wmax = vmax.value - params.vinf
      params.c = wmax > 0 ? Math.max(0, Math.min(1, (v - params.vinf) / wmax)) : 0.5
      break
    }
    case 'p6': { // 2D → d, e
      const wmax = vmax.value - params.vinf
      const qmax = pmax.value - localP0.value

      // e from y
      params.e = qmax > 0 ? Math.max(0, Math.min(1, (p - localP0.value) / qmax)) : 0.5

      // d from x: x6 = vinf + wmax*(1-d+cd) => d = (1 - (x6-vinf)/wmax)/(1-c)
      if (wmax > 0 && Math.abs(1 - params.c) > 1e-10) {
        const ratio = (v - params.vinf) / wmax
        params.d = Math.max(0, Math.min(1, (1 - ratio) / (1 - params.c)))
      }
      break
    }
  }

  recalculate()
}

function onMouseUp() {
  if (dragging.value) {
    dragging.value = null
    debouncedServerCompute()
  }
}

// Recalculate locally
function recalculate() {
  if (households.value.length === 0) return

  localP0.value = computeP0(
    households.value, recettes.value, abop.value, abos.value,
    params.vinf, vmax.value, pmax.value,
    params.a, params.b, params.c, params.d, params.e,
  )

  const result = computeImpacts(
    households.value, recettes.value, abop.value, abos.value,
    params.vinf, vmax.value, pmax.value,
    params.a, params.b, params.c, params.d, params.e,
  )
  impacts.value = result.impacts
}

// Debounced server compute
let serverTimeout: ReturnType<typeof setTimeout> | null = null
function debouncedServerCompute() {
  if (serverTimeout) clearTimeout(serverTimeout)
  serverTimeout = setTimeout(async () => {
    try {
      const result = await api.post<any>('/tariff/compute', {
        commune_slug: props.communeSlug,
        vinf: params.vinf,
        a: params.a,
        b: params.b,
        c: params.c,
        d: params.d,
        e: params.e,
      })
      // Use authoritative server p0
      localP0.value = result.p0
      impacts.value = result.impacts.map((imp: any) => ({
        volume: imp.volume,
        oldPrice: imp.old_price,
        newPriceRP: imp.new_price_rp,
        newPriceRS: imp.new_price_rs,
      }))
    } catch (e) {
      // Silently fall back to client-side calculation
    }
  }, 300)
}

// Submit vote
async function submitVote() {
  submitting.value = true
  try {
    await api.post(`/communes/${props.communeSlug}/votes`, {
      vinf: params.vinf,
      a: params.a,
      b: params.b,
      c: params.c,
      d: params.d,
      e: params.e,
    })
    emit('vote-submitted')
  } catch (e: any) {
    alert(e.message || 'Erreur lors de la soumission du vote')
  } finally {
    submitting.value = false
  }
}

// Load data on mount
onMounted(async () => {
  try {
    // Load commune params
    const communeParams = await api.get<any>(`/communes/${props.communeSlug}/params`)
    vmax.value = communeParams.vmax
    pmax.value = communeParams.pmax
    recettes.value = communeParams.recettes
    abop.value = communeParams.abop
    abos.value = communeParams.abos
    params.vinf = communeParams.vmax / 2

    // Load household stats (we need volumes for p0 calculation)
    // For client-side compute, we fetch stats and create a simplified model
    const stats = await api.get<any>(`/communes/${props.communeSlug}/households/stats`)

    // Create representative household distribution for client-side compute
    // (simplified: use average volumes by status)
    const rsCount = stats.rs_count || 0
    const rpCount = stats.rp_count || 0
    const proCount = stats.pro_count || 0
    const avgVol = stats.avg_volume || 90

    const hh: HouseholdData[] = []
    for (let i = 0; i < rsCount; i++) hh.push({ volume_m3: avgVol, status: 'RS' })
    for (let i = 0; i < rpCount; i++) hh.push({ volume_m3: avgVol, status: 'RP' })
    for (let i = 0; i < proCount; i++) hh.push({ volume_m3: avgVol, status: 'PRO' })
    households.value = hh

    // Initial server compute for accurate p0
    recalculate()
    debouncedServerCompute()
  } catch (e) {
    console.error('Error loading commune data:', e)
  }
})
</script>

<style scoped>
.editor-layout {
  display: grid;
  grid-template-columns: 1fr 350px;
  gap: 1.5rem;
}

@media (max-width: 900px) {
  .editor-layout {
    grid-template-columns: 1fr;
  }
}

.editor-canvas {
  padding: 0.5rem;
}

.editor-canvas svg {
  width: 100%;
  height: auto;
  user-select: none;
}

.param-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
}

.param-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.25rem 0;
}

.param-label {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  font-weight: 500;
}

.param-value {
  font-family: monospace;
  font-weight: 600;
}

.text-up { color: #dc2626; }
.text-down { color: #059669; }
</style>
