<template>
  <BaseModal
    :show="show"
    :title="step === 1 ? 'Mesh Device Detected' : 'Set Up Your Mesh Radio'"
    max-width="max-w-lg"
    content-class="max-h-[90vh] overflow-y-auto"
    @close="dismiss"
  >
    <!-- Step 1: detection + hardware graphic -->
    <div v-if="step === 1" class="text-center">
      <div class="mx-auto my-2 w-44 h-44 relative">
        <!-- pulsing signal waves behind the board image -->
        <svg viewBox="0 0 160 160" class="absolute inset-0 w-full h-full" aria-hidden="true">
          <g class="mesh-detect-waves" stroke="rgba(251,146,60,0.5)" fill="none" stroke-width="2.5" stroke-linecap="round">
            <path d="M130 44 a30 30 0 0 1 0 28" />
            <path d="M138 36 a42 42 0 0 1 0 44" />
            <path d="M146 28 a54 54 0 0 1 0 60" />
          </g>
        </svg>
        <!-- actual board image (vendored from the Meshtastic web flasher) -->
        <img
          :src="deviceImage.image"
          :alt="deviceImage.label"
          class="relative w-full h-full object-contain drop-shadow-[0_8px_24px_rgba(251,146,60,0.25)]"
          @error="imageFailed = true"
          v-if="!imageFailed"
        />
        <div v-else class="relative w-full h-full flex items-center justify-center text-5xl">📡</div>
      </div>
      <p class="text-white text-base font-medium">{{ deviceImage.label }}</p>
      <p class="text-white/60 text-xs mt-1">
        {{ deviceImage.exact ? 'Detected' : 'Detected LoRa radio' }} on
        <span class="font-mono text-orange-300">{{ devicePath }}</span>
      </p>
      <p class="text-white/50 text-xs mt-2">
        Connect it to join the off-grid mesh — chat, block headers, and payments
        keep flowing even without internet.
      </p>
      <div class="flex gap-2 mt-6">
        <button class="flex-1 glass-button px-4 py-2 rounded-lg text-sm" @click="dismiss">
          Not Now
        </button>
        <button class="flex-1 glass-button glass-button-warning px-4 py-2 rounded-lg text-sm font-medium" @click="step = 2">
          Set Up
        </button>
      </div>
    </div>

    <!-- Step 2: configuration with presets -->
    <div v-else>
      <p class="text-white/60 text-xs mb-4">
        Archipelago presets are pre-selected — confirm the region and you're on the mesh.
      </p>

      <div class="space-y-4">
        <!-- Region — the meaning adapts to the firmware: Meshtastic takes a
             region enum directly; MeshCore/RNode take raw RF params owned by
             the firmware/daemon, so the region only drives displayed guidance. -->
        <div>
          <label class="block text-sm text-white/80 mb-1">LoRa region / frequency plan</label>
          <select v-model="form.region" class="w-full rounded-lg bg-white/[0.06] border border-white/10 text-white px-3 py-2 text-sm focus:outline-none focus:border-orange-400/60">
            <option value="">Keep the radio's current region</option>
            <option v-for="r in LORA_REGIONS" :key="r.code" :value="r.code">{{ r.label }}</option>
          </select>
          <p v-if="suggestedRegion && form.region === suggestedRegion.code" class="text-[11px] text-green-400/80 mt-1">
            Suggested from your node's location
          </p>
          <p v-if="selectedRegion && selectedRegion.dutyCyclePct < 100" class="text-[11px] text-amber-400/80 mt-1">
            {{ selectedRegion.code }} limits airtime to {{ selectedRegion.dutyCyclePct }}% duty cycle ({{ selectedRegion.band }} MHz) — the radio enforces this automatically.
          </p>
          <p v-if="effectiveKind === 'meshcore' && meshcorePlan" class="text-[11px] text-sky-300/80 mt-1">
            MeshCore community plan for {{ selectedRegion?.code }}: {{ meshcorePlan.freqMhz }} MHz, {{ meshcorePlan.bwKhz }} kHz, SF{{ meshcorePlan.sf }}, CR4/{{ meshcorePlan.cr }} — set on the radio via its MeshCore app if it differs.
          </p>
          <p v-else-if="effectiveKind === 'meshcore' && selectedRegion" class="text-[11px] text-sky-300/80 mt-1">
            MeshCore radios keep their flashed RF settings — make sure the radio is on the {{ selectedRegion.band }} MHz band for {{ selectedRegion.code }}.
          </p>
          <p v-if="effectiveKind === 'reticulum'" class="text-[11px] text-sky-300/80 mt-1">
            RNode radio parameters (frequency / bandwidth / SF / CR) are managed by the Reticulum daemon's interface config on this node.
          </p>
        </div>

        <!-- Node name -->
        <div>
          <label class="block text-sm text-white/80 mb-1">Name on the mesh</label>
          <input v-model="form.name" maxlength="24" placeholder="e.g. basement-node"
            class="w-full rounded-lg bg-white/[0.06] border border-white/10 text-white px-3 py-2 text-sm focus:outline-none focus:border-orange-400/60" />
        </div>

        <!-- Channel (Meshtastic secondary channel / MeshCore group channel;
             Reticulum has no channel concept — IFAC lives in the daemon config) -->
        <div v-if="effectiveKind !== 'reticulum'">
          <label class="block text-sm text-white/80 mb-1">Channel</label>
          <input v-model="form.channel" maxlength="11"
            class="w-full rounded-lg bg-white/[0.06] border border-white/10 text-white px-3 py-2 text-sm focus:outline-none focus:border-orange-400/60" />
          <p class="text-[11px] text-white/40 mt-1">
            Archipelago nodes find each other on the "archipelago" channel; the public default channel stays active for interop.
          </p>
        </div>

        <!-- Firmware (advanced) -->
        <div>
          <button class="text-xs text-orange-300 hover:text-orange-200" @click="showAdvanced = !showAdvanced">
            {{ showAdvanced ? '▾' : '▸' }} Advanced
          </button>
          <div v-if="showAdvanced" class="mt-2">
            <label class="block text-sm text-white/80 mb-1">Radio firmware</label>
            <select v-model="form.deviceKind" class="w-full rounded-lg bg-white/[0.06] border border-white/10 text-white px-3 py-2 text-sm focus:outline-none focus:border-orange-400/60">
              <option value="auto">Auto-detect (Meshcore → Meshtastic → RNode)</option>
              <option value="meshcore">MeshCore</option>
              <option value="meshtastic">Meshtastic</option>
              <option value="reticulum">Reticulum / RNode</option>
            </select>
            <p class="text-[11px] text-white/40 mt-1">
              Pin this if you know what's flashed on the board — auto-detect probes each firmware in order.
            </p>
          </div>
        </div>
      </div>

      <p v-if="error" class="text-xs text-red-400 mt-3">{{ error }}</p>

      <div class="flex gap-2 mt-6">
        <button class="glass-button px-4 py-2 rounded-lg text-sm" @click="step = 1">Back</button>
        <button
          class="flex-1 glass-button glass-button-warning px-4 py-2 rounded-lg text-sm font-medium disabled:opacity-50"
          :disabled="connecting"
          @click="connect"
        >
          {{ connecting ? 'Connecting…' : 'Connect to Mesh' }}
        </button>
      </div>
    </div>
  </BaseModal>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useRouter } from 'vue-router'
import BaseModal from '@/components/BaseModal.vue'
import { useMeshStore } from '@/stores/mesh'
import { useAppStore } from '@/stores/app'
import { LORA_REGIONS, regionByCode, suggestRegionFromLatLon, meshcorePlanFor } from '@/utils/loraRegions'
import { resolveMeshDeviceImage } from '@/utils/meshDeviceImages'

const mesh = useMeshStore()
const appStore = useAppStore()
const router = useRouter()

const step = ref<1 | 2>(1)
const showAdvanced = ref(false)
const connecting = ref(false)
const error = ref('')

const devicePath = computed(() => mesh.undismissedDetectedDevices[0] ?? '')
const show = computed(() => !!devicePath.value)
const imageFailed = ref(false)
const deviceImage = computed(() =>
  resolveMeshDeviceImage(
    mesh.status?.detected_device_info?.find(d => d.path === devicePath.value)
  )
)

const suggestedRegion = computed(() => {
  const info = appStore.serverInfo as { lat?: number | null; lon?: number | null } | undefined
  if (info?.lat != null && info?.lon != null) {
    return suggestRegionFromLatLon(info.lat, info.lon)
  }
  return undefined
})

const form = ref({
  region: '',
  name: '',
  channel: 'archipelago',
  deviceKind: 'auto',
})

const selectedRegion = computed(() => regionByCode(form.value.region))
// The firmware whose options we surface: the explicit pin wins, else the
// last detected/connected type, else meshtastic-style (where presets apply).
const effectiveKind = computed(() => {
  if (form.value.deviceKind !== 'auto') return form.value.deviceKind
  const t = (mesh.status?.device_type ?? '').toLowerCase()
  return t === 'meshcore' || t === 'meshtastic' || t === 'reticulum' ? t : 'auto'
})
const meshcorePlan = computed(() => meshcorePlanFor(form.value.region))

// (Re)apply presets each time a new device surfaces the modal
watch(show, (visible) => {
  if (visible) {
    step.value = 1
    error.value = ''
    imageFailed.value = false
    form.value.region = suggestedRegion.value?.code ?? mesh.status?.lora_region ?? ''
    form.value.name = mesh.status?.self_advert_name ?? appStore.serverName ?? ''
    form.value.channel = mesh.status?.channel_name || 'archipelago'
    form.value.deviceKind = mesh.status?.device_kind ?? 'auto'
  }
})

function dismiss() {
  if (devicePath.value) mesh.dismissDetectedDevice(devicePath.value)
}

async function connect() {
  connecting.value = true
  error.value = ''
  try {
    const path = devicePath.value
    await mesh.configure({
      enabled: true,
      device_path: path,
      channel_name: form.value.channel.trim() || 'archipelago',
      ...(form.value.name.trim() ? { advert_name: form.value.name.trim() } : {}),
      ...(form.value.region ? { lora_region: form.value.region } : {}),
      device_kind: form.value.deviceKind,
    })
    mesh.dismissDetectedDevice(path)
    void router.push('/mesh')
  } catch (e) {
    error.value = e instanceof Error ? e.message : 'Failed to configure the mesh radio'
  } finally {
    connecting.value = false
  }
}
</script>

<style scoped>
.mesh-detect-waves path {
  animation: mesh-wave-pulse 2.2s ease-out infinite;
  opacity: 0;
}
.mesh-detect-waves path:nth-child(2) { animation-delay: 0.35s; }
.mesh-detect-waves path:nth-child(3) { animation-delay: 0.7s; }
@keyframes mesh-wave-pulse {
  0% { opacity: 0; }
  25% { opacity: 1; }
  100% { opacity: 0; }
}
</style>
