/**
 * Main app layout — кастомный `<AnimatedSlot>` + `<NavBar>`.
 *
 * AnimatedSlot — обёртка над Slot'ом, анимирующая переход при смене
 * pathname'а. Направление анимации вычисляется по TAB_ORDER: если
 * целевой tab "справа" — слайд из правой стороны, "слева" — из левой.
 *
 * Intra-tab навигация (chats/index → chats/[id]) обслуживается вложенным
 * Stack'ом в chats/_layout.tsx — там остаётся нативная slide-from-right
 * анимация, чтобы chat detail "выезжал" поверх списка.
 *
 * Side-effects (balance, contacts, WS auth, dev seed) — монтируются здесь
 * один раз; переходы между tab'ами их не перезапускают.
 */
import React, { useEffect } from 'react';
import { View, Platform } from 'react-native';
import { router, usePathname } from 'expo-router';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useStore } from '@/lib/store';
import { useBalance } from '@/hooks/useBalance';
import { useContacts } from '@/hooks/useContacts';
import { useWellKnownContracts } from '@/hooks/useWellKnownContracts';
import { useNotifications } from '@/hooks/useNotifications';
import { useGlobalInbox } from '@/hooks/useGlobalInbox';
import { getWSClient } from '@/lib/ws';
import { NavBar } from '@/components/NavBar';
import { AnimatedSlot } from '@/components/AnimatedSlot';
import { saveContact } from '@/lib/storage';
import {
  fetchDevices, buildLinkDeviceTx, submitTx,
} from '@/lib/api';

export default function AppLayout() {
  const keyFile  = useStore(s => s.keyFile);
  const requests = useStore(s => s.requests);
  const insets   = useSafeAreaInsets();
  const pathname = usePathname();

  // NavBar прячется на full-screen экранах:
  //  - chat detail
  //  - compose (new post modal)
  //  - feed sub-routes (post detail, hashtag search)
  //  - tx detail
  const hideNav =
    /^\/chats\/[^/]+/.test(pathname) ||
    pathname === '/compose' ||
    /^\/feed\/.+/.test(pathname) ||
    /^\/tx\/.+/.test(pathname);

  useBalance();
  useContacts();
  useWellKnownContracts();
  useNotifications();   // permission + tap-handler
  useGlobalInbox();     // global inbox listener → notifications on new peer msg

  // Ensure the Saved Messages (self-chat) contact exists as soon as the user
  // is signed in, so it shows up in the chat list without any prior action.
  const contacts      = useStore(s => s.contacts);
  const upsertContact = useStore(s => s.upsertContact);
  useEffect(() => {
    if (!keyFile) return;
    if (contacts.some(c => c.address === keyFile.pub_key)) return;
    const saved = {
      address:   keyFile.pub_key,
      x25519Pub: keyFile.x25519_pub,
      alias:     'Saved Messages',
      addedAt:   Date.now(),
    };
    upsertContact(saved);
    saveContact(saved).catch(() => { /* best-effort — re-added next boot anyway */ });
  }, [keyFile, contacts, upsertContact]);

  useEffect(() => {
    const ws = getWSClient();
    if (keyFile) ws.setAuthCreds({ pubKey: keyFile.pub_key, privKey: keyFile.priv_key });
    else ws.setAuthCreds(null);
  }, [keyFile]);

  // Multi-device registry bootstrap (v2.2.0). On every sign-in:
  //   1. Fetch our own device list from chain.
  //   2. If our local X25519 pub isn't in the active set, submit a
  //      LINK_DEVICE tx for it — this makes "this device" discoverable
  //      to senders. No-ops after the first successful submission on
  //      a given chain + master key pair.
  // Failures are swallowed: insufficient balance, offline node, or a
  // chain that hasn't upgraded to v2.2.0 all surface the same way
  // (our device just isn't registered yet; next sign-in tries again).
  useEffect(() => {
    if (!keyFile) return;
    let cancelled = false;
    (async () => {
      try {
        const devs = await fetchDevices(keyFile.pub_key);
        if (cancelled) return;
        if (devs.some(d => d.x25519_pub_key === keyFile.x25519_pub)) {
          return; // already registered
        }
        const deviceName = Platform.select({
          ios:     'iPhone',
          android: 'Android phone',
          default: 'Device',
        }) ?? 'Device';
        const tx = buildLinkDeviceTx({
          from:       keyFile.pub_key,
          x25519Pub:  keyFile.x25519_pub,
          deviceName,
          privKey:    keyFile.priv_key,
        });
        await submitTx(tx);
      } catch {
        /* best-effort — next launch retries */
      }
    })();
    return () => { cancelled = true; };
  }, [keyFile]);

  useEffect(() => {
    if (keyFile === null) {
      const t = setTimeout(() => {
        if (!useStore.getState().keyFile) router.replace('/');
      }, 300);
      return () => clearTimeout(t);
    }
  }, [keyFile]);

  return (
    <View style={{ flex: 1, backgroundColor: '#000000' }}>
      <View style={{ flex: 1 }}>
        <AnimatedSlot />
      </View>
      {!hideNav && (
        <NavBar
          bottomInset={insets.bottom}
          requestCount={requests.length}
          notifCount={0}
        />
      )}
    </View>
  );
}
