<script lang="ts">
  import "$lib/style.css";
  import "iconify-icon";
  import { hasMnemonic, walletState } from "$lib/wallet.svelte";
  import { onMount } from "svelte";
  import { goto } from "$app/navigation";
  import PasswordDialog from "$lib/components/PasswordDialog.svelte";
  import { page } from "$app/state";
  import { start as startNwc } from "$lib/nwc.svelte";
  import SplashScreen from "$lib/components/SplashScreen.svelte";
  import ErrorDialog from "$lib/components/ErrorDialog.svelte";
  import InstallPrompt from "$lib/components/InstallPrompt.svelte";
  import { online } from "$lib/online.svelte";
  import Offline from "$lib/components/Offline.svelte";
  import { shaderEnabled } from "$lib/settings.svelte";

  type AppError = {
    message: string;
    stack?: string;
  };

  let { children } = $props();
  let showSplash = $state(true);
  let closingSplash = $state(false);
  let currentError = $state<AppError | null>(null);
  let showInstallPrompt = $state(false);
  let deferredPrompt: Event | undefined = $state(undefined);

  async function handleInstallClick() {
    if (deferredPrompt) {
      (deferredPrompt as any).prompt();
      const { outcome } = await (deferredPrompt as any).userChoice;
      if (outcome === "accepted") {
        deferredPrompt = undefined;
        showInstallPrompt = false;
      }
    }
  }

  function goToSettings() {
    goto("/settings");
  }

  const isOnSetup = $derived(page.route.id?.startsWith("/setup"));
  const isOnSettings = $derived(page.route.id?.startsWith("/settings"));
  const showSettingsButton = $derived(
    !isOnSetup && !isOnSettings && hasMnemonic()
  );

  onMount(() => {
    setTimeout(() => {
      closingSplash = true;
      setTimeout(() => {
        showSplash = false;
      }, 1000);
    }, 3000);

    window.addEventListener("error", (event: ErrorEvent) => {
      event.preventDefault();
      if (event.message.indexOf("Svelte error")) return;
      currentError = { message: event.message, stack: event.error?.stack };
    });

    window.addEventListener(
      "unhandledrejection",
      (event: PromiseRejectionEvent) => {
        const reason = event.reason;
        if (reason instanceof Error) {
          if (reason.message.indexOf("Svelte error")) return;
          currentError = { message: reason.message, stack: reason.stack };
        } else {
          if (String(reason).indexOf("Svelte error")) return;
          currentError = { message: String(reason) };
        }
      }
    );

    window.addEventListener("beforeinstallprompt", (e) => {
      e.preventDefault();
      deferredPrompt = e;
      if (
        !window.matchMedia("(display-mode: standalone)").matches &&
        /Mobi|Android/i.test(navigator.userAgent)
      ) {
        showInstallPrompt = true;
      }
    });

    if (!hasMnemonic() && !isOnSetup) {
      goto("/setup");
    }
  });
</script>

<svelte:head>
  <title>Portal BTC</title>
</svelte:head>

<div class="container" class:retro-shader={$shaderEnabled}>
  {#if !$online}
    <Offline />
  {:else if showInstallPrompt && deferredPrompt}
    <InstallPrompt onInstall={handleInstallClick} />
  {:else if showSplash}
    <SplashScreen closing={closingSplash} />
  {:else if !$walletState.open && !isOnSetup}
    <PasswordDialog onunlock={() => startNwc()} />
  {:else}
    <main class="app-wrapper">
      {#if showSettingsButton}
        <div class="settings-button-container">
          <button class="retro-btn settings-btn" onclick={goToSettings}>
            <iconify-icon icon="mdi:cog" width="16" height="16"></iconify-icon>
            Settings
          </button>
        </div>
      {/if}

      {@render children()}
    </main>
  {/if}

  <ErrorDialog error={currentError} onclose={() => (currentError = null)} />
</div>

<style>
  .container {
    height: 100vh;
    max-height: 100vh;
    width: 100vw;
    overflow-y: auto;
  }
  .retro-shader {
    position: relative;
  }

  .retro-shader::before {
    content: " ";
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    background:
      linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%),
      linear-gradient(
        90deg,
        rgba(255, 0, 0, 0.06),
        rgba(0, 255, 0, 0.02),
        rgba(0, 0, 255, 0.06)
      );
    z-index: 2000;
    background-size:
      100% 2px,
      3px 100%;
    background-attachment: fixed;
    pointer-events: none;
  }

  .retro-shader::after {
    content: " ";
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    background: rgba(18, 16, 16, 0.1);
    opacity: 0;
    z-index: 2001;
    pointer-events: none;
  }

  .settings-button-container {
    position: absolute;
    top: 1rem;
    right: 1rem;
    z-index: 10;
  }

  .settings-btn {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.7rem;
    padding: 0.5rem 0.75rem;
  }
</style>
