<script lang="ts">
  import { onMount } from 'svelte';
  import { app } from './lib/app.svelte';
  import { api, inTauri } from './lib/bridge';
  import ConnectionScreen from './components/ConnectionScreen.svelte';
  import HelpOverlay from './components/HelpOverlay.svelte';
  import ProfileDrawer from './components/ProfileDrawer.svelte';
  import RideScreen from './components/RideScreen.svelte';
  import Toasts from './components/Toasts.svelte';

  let ready = $state(false);
  let fatal = $state<string | null>(null);

  onMount(async () => {
    if (!inTauri) {
      fatal = 'Not running inside the Tauri shell — start the app with `cargo tauri dev`.';
      return;
    }
    try {
      await app.init();
      ready = true;
    } catch (e) {
      fatal = String(e);
    }
  });

  /**
   * Keyboard control (FR-3.19). Handled once, here, and dispatched straight to
   * Rust — the frontend never applies a step itself, it only asks.
   */
  function onKey(e: KeyboardEvent) {
    if (e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLInputElement) return;
    if (e.metaKey || e.ctrlKey || e.altKey) return;

    const step = e.shiftKey ? 2 : 0.5;
    const run = (fn: () => Promise<unknown>) => {
      e.preventDefault();
      app.run(fn);
    };

    switch (e.key) {
      case 'ArrowUp':
        return run(() => api.nudgeGradient(step));
      case 'ArrowDown':
        return run(() => api.nudgeGradient(-step));
      case '0':
        return run(() => api.resetGradient());
      case ' ':
        return run(() => api.togglePause());
      case 'm':
      case 'M':
        return run(() => api.cycleMode());
      case 'l':
      case 'L':
        return run(() => api.markLap());
      case ']':
        return run(() => bumpTarget(1));
      case '[':
        return run(() => bumpTarget(-1));
      case 'p':
      case 'P':
        e.preventDefault();
        app.showProfiles = !app.showProfiles;
        return;
      case 'd':
      case 'D':
        app.screen = 'connect';
        return;
      case 'r':
      case 'R':
        app.screen = 'ride';
        return;
      case '?':
        app.showHelp = !app.showHelp;
        return;
      case 'Escape':
        app.showHelp = false;
        app.showProfiles = false;
        return;
    }
  }

  /** `[` / `]` adjust whichever target the active mode actually uses. */
  async function bumpTarget(dir: number): Promise<unknown> {
    const ride = app.ride;
    if (!ride) return;
    if (ride.mode === 'Erg') return api.setPower(ride.powerTargetW + dir * 10);
    if (ride.mode === 'Resistance') return api.setResistance(ride.resistanceLevel + dir * 2);
    return api.nudgeGradient(dir * 0.5);
  }
</script>

<svelte:window on:keydown={onKey} />

<main>
  {#if fatal}
    <div class="fatal">
      <h1>BikeControl could not start</h1>
      <p>{fatal}</p>
    </div>
  {:else if !ready}
    <div class="boot"><span class="label">Starting…</span></div>
  {:else if app.screen === 'ride'}
    <RideScreen />
  {:else}
    <ConnectionScreen />
  {/if}

  {#if app.showProfiles}<ProfileDrawer />{/if}
  {#if app.showHelp}<HelpOverlay />{/if}
  <Toasts />
</main>

<style>
  main {
    height: 100%;
    min-height: 0;
  }

  .boot,
  .fatal {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    height: 100%;
    text-align: center;
    padding: 2rem;
  }

  .fatal h1 {
    margin: 0;
    font-size: 1.4rem;
    font-weight: 300;
  }

  .fatal p {
    margin: 0;
    color: var(--ink-dim);
    max-width: 40rem;
  }
</style>
