<script>
  import { onMount, onDestroy } from 'svelte'
  import StatusBar from './components/StatusBar.svelte'
  import WorldMap from './components/WorldMap.svelte'
  import SatSelector from './components/SatSelector.svelte'
  import PassesPanel from './components/PassesPanel.svelte'
  import SettingsPanel from './components/SettingsPanel.svelte'
  import PolarPlot from './components/PolarPlot.svelte'
  import { Go, onWailsEvent } from './lib/wails.js'
  import { get } from 'svelte/store'
  import { satPositions, satList, trackedSat, trackedPosition, passes, tleAge, tleLoaded, flexConnected, rotorConnected, skycatConnected, settings, watchlist, soundEnabled, passesAllCache } from './stores/satstore.js'

  let activeTab = 'map'
  let cleanups = []
  let mapComponent

  import { dopplerEnabled, rotorEnabled } from './stores/satstore.js'
  import { getDisplayName } from './lib/satdb.js'

  // Sync toggles → Go backend
  $: Go.SetDopplerEnabled($dopplerEnabled)
  $: Go.SetRotorEnabled($rotorEnabled)

  onMount(async () => {
    const s = $settings
    await Go.SetObserverLocation(s.qthLat, s.qthLon, s.qthAlt)
    await Go.SetSatelliteFrequencies(s.downlinkHz, s.uplinkHz)

    if (s.autoConnectFlex) {
      const res = await Go.ConnectFlexRadio(s.flexHost, s.flexPort)
      if (res === 'OK') {
        flexConnected.set(true)
        // Apply slice config from settings immediately after connect
        const rx = s.rxSlice ?? 0
        const tx = s.txSlice ?? 1
        await Go.SetSliceConfig(rx, tx)
      }
    }
    if (s.autoConnectRotor) {
      const res = await Go.ConnectRotor(s.rotorHost, s.rotorPort)
      if (res === 'OK') {
        rotorConnected.set(true)
        await Go.SetRotorAzOnly(s.rotorAzOnly ?? true)
      }
    }
    if (s.autoConnectSkycat && s.radioType === 'skycat') {
      const res = await Go.ConnectSkyCAT(s.skycatHost, s.skycatPort)
      if (res === 'OK') {
        skycatConnected.set(true)
        await Go.SetSkyCATMode(s.skycatSatMode || 'Duplex')
      }
    }
    // Sync radio type to backend on startup
    if (s.radioType) await Go.SetRadioType(s.radioType)

    const names = await Go.GetSatelliteList()
    if (names) satList.set(names)
    const age = await Go.GetTLEAge()
    if (age !== null) tleAge.set(age)
    await Go.SetWatchlist($watchlist)

    cleanups.push(onWailsEvent('sat:positions', p => satPositions.set(p)))
    cleanups.push(onWailsEvent('tle:loaded', names => {
      satList.set(names); tleLoaded.set(true)
      Go.GetTLEAge().then(a => tleAge.set(a))
    }))
  })

  onDestroy(() => cleanups.forEach(fn => fn?.()))

  function handleKey(e) {
    if (e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT') return
    if (e.key === 'm' || e.key === 'M') activeTab = 'map'
    if (e.key === 'p' || e.key === 'P') activeTab = 'passes'
    if (e.key === 's' || e.key === 'S') activeTab = 'settings'
  }

  $: currentAz = $trackedPosition?.az ?? null
  $: currentEl = $trackedPosition?.el ?? null

  // ── AOS Voice Alert Engine ──────────────────────────────────────────────
  // Track previous elevation for each sat to detect the neg→pos crossing
  let _prevElevations = {}

  // Pick voice: use persisted setting, fallback to best English voice
  function getVoice() {
    const voices = window.speechSynthesis.getVoices()
    const saved = $settings.ttsVoiceName
    if (saved) {
      const v = voices.find(v => v.name === saved)
      if (v) return v
    }
    // Fallback: preferred Windows English voices
    const preferred = ['Microsoft David', 'Microsoft Zira', 'Microsoft Mark', 'Microsoft James', 'Microsoft Linda', 'Microsoft George', 'Microsoft Hazel']
    for (const name of preferred) {
      const v = voices.find(v => v.name.startsWith(name))
      if (v) return v
    }
    return voices.find(v => v.lang === 'en-US' || v.lang === 'en-GB') || null
  }

  function announceAOS(satName, durationSecs) {
    if (!window.speechSynthesis) return
    const display = getDisplayName(satName)
    const mins = Math.round(durationSecs / 60)
    const text = `AOS ${display} is rising. Pass will last for ${mins} minute${mins !== 1 ? 's' : ''}.`
    const utt = new SpeechSynthesisUtterance(text)
    utt.lang = 'en-US'
    utt.rate = 0.95
    utt.pitch = 1.0
    utt.volume = 1.0
    const voice = getVoice()
    if (voice) utt.voice = voice
    window.speechSynthesis.cancel()
    window.speechSynthesis.speak(utt)
  }

  // Watch satPositions for AOS crossings on all watchlist sats
  satPositions.subscribe(positions => {
    if (!positions || !$soundEnabled) return
    const wl = new Set($watchlist)
    for (const pos of positions) {
      if (!wl.has(pos.name)) continue
      const prev = _prevElevations[pos.name]
      const curr = pos.el
      // Detect crossing from below horizon to above (neg → pos)
      if (prev !== undefined && prev < 0 && curr >= 0) {
        // Find pass duration from passesAllCache or tracked sat passes
        let durationSecs = 600 // fallback 10 min
        const now = Date.now()
        const allCache = get(passesAllCache)
        const trackedPasses = get(passes)
        const allAvail = [...(allCache || []), ...(trackedPasses || []).map(p => ({...p, satName: get(trackedSat)}))]
        const match = allAvail.find(p =>
          p.satName === pos.name &&
          new Date(p.aos).getTime() <= now + 30000 &&
          new Date(p.los).getTime() >= now
        )
        if (match?.duration) durationSecs = match.duration
        announceAOS(pos.name, durationSecs)
      }
      _prevElevations[pos.name] = curr
    }
  })
</script>

<svelte:window on:keydown={handleKey} />
<svelte:head>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
</svelte:head>

<div class="app">
  <StatusBar />

  <div class="main">
    <!-- Left sidebar -->
    <aside class="sidebar">
      <div class="sidebar-hdr">
        <div class="logo-wrap">
          <div class="logo-icon">🛰</div>
          <div>
            <div class="logo-text">SatMaster</div>
            <div class="logo-sub">Satellite Tracker</div>
          </div>
        </div>
      </div>
      <SatSelector />
    </aside>

    <!-- Main content -->
    <main class="center">
      <nav class="tabs">
        <button class="tab {activeTab==='map'?'on':''}" on:click={() => activeTab='map'}>
          <span class="tab-icon">🗺</span> World Map
        </button>
        <button class="tab {activeTab==='passes'?'on':''}" on:click={() => activeTab='passes'}>
          <span class="tab-icon">📡</span> Passes
        </button>
        <button class="tab {activeTab==='settings'?'on':''}" on:click={() => activeTab='settings'}>
          <span class="tab-icon">⚙️</span> Settings
        </button>
      </nav>

      <div class="panel-stack">
        <!-- Map: always in DOM, hidden via visibility when not active so Leaflet keeps its size -->
        <div class="panel" class:panel-hidden={activeTab !== 'map'}>
          <WorldMap bind:this={mapComponent}/>
          {#if $trackedSat && activeTab === 'map'}
            <div class="polar-ov">
              <PolarPlot points={$passes[0]?.points||[]} currentAz={currentAz} currentEl={currentEl} satName={$trackedSat} size={200}/>
            </div>
          {/if}
        </div>

        {#if activeTab === 'passes'}
          <div class="panel">
            <PassesPanel currentAz={currentAz} currentEl={currentEl}/>
          </div>
        {/if}

        {#if activeTab === 'settings'}
          <div class="panel">
            <SettingsPanel/>
          </div>
        {/if}
      </div>
    </main>
  </div>
</div>

<style>
  :global(*,*::before,*::after){box-sizing:border-box;margin:0;padding:0}
  :global(body){background:#f0f2f5;overflow:hidden;user-select:none;-webkit-user-select:none;font-family:'Inter',system-ui,sans-serif}
  :global(::-webkit-scrollbar){width:5px}
  :global(::-webkit-scrollbar-track){background:#f0f2f5}
  :global(::-webkit-scrollbar-thumb){background:#c0ccd8;border-radius:3px}

  .app { display:flex; flex-direction:column; height:100vh; width:100vw; background:#f0f2f5; }
  .main { display:flex; flex:1; overflow:hidden; min-height:0; gap:12px; padding:0 12px 12px; }

  /* Sidebar */
  .sidebar {
    width:280px; flex-shrink:0;
    display:flex; flex-direction:column;
    background:white; border-radius:12px;
    box-shadow:0 1px 4px rgba(0,0,0,0.08);
    overflow:hidden; margin-top:8px;
  }
  .sidebar-hdr {
    padding:14px 16px; border-bottom:1px solid #e8edf2;
    background:white; flex-shrink:0;
  }
  .logo-wrap { display:flex; align-items:center; gap:10px; }
  .logo-icon { font-size:24px; }
  .logo-text { font-size:15px; font-weight:700; color:#1a2a3a; letter-spacing:-.01em; }
  .logo-sub  { font-size:10px; color:#7a9ab8; margin-top:1px; }

  /* Center */
  .center {
    flex:1; display:flex; flex-direction:column;
    overflow:hidden; min-width:0; min-height:0;
    margin-top:8px;
  }

  /* Tabs */
  .tabs {
    display:flex; gap:4px;
    background:white; border-radius:10px;
    padding:6px; margin-bottom:8px;
    box-shadow:0 1px 4px rgba(0,0,0,0.06);
    flex-shrink:0;
  }
  .tab {
    display:flex; align-items:center; gap:6px;
    background:none; border:none;
    color:#6a8aa8; font-family:'Inter',sans-serif;
    font-size:13px; font-weight:500;
    padding:8px 16px; border-radius:7px;
    cursor:pointer; transition:all .15s;
  }
  .tab:hover { background:#f0f4f8; color:#1a2a3a; }
  .tab.on { background:#1a5a9a; color:white; font-weight:600; }
  .tab-icon { font-size:14px; }

  /* Panel stack */
  .panel-stack { position:relative; flex:1; overflow:hidden; min-height:0; border-radius:12px; box-shadow:0 1px 4px rgba(0,0,0,0.08); }
  .panel { position:absolute; top:0; left:0; right:0; bottom:0; width:100%; height:100%; border-radius:12px; overflow:hidden; background:white; }
  .panel-hidden { visibility:hidden; pointer-events:none; }

  .polar-ov {
    position:absolute; top:14px; right:14px; z-index:500;
    background:rgba(255,255,255,0.92); border:1px solid #d0dce8;
    border-radius:50%; box-shadow:0 4px 16px rgba(0,0,0,0.12);
    padding:3px; backdrop-filter:blur(4px);
  }
</style>