<template>
  <div class="flex min-h-[80vh] flex-col items-center justify-center p-6">
    <div class="kestrel-card-modal w-full max-w-md p-6">
      <h2 class="kestrel-section-heading mb-2">
        Share live (camera + location)
      </h2>
      <p class="mb-4 text-sm text-kestrel-muted">
        Use this page in Safari on your iPhone to stream your camera and location to the map. You'll appear as a live POI.
      </p>
      <div
        v-if="!isSecureContext"
        class="mb-4 rounded border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-sm text-amber-200"
      >
        <strong>HTTPS required.</strong> From your phone, camera and location only work over a secure connection. Open this app using an HTTPS URL (e.g. a tunnel like ngrok, or a server with an SSL certificate).
      </div>

      <!-- Status -->
      <div class="mb-4 rounded border border-kestrel-border bg-kestrel-bg px-3 py-2 text-sm text-kestrel-text">
        <p
          v-if="status"
          class="font-medium"
        >
          {{ status }}
        </p>
        <p
          v-if="webrtcState === 'connecting'"
          class="mt-1 text-kestrel-muted"
        >
          WebRTC: connecting…
        </p>
        <template v-if="webrtcState === 'failed'">
          <p class="mt-1 font-medium text-red-400">
            WebRTC: failed
          </p>
          <p
            v-if="webrtcFailureReason?.wrongHost"
            class="mt-1 text-amber-400"
          >
            Wrong host: server sees <strong>{{ webrtcFailureReason.wrongHost.serverHostname }}</strong> but you opened this page at <strong>{{ webrtcFailureReason.wrongHost.clientHostname }}</strong>. Use the same URL on phone and server, or set MEDIASOUP_ANNOUNCED_IP.
          </p>
          <ul class="mt-2 list-inside list-disc space-y-0.5 text-kestrel-muted">
            <li><strong>Firewall:</strong> Open UDP/TCP ports 40000-49999 on the server.</li>
            <li><strong>Wrong host:</strong> Server must see the same address you use (see above or open /api/live/debug-request-host).</li>
            <li><strong>Restrictive NAT / cellular:</strong> A TURN server may be required (future enhancement).</li>
          </ul>
        </template>
        <p
          v-if="error"
          class="mt-1 text-red-400"
        >
          {{ error }}
        </p>
      </div>

      <!-- Local preview -->
      <div
        v-if="stream && videoRef"
        class="kestrel-video-frame mb-4"
      >
        <video
          ref="videoRef"
          autoplay
          playsinline
          muted
          class="h-full w-full object-cover"
        />
        <div
          v-if="sharing"
          class="absolute bottom-2 left-2 rounded bg-black/70 px-2 py-1 text-xs text-green-400"
        >
          ● Live - you appear on the map
        </div>
      </div>

      <!-- Controls -->
      <div class="flex flex-col gap-2">
        <button
          v-if="!sharing"
          type="button"
          class="w-full rounded bg-kestrel-accent px-4 py-3 text-sm font-medium text-kestrel-bg transition-opacity hover:opacity-90 disabled:opacity-50"
          :disabled="starting"
          @click="startSharing"
        >
          {{ starting ? 'Starting…' : 'Start sharing' }}
        </button>
        <button
          v-else
          type="button"
          class="w-full rounded border border-red-400/60 bg-red-400/10 px-4 py-3 text-sm font-medium text-red-400 transition-opacity hover:bg-red-400/20"
          @click="stopSharing"
        >
          Stop sharing
        </button>
        <NuxtLink
          to="/"
          class="block text-center text-sm text-kestrel-muted underline hover:text-kestrel-accent"
        >
          Back to map
        </NuxtLink>
      </div>
    </div>
  </div>
</template>

<script setup>
import { createMediasoupDevice, createSendTransport } from '~/composables/useWebRTC.js'
import { getWebRTCFailureReason } from '~/composables/useWebRTCFailureReason.js'
import { initLogger, logError, logWarn } from '~/utils/logger.js'
import { useUser } from '~/composables/useUser.js'

definePageMeta({ layout: 'default' })

const { user } = useUser()

const videoRef = ref(null)
const stream = ref(null)
const sessionId = ref(null)
const status = ref('')
const error = ref('')
const sharing = ref(false)
const starting = ref(false)
const isSecureContext = typeof window !== 'undefined' && window.isSecureContext
const webrtcState = ref('') // '', 'connecting', 'connected', 'failed'
const webrtcFailureReason = ref(null) // { wrongHost: { serverHostname, clientHostname } | null }
const locationWatchId = ref(null)
const locationIntervalId = ref(null)
const device = ref(null)
const sendTransport = ref(null)
const producer = ref(null)

async function runFailureReasonCheck() {
  webrtcFailureReason.value = await getWebRTCFailureReason()
}

function setStatus(msg) {
  status.value = msg
  error.value = ''
}

function setError(msg) {
  error.value = msg
}

async function startSharing() {
  starting.value = true
  setStatus('Requesting camera and location…')
  setError('')

  try {
    // 1. Start live session on server
    const session = await $fetch('/api/live/start', {
      method: 'POST',
      body: {},
    })
    sessionId.value = session.id
    // Initialize logger with session and user context
    initLogger(session.id, user.value?.id)
    setStatus('Session started. Requesting camera…')

    // 2. Get camera if available (requires HTTPS on mobile Safari)
    const hasMediaDevices = typeof navigator !== 'undefined' && navigator.mediaDevices != null
    if (!hasMediaDevices) {
      setError('Media devices not available. HTTPS required.')
      cleanup()
      return
    }

    let mediaStream = null
    try {
      mediaStream = await navigator.mediaDevices.getUserMedia({
        video: {
          facingMode: 'environment',
          width: { ideal: 1280 },
          height: { ideal: 720 },
        },
        audio: false,
      })
      stream.value = mediaStream
      if (videoRef.value) {
        videoRef.value.srcObject = mediaStream
      }
      setStatus('Camera on. Setting up WebRTC…')
    }
    catch {
      setError('Camera denied or unavailable. Allow camera access in browser settings.')
      cleanup()
      return
    }

    // 3. Initialize Mediasoup device and create WebRTC transport
    try {
      webrtcState.value = 'connecting'
      webrtcFailureReason.value = null
      const rtpCapabilities = await $fetch(`/api/live/webrtc/router-rtp-capabilities?sessionId=${sessionId.value}`, {
        credentials: 'include',
      })
      device.value = await createMediasoupDevice(rtpCapabilities)
      sendTransport.value = await createSendTransport(device.value, sessionId.value, {
        onConnectSuccess: () => { webrtcState.value = 'connected' },
        onConnectFailure: () => {
          webrtcState.value = 'failed'
          runFailureReasonCheck()
        },
      })

      // 4. Produce video track
      const videoTrack = mediaStream.getVideoTracks()[0]
      if (!videoTrack) {
        throw new Error('No video track available')
      }
      producer.value = await sendTransport.value.produce({ track: videoTrack })
      // Monitor producer events
      producer.value.on('transportclose', () => {
        logWarn('share-live: Producer transport closed', {
          producerId: producer.value.id,
          producerPaused: producer.value.paused,
          producerClosed: producer.value.closed,
        })
      })
      producer.value.on('trackended', () => {
        logWarn('share-live: Producer track ended', {
          producerId: producer.value.id,
          producerPaused: producer.value.paused,
          producerClosed: producer.value.closed,
        })
      })
      // Monitor transport state (mediasoup-client does not pass a parameter; read from transport.connectionState)
      sendTransport.value.on('connectionstatechange', () => {
        const state = sendTransport.value.connectionState
        if (state === 'connected') webrtcState.value = 'connected'
        else if (state === 'failed' || state === 'disconnected' || state === 'closed') {
          logWarn('share-live: Send transport connection state changed', {
            state,
            transportId: sendTransport.value.id,
            producerId: producer.value.id,
          })
          if (state === 'failed') {
            webrtcState.value = 'failed'
            runFailureReasonCheck()
          }
        }
      })
      // Monitor track state
      if (producer.value.track) {
        producer.value.track.addEventListener('ended', () => {
          logWarn('share-live: Producer track ended', {
            producerId: producer.value.id,
            trackId: producer.value.track.id,
            trackReadyState: producer.value.track.readyState,
            trackEnabled: producer.value.track.enabled,
            trackMuted: producer.value.track.muted,
          })
        })
        producer.value.track.addEventListener('mute', () => {
          logWarn('share-live: Producer track muted', {
            producerId: producer.value.id,
            trackId: producer.value.track.id,
            trackEnabled: producer.value.track.enabled,
            trackMuted: producer.value.track.muted,
          })
        })
        producer.value.track.addEventListener('unmute', () => {})
      }
      webrtcState.value = 'connected'
      setStatus('WebRTC connected. Requesting location…')
    }
    catch (webrtcErr) {
      logError('share-live: WebRTC setup error', { err: webrtcErr.message || String(webrtcErr), stack: webrtcErr.stack })
      webrtcState.value = 'failed'
      runFailureReasonCheck()
      setError('Failed to set up video stream: ' + (webrtcErr.message || String(webrtcErr)))
      cleanup()
      return
    }

    // 5. Get location (continuous) - also requires HTTPS on mobile Safari
    if (!navigator.geolocation) {
      setError('Geolocation not supported in this browser.')
      cleanup()
      return
    }
    try {
      await new Promise((resolve, reject) => {
        locationWatchId.value = navigator.geolocation.watchPosition(
          (pos) => {
            resolve(pos)
          },
          (err) => {
            reject(err)
          },
          { enableHighAccuracy: true, maximumAge: 0, timeout: 10000 },
        )
      })
    }
    catch (locErr) {
      const msg = locErr?.code === 1 || (locErr?.message && locErr.message.toLowerCase().includes('permission'))
        ? 'Camera and location require a secure connection (HTTPS) when using this page from your phone. Open this app via an HTTPS URL (e.g. use a tunnel or a server with SSL).'
        : (locErr?.message || 'Location was denied or unavailable.')
      setError(msg)
      cleanup()
      return
    }
    setStatus('Location enabled. Streaming live…')
    sharing.value = true
    starting.value = false

    // 6. Send location updates periodically (video is handled by WebRTC)
    let locationUpdate404Logged = false
    const sendLocationUpdate = async () => {
      if (!sessionId.value || !sharing.value) return
      const id = sessionId.value
      const pos = await new Promise((resolve, reject) => {
        navigator.geolocation.getCurrentPosition(resolve, reject, {
          enableHighAccuracy: true,
          maximumAge: 2000,
          timeout: 5000,
        })
      }).catch(() => null)
      const lat = pos?.coords?.latitude
      const lng = pos?.coords?.longitude

      if (Number.isFinite(lat) && Number.isFinite(lng)) {
        try {
          await $fetch(`/api/live/${id}`, {
            method: 'PATCH',
            body: {
              lat,
              lng,
            },
            credentials: 'include',
          })
        }
        catch (e) {
          if (e?.statusCode === 404) {
            if (locationIntervalId.value != null) {
              clearInterval(locationIntervalId.value)
              locationIntervalId.value = null
            }
            sharing.value = false
            if (!locationUpdate404Logged) {
              locationUpdate404Logged = true
              logWarn('share-live: Session ended (404), stopping location updates', { sessionId: id })
            }
          }
          else {
            logWarn('share-live: Live location update failed', { err: e.message || String(e) })
          }
        }
      }
    }

    await sendLocationUpdate()
    locationIntervalId.value = setInterval(sendLocationUpdate, 2000)
  }
  catch (e) {
    starting.value = false
    if (e?.message) setError(e.message)
    else if (e?.name === 'NotAllowedError') setError('Camera or location was denied. Allow in Safari settings.')
    else if (e?.name === 'NotFoundError') setError('No camera found.')
    else setError('Failed to start: ' + String(e))
    cleanup()
  }
}

function cleanup() {
  if (locationWatchId.value != null && navigator.geolocation?.clearWatch) {
    navigator.geolocation.clearWatch(locationWatchId.value)
  }
  locationWatchId.value = null
  if (locationIntervalId.value != null) {
    clearInterval(locationIntervalId.value)
  }
  locationIntervalId.value = null
  if (producer.value) {
    producer.value.close()
    producer.value = null
  }
  if (sendTransport.value) {
    sendTransport.value.close()
    sendTransport.value = null
  }
  device.value = null
  if (stream.value) {
    stream.value.getTracks().forEach(t => t.stop())
    stream.value = null
  }
  if (sessionId.value) {
    $fetch(`/api/live/${sessionId.value}`, { method: 'DELETE' }).catch(() => {})
    sessionId.value = null
  }
  sharing.value = false
  webrtcState.value = ''
  webrtcFailureReason.value = null
}

async function stopSharing() {
  setStatus('Stopping…')
  cleanup()
  setStatus('')
  setError('')
}

onBeforeUnmount(() => {
  cleanup()
})
</script>
