[Back]
@extends('layout')

@section('title')
  <title>{{ $floor->name }} — Map</title>
@endsection

@section('content')
<section class="container py-4">

  {{-- @if(app()->environment('local'))
    <a class="btn btn-warning btn-sm mb-3" href="{{ route('map.coords', $floor->slug) }}">
      Trace hotspots on {{ $floor->name }}
    </a>
  @endif --}}

  {{-- Top bar: floor tabs + Scan QR --}}
  <div class="d-flex align-items-center justify-content-between mb-3 flex-wrap gap-2">
    <ul class="nav nav-pills">
      @foreach($floors as $f)
        <li class="nav-item">
          <a class="nav-link {{ $f->id === $floor->id ? 'active' : '' }}" href="{{ route('map.show', $f->slug) }}">
            {{ $f->name }}
          </a>
        </li>
      @endforeach
    </ul>
    <a href="{{ route('nav.scan') }}" class="btn btn-outline-primary btn-sm">Scan QR</a>
  </div>

  @if(session('status'))
    <div class="alert alert-info mb-3">{{ session('status') }}</div>
  @endif

  <div class="card shadow-sm">
    <div class="card-body">
      <div class="w-100" style="max-width: 1100px; margin: 0 auto;">
        <div class="ratio" style="--bs-aspect-ratio: calc({{ $floor->height }} / {{ $floor->width }} * 100%);">

          <svg xmlns="http://www.w3.org/2000/svg"
               viewBox="0 0 {{ $floor->width }} {{ $floor->height }}"
               class="w-100 h-100" role="img" aria-label="{{ $floor->name }}">

            {{-- Arrowhead for animated first leg --}}
            <defs>
              <marker id="arrow-next"
                      markerWidth="4" markerHeight="4"
                      refX="4" refY="2"
                      orient="auto"
                      markerUnits="strokeWidth">
                <path d="M0,0 L4,2 L0,4 Z" fill="#198754" />
              </marker>
            </defs>

            {{-- Background --}}
            <image href="{{ asset($floor->image_path) }}"
                   x="0" y="0" width="{{ $floor->width }}" height="{{ $floor->height }}"
                   preserveAspectRatio="xMidYMid meet" />

            {{-- Hotspots --}}
            <g class="hotspots">
              @foreach($areas as $a)
                @php $href = $a->href ?: '#'; @endphp
                <a href="{{ $href }}" aria-label="{{ $a->name }}">
                  @switch($a->shape)
                    @case('rect') <rect class="hotspot" x="{{ $a->x }}" y="{{ $a->y }}" width="{{ $a->width }}" height="{{ $a->height }}" /> @break
                    @case('path') <path class="hotspot" d="{{ $a->d }}" /> @break
                    @default      <polygon class="hotspot" points="{{ $a->points }}" />
                  @endswitch
                  <title>{{ $a->name }}</title>
                </a>
              @endforeach
            </g>

            {{-- All checkpoints on this floor (faint) --}}
            <g class="floor-cp">
              @foreach($floorCheckpoints as $cp)
                <g transform="translate({{ $cp->x }}, {{ $cp->y }})">
                  <circle r="4" class="cp-faint" />
                </g>
              @endforeach
            </g>

            {{-- ROUTE baseline (dotted) --}}
            <g class="route-layer">
              @if(!empty($segmentsByFloor[$floor->id]))
                @php
                  $pointsArr = [];
                  foreach ($segmentsByFloor[$floor->id] as $pair) {
                    $pair = trim($pair);
                    if ($pair==='') continue;
                    foreach (explode(' ', $pair) as $pt) if ($pt!=='') $pointsArr[] = $pt;
                  }
                  $clean = []; $last=null;
                  foreach ($pointsArr as $pt){ if ($pt !== $last) $clean[] = $pt; $last = $pt; }
                  $pointsStr = implode(' ', $clean);
                @endphp
                @if($pointsStr !== '')
                  <polyline class="route dotted" points="{{ $pointsStr }}" />
                @endif
              @endif

              {{-- Animated first leg (current -> next) --}}
              @if(!empty($blinkSegmentPointsByFloor[$floor->id]))
                <polyline class="route march-line"
                          points="{{ $blinkSegmentPointsByFloor[$floor->id] }}"
                          marker-end="url(#arrow-next)" />
              @endif

              {{-- Numbered route checkpoints (global numbering) --}}
              @if(!empty($routeCpsByFloor[$floor->id]))
                @foreach($routeCpsByFloor[$floor->id] as $rcp)
                  <g transform="translate({{ $rcp->x }}, {{ $rcp->y }})" class="route-cp">
                    <circle r="8" class="route-cp-dot" />
                    <text y="4" text-anchor="middle" class="route-cp-num">
                      {{ $routeStepIndex[$rcp->id] ?? '' }}
                    </text>
                  </g>
                @endforeach
              @endif

              {{-- CURRENT (blinking) --}}
              @if($currentDot && $currentCp && $currentCp->floor_id === $floor->id)
                <g>
                  <circle class="current blink" cx="{{ $currentDot['x'] }}" cy="{{ $currentDot['y'] }}" r="9" />
                  <text x="{{ $currentDot['x'] }}" y="{{ $currentDot['y'] + 18 }}"
                        text-anchor="middle" font-size="12" fill="#212529">You are here</text>
                </g>
              @endif

              {{-- DESTINATION --}}
              @if($destDot && $destCp && $destCp->floor_id === $floor->id)
                <g>
                  <circle class="dest" cx="{{ $destDot['x'] }}" cy="{{ $destDot['y'] }}" r="8" />
                  <text x="{{ $destDot['x'] + 14 }}" y="{{ $destDot['y'] - 12 }}" font-size="12" fill="#212529">{{ $destCp->name }}</text>
                </g>
              @endif
            </g>

          </svg>
        </div>
      </div>

      {{-- Status & actions --}}
      <div class="d-flex flex-wrap gap-2 align-items-center mt-3">
        @if($currentCp)<span class="badge text-bg-secondary">Current: {{ $currentCp->name }}</span>@endif
        @if($destCp)<span class="badge text-bg-primary">Destination: {{ $destCp->name }}</span>@endif
        @if(!empty($nextInstruction)) <span class="ms-2 small text-muted">Next: {{ $nextInstruction }}</span> @endif

        <div class="ms-auto d-flex flex-wrap gap-2 align-items-center">
          {{-- Voice controls --}}
          <div class="form-check form-switch me-2">
            <input class="form-check-input" type="checkbox" id="voiceToggle">
            <label class="form-check-label" for="voiceToggle">Enable voice</label>
          </div>
          <button id="voiceReplay" class="btn btn-sm btn-outline-primary" type="button">Replay</button>

          {{-- Manual "I'm here" setter --}}
          <form method="POST" action="{{ route('nav.set') }}" class="d-flex gap-2 ms-3">
            @csrf
            <select name="slug" class="form-select form-select-sm">
              <option value="">I’m here…</option>
              @foreach($floorCheckpoints as $cp)
                <option value="{{ $cp->slug }}">{{ $cp->name }}</option>
              @endforeach
            </select>
            <button class="btn btn-sm btn-outline-success" type="submit">Set</button>
          </form>

          @php
            $currentFloorSlug = $currentCp ? ($floors->firstWhere('id', $currentCp->floor_id)->slug ?? null) : null;
            $destFloorSlug    = $destCp ? ($floors->firstWhere('id', $destCp->floor_id)->slug ?? null) : null;
          @endphp
          @if($currentFloorSlug && $currentFloorSlug !== $floor->slug)
            <a class="btn btn-sm btn-outline-secondary" href="{{ route('map.show', $currentFloorSlug) }}">Go to Current Floor</a>
          @endif
          @if($destFloorSlug && $destFloorSlug !== $floor->slug)
            <a class="btn btn-sm btn-outline-primary" href="{{ route('map.show', $destFloorSlug) }}">Go to Destination Floor</a>
          @endif
          <a href="{{ route('nav.clear') }}" class="btn btn-sm btn-outline-danger">Clear navigation</a>
        </div>
      </div>

      <div class="d-flex gap-2 mt-3">
        <a href="{{ url('/home') }}" class="btn btn-outline-secondary">Back to Menu</a>
      </div>
    </div>
  </div>
</section>

{{-- VOICE (auto-speak on ?s=1 or after QR) --}}
<div id="voice-nudge" class="voice-nudge d-none">🔊 Tap to enable voice guidance</div>
{{-- <script>
(function() {
  const steps = @json($ttsSteps ?? []);
  const lang  = @json($ttsLang ?? 'en-US');

  const toggle = document.getElementById('voiceToggle');
  const replay = document.getElementById('voiceReplay');
  const nudge  = document.getElementById('voice-nudge');

  const enabledKey  = 'map_voice_enabled';
  const unlockedKey = 'map_voice_unlocked';

  // Want to auto-speak? (from nav/qr/scan we append s=1)
  const params = new URLSearchParams(window.location.search);
  const wantSpeak = params.has('s') || params.get('speak') === '1';

  // Restore state
  const wasEnabled  = localStorage.getItem(enabledKey) === '1';
  let   isUnlocked  = sessionStorage.getItem(unlockedKey) === '1';

  // If asked to speak, default enable voice for the user
  const enableNow = wasEnabled || wantSpeak;
  localStorage.setItem(enabledKey, enableNow ? '1' : '0');
  toggle.checked = enableNow;

  function speak(text) {
    if (!text) return;
    if (!('speechSynthesis' in window)) return;
    window.speechSynthesis.cancel();

    const u = new SpeechSynthesisUtterance(text);
    u.lang   = lang; u.rate = 1; u.pitch = 1; u.volume = 1;

    function pickVoiceAndSpeak() {
      const voices = window.speechSynthesis.getVoices() || [];
      let v = voices.find(v => v.lang === lang)
           || voices.find(v => v.lang && v.lang.startsWith(lang.split('-')[0]))
           || voices.find(v => /en-/i.test(v.lang))
           || voices[0];
      if (v) u.voice = v;
      window.speechSynthesis.speak(u);
    }

    if (window.speechSynthesis.getVoices().length === 0) {
      window.speechSynthesis.onvoiceschanged = pickVoiceAndSpeak;
    } else {
      pickVoiceAndSpeak();
    }
  }

  // Unlock on first real gesture
  ['click','touchstart','keydown'].forEach(evt => {
    document.addEventListener(evt, () => {
      sessionStorage.setItem(unlockedKey, '1');
      isUnlocked = true;
      if (!nudge.classList.contains('d-none') && toggle.checked && steps.length) {
        nudge.classList.add('d-none');
        speak(steps[0]);
      }
    }, { once:true, capture:true });
  });

  // Toggle & replay
  toggle.addEventListener('change', () => {
    localStorage.setItem(enabledKey, toggle.checked ? '1' : '0');
    if (toggle.checked) {
      sessionStorage.setItem(unlockedKey, '1');
      isUnlocked = true;
      if (steps.length) speak(steps[0]);
    } else {
      window.speechSynthesis.cancel();
    }
  });
  replay.addEventListener('click', () => {
    if (toggle.checked && steps.length) speak(steps[0]);
  });

  // Try to auto-speak on load if enabled + unlocked
  function tryAutoSpeakOnce() {
    if (!toggle.checked || !steps.length) return;
    if (isUnlocked) {
      setTimeout(() => speak(steps[0]), 120);
    } else if (wantSpeak) {
      // Show a one-tap nudge if the browser blocks autoplay (external camera QR case)
      nudge.classList.remove('d-none');
    }
  }
  window.addEventListener('pageshow', tryAutoSpeakOnce);
  if (document.visibilityState === 'visible') tryAutoSpeakOnce();
})();
</script> --}}

<script>
  (function () {
    const steps = @json($ttsSteps ?? []);
    const lang  = @json($ttsLang ?? 'en-US');
  
    const toggle = document.getElementById('voiceToggle');
    const replay = document.getElementById('voiceReplay');
    const nudge  = document.getElementById('voice-nudge');
  
    const LS_ENABLED = 'map_voice_enabled';
    const SS_UNLOCK  = 'map_voice_unlocked';
    const LS_PREOK   = 'map_voice_preapproved';
  
    const params      = new URLSearchParams(location.search);
    const wantSpeak   = params.has('s') || params.get('speak') === '1';
    const wasEnabled  = localStorage.getItem(LS_ENABLED) === '1';
    const preapproved = localStorage.getItem(LS_PREOK) === '1';
    let   isUnlocked  = sessionStorage.getItem(SS_UNLOCK) === '1';
  
    // Default enable when asked to speak
    const enableNow = wasEnabled || wantSpeak;
    localStorage.setItem(LS_ENABLED, enableNow ? '1' : '0');
    toggle.checked = enableNow;
  
    // ======== tuning: shorter delay & faster retries ========
    const RETRY_INTERVAL_MS = 150;   // was 400ms
    const MAX_TRIES         = 20;    // ~3s total
    const RAPID_ATTEMPTS    = 3;     // 3 immediate RAF attempts
    // ========================================================
  
    let speakTimer  = null;
    let speakTries  = 0;
    let speakingNow = false;
  
    // Pre-warm voices (helps some browsers load voices synchronously)
    try { void window.speechSynthesis.getVoices(); } catch {}
  
    function pickVoice(u) {
      const voices = window.speechSynthesis.getVoices() || [];
      return (
        voices.find(v => v.lang === lang) ||
        voices.find(v => v.lang && v.lang.startsWith(lang.split('-')[0])) ||
        voices.find(v => /en-/i.test(v.lang)) ||
        voices[0] || null
      );
    }
  
    function actuallySpeak(text) {
      if (!text || !('speechSynthesis' in window)) return false;
  
      try { window.speechSynthesis.resume(); } catch {}
      // Only cancel if we’re not already speaking; avoids cutting off first start
      if (!speakingNow) window.speechSynthesis.cancel();
  
      const u = new SpeechSynthesisUtterance(text);
      u.lang = lang; u.rate = 1; u.pitch = 1; u.volume = 1;
  
      u.onstart = () => {
        speakingNow = true;
        localStorage.setItem(LS_PREOK, '1');
        nudge.classList.add('d-none');
      };
      u.onend = () => { speakingNow = false; };
      u.onerror = () => { speakingNow = false; };
  
      const v = pickVoice(u);
      if (v) u.voice = v;
  
      try {
        window.speechSynthesis.speak(u);
        return true;
      } catch {
        return false;
      }
    }
  
    function stopRetry() {
      if (speakTimer) { clearInterval(speakTimer); speakTimer = null; }
    }
  
    // 3 super-fast attempts via RAF to minimize perceived delay
    function rapidAttemptsThenRetry() {
      let left = RAPID_ATTEMPTS;
      function tick() {
        if (!toggle.checked || !steps.length) return;
        if (actuallySpeak(steps[0])) return; // success — stop
        left--;
        if (left > 0) requestAnimationFrame(tick);
        else startRetryLoop();
      }
      requestAnimationFrame(tick);
    }
  
    function startRetryLoop() {
      speakTries = 0;
      speakTimer = setInterval(() => {
        if (speakingNow) { stopRetry(); return; }
        speakTries++;
        try { window.speechSynthesis.resume(); } catch {}
        const ok = actuallySpeak(steps[0]);
        if (ok || speakTries >= MAX_TRIES) {
          stopRetry();
          if (!ok) nudge.classList.remove('d-none'); // needs one tap
        }
      }, RETRY_INTERVAL_MS);
    }
  
    function tryAutoSpeakNow() {
      if (!toggle.checked || !steps.length) return;
      // Immediate attempt first (no delay)
      if (actuallySpeak(steps[0])) return;
      // Rapid attempts (~0–50ms), then tight retry loop
      rapidAttemptsThenRetry();
    }
  
    // First user gesture unlocks this tab
    ['click','touchstart','keydown'].forEach(evt => {
      document.addEventListener(evt, () => {
        sessionStorage.setItem(SS_UNLOCK, '1');
        isUnlocked = true;
        if (toggle.checked && steps.length) {
          nudge.classList.add('d-none');
          tryAutoSpeakNow();
        }
      }, { once:true, capture:true });
    });
  
    // Toggle & replay
    toggle.addEventListener('change', () => {
      localStorage.setItem(LS_ENABLED, toggle.checked ? '1' : '0');
      if (toggle.checked) {
        sessionStorage.setItem(SS_UNLOCK, '1');
        isUnlocked = true;
        tryAutoSpeakNow();
      } else {
        window.speechSynthesis.cancel();
        stopRetry();
      }
    });
    replay.addEventListener('click', () => {
      tryAutoSpeakNow();
    });
  
    // Auto-speak on load if there’s any chance
    function maybeAutoSpeak() {
      if (!toggle.checked || !steps.length) return;
      const canTry = wantSpeak && (isUnlocked || preapproved);
      if (canTry) {
        tryAutoSpeakNow();
      } else if (wantSpeak) {
        // Even without unlock, try immediately; if blocked, we’ll show nudge
        tryAutoSpeakNow();
      }
    }
  
    window.addEventListener('pageshow', maybeAutoSpeak);
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible') maybeAutoSpeak();
    });
    if (document.visibilityState === 'visible') maybeAutoSpeak();
  
  })();
</script>
  
   

<style>
  /* hotspots */
  .hotspots .hotspot { fill: rgba(0,0,0,0); stroke: rgba(0,0,0,0.28); stroke-width: 2; cursor: pointer; transition: fill .15s, stroke .15s; }
  .hotspots a:hover .hotspot, .hotspots a:focus .hotspot { fill: rgba(13,110,253,.18); stroke: rgba(13,110,253,.85); }

  /* faint checkpoints */
  .cp-faint { fill:#6c757d; opacity:.35; }

  /* dotted route */
  .route-layer .route.dotted { fill:none; stroke:#198754; stroke-width:6; stroke-linecap:round; stroke-linejoin:round; pointer-events:none; stroke-dasharray:1 14; opacity:.5; }
  .route-layer .march-line   { fill:none; stroke:#198754; stroke-width:6; stroke-linecap:round; stroke-linejoin:round; pointer-events:none; stroke-dasharray:1 14; animation:march .9s linear infinite; }

  /* numbered route checkpoints */
  .route-cp .route-cp-dot { fill:#fff; stroke:#198754; stroke-width:3; }
  .route-cp .route-cp-num { font-size:11px; fill:#198754; font-weight:700; text-shadow:0 1px 0 #fff; }

  /* markers */
  .route-layer .current, .route-layer .dest { stroke:#fff; stroke-width:2; pointer-events:none; }
  .route-layer .current { fill:#dc3545; }
  .route-layer .dest    { fill:#0d6efd; }

  /* blink for current */
  .blink { animation: blink 1s steps(2, start) infinite; }

  /* voice nudge */
  .voice-nudge { position: fixed; inset:auto 16px 16px 16px; background:#0d6efd; color:#fff; padding:10px 14px; border-radius:12px; box-shadow:0 6px 20px rgba(0,0,0,.2); text-align:center; font-weight:600; z-index: 9999; }
  .d-none { display:none !important; }

  /* animations */
  @keyframes march { to { stroke-dashoffset: -15; } }
  @keyframes blink { to { opacity: 0; } }

  @media (prefers-reduced-motion: reduce) {
    .blink, .route-layer .march-line { animation: none; }
  }
</style>
@endsection