// app.jsx — Main app shell, routing, state management

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": 3,
  "font": 2
}/*EDITMODE-END*/;

// 4 curated accent palettes
const PALETTES = [
  { name: 'Korall (Standard)', primary: '#D97757', deep: '#B85A3C', soft: '#FAEDE4', ink: '#5C2E1B' },
  { name: 'Tiefblau',          primary: '#2A6FDB', deep: '#1F58B0', soft: '#E1ECF9', ink: '#0F2B5C' },
  { name: 'Waldgrün',          primary: '#3F8F5C', deep: '#2A6E45', soft: '#E0EFE5', ink: '#1E4730' },
  { name: 'Gold',              primary: '#C28428', deep: '#9A6618', soft: '#FAF1DD', ink: '#5C3F0E' },
];

// 4 curated typography bundles (body + display + tracking adj.)
const FONTS = [
  {
    name: 'Editorial',
    sans: "'Plus Jakarta Sans', -apple-system, system-ui, sans-serif",
    display: "'Instrument Serif', 'Plus Jakarta Sans', serif",
    displayWeight: 400, sansTrack: -0.01, displayTrack: -0.02,
    sample: { sans: 'Aa', display: 'Aa' },
  },
  {
    name: 'Geometrisch',
    sans: "'Space Grotesk', system-ui, sans-serif",
    display: "'Bricolage Grotesque', 'Space Grotesk', sans-serif",
    displayWeight: 500, sansTrack: -0.005, displayTrack: -0.03,
    sample: { sans: 'Aa', display: 'Aa' },
  },
  {
    name: 'Klassisch',
    sans: "'Manrope', system-ui, sans-serif",
    display: "'Newsreader', 'Manrope', serif",
    displayWeight: 500, sansTrack: -0.005, displayTrack: -0.015,
    sample: { sans: 'Aa', display: 'Aa' },
  },
  {
    name: 'Skandinavisch',
    sans: "'DM Sans', system-ui, sans-serif",
    display: "'Fraunces', 'DM Sans', serif",
    displayWeight: 400, sansTrack: -0.01, displayTrack: -0.02,
    sample: { sans: 'Aa', display: 'Aa' },
  },
];

// ─── Font bundle picker (custom — shows preview Aa) ─────────────────────
function FontBundlePicker({ value, onChange }) {
  return (
    <div style={{
      display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, padding: '6px 0',
    }}>
      {FONTS.map((f, i) => {
        const on = i === value;
        return (
          <button
            key={i} type="button"
            onClick={() => onChange(i)}
            style={{
              background: on ? '#1F1A14' : '#FAF7F2',
              color: on ? '#fff' : '#1F1A14',
              border: on ? '2px solid #D97757' : '1px solid #E0DACF',
              borderRadius: 12, padding: '12px 10px', cursor: 'pointer',
              display: 'flex', flexDirection: 'column', gap: 6, textAlign: 'left',
              transition: 'all .15s ease',
            }}
          >
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 4 }}>
              <span style={{
                fontFamily: f.display, fontWeight: f.displayWeight, fontSize: 32,
                lineHeight: 0.9, letterSpacing: f.displayTrack + 'em',
              }}>Aa</span>
              <span style={{
                fontFamily: f.sans, fontWeight: 600, fontSize: 14,
                opacity: 0.65, letterSpacing: f.sansTrack + 'em',
              }}>Aa</span>
            </div>
            <div style={{
              fontFamily: f.sans, fontSize: 11, fontWeight: 600,
              letterSpacing: -0.005, marginTop: 2,
            }}>{f.name}</div>
          </button>
        );
      })}
    </div>
  );
}

function useIsDesktop() {
  const [isDesktop, setIsDesktop] = React.useState(() => window.matchMedia('(min-width: 960px)').matches);
  React.useEffect(() => {
    const media = window.matchMedia('(min-width: 960px)');
    const update = () => setIsDesktop(media.matches);
    update();
    media.addEventListener('change', update);
    return () => media.removeEventListener('change', update);
  }, []);
  return isDesktop;
}

const DESKTOP_ROUTES = new Set([
  'dashboard',
  'searchBuilder',
  'searchBuilderMiete',
  'results',
  'mietenResults',
  'listing',
  'aiEval',
  'mietenDashboard',
  'discover',
  'investor',
  'compare',
  'portfolio',
  'notifications',
  'profile',
  'security',
  'admin',
  'exports',
]);

function desktopRouteHash(name = 'dashboard', params = null) {
  const route = DESKTOP_ROUTES.has(name) ? name : 'dashboard';
  const query = new URLSearchParams();
  Object.entries(params || {}).forEach(([key, value]) => {
    if (value == null || value === '') return;
    query.set(key, Array.isArray(value) ? value.join(',') : String(value));
  });
  const qs = query.toString();
  return `#/${route}${qs ? `?${qs}` : ''}`;
}

function desktopRouteUrl(name, params) {
  return `/${desktopRouteHash(name, params)}`;
}

function parseDesktopRouteHash() {
  const raw = window.location.hash || '';
  if (!raw.startsWith('#/')) return null;
  const clean = raw.slice(2);
  const [routeName, queryString = ''] = clean.split('?');
  if (!DESKTOP_ROUTES.has(routeName)) return null;
  const query = new URLSearchParams(queryString);
  const params = {};
  query.forEach((value, key) => {
    params[key] = key === 'ids' ? value.split(',').filter(Boolean) : value;
  });
  return { name: routeName, params: Object.keys(params).length ? params : null };
}


function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const palette = PALETTES[t.palette] || PALETTES[0];
  const font = FONTS[t.font] || FONTS[0];
  const isDesktop = useIsDesktop();
  const sharedListing = window.REVAMP_SHARED_LISTING || null;

  // Apply palette + font tokens to CSS vars
  React.useEffect(() => {
    const r = document.documentElement;
    r.style.setProperty('--primary', palette.primary);
    r.style.setProperty('--primary-deep', palette.deep);
    r.style.setProperty('--primary-soft', palette.soft);
    r.style.setProperty('--primary-ink', palette.ink);
    r.style.setProperty('--font-sans', font.sans);
    r.style.setProperty('--font-display', font.display);
    r.style.setProperty('--font-display-weight', font.displayWeight);
  }, [t.palette, t.font]);

  // App state
  const [booting, setBooting] = React.useState(true);
  const [authed, setAuthed] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [flash, setFlash] = React.useState(null);
  const [user, setUser] = React.useState(null);
  const [plan, setPlan] = React.useState(null);
  const [taskLimit, setTaskLimit] = React.useState(null);
  const [admin, setAdmin] = React.useState(null);
  const [tab, setTab] = React.useState('immobilien'); // bottom nav root
  // Stack: array of { name, params } per tab — but simpler: single stack
  const [stack, setStack] = React.useState([{ name: 'dashboard', params: null }]);

  const [searches, setSearches] = React.useState([]);
  const [listings, setListings] = React.useState([]);
  const [evaluations, setEvaluations] = React.useState({});
  const [favs, setFavs] = React.useState(new Set());
  const [archived, setArchived] = React.useState(new Set());
  const [notifications, setNotifications] = React.useState([]);
  const [investor, setInvestor] = React.useState(null);
  const [portfolioAnalytics, setPortfolioAnalytics] = React.useState(null);
  const [notificationSettings, setNotificationSettings] = React.useState(null);
  const notifBadge = notifications.filter(n => !n.read).length;
  const desktopHistoryReady = React.useRef(false);
  const mobileHistoryReady = React.useRef(false);
  const deepLinkHandled = React.useRef(false);
  const stackRef = React.useRef(stack);

  React.useEffect(() => {
    stackRef.current = stack;
  }, [stack]);

  const writeDesktopHistory = React.useCallback((name, params = null, replace = false) => {
    if (!isDesktop || !authed || sharedListing) return;
    const url = desktopRouteUrl(name, params);
    const current = `${window.location.pathname}${window.location.hash}`;
    if (current === url) return;
    window.history[replace ? 'replaceState' : 'pushState']({ immobotDesktop: true, name, params }, '', url);
  }, [isDesktop, authed, sharedListing]);

  const writeMobileHistory = React.useCallback((nextStack, replace = false) => {
    if (isDesktop || !authed || sharedListing || !window.history?.pushState) return;
    const safeStack = Array.isArray(nextStack) && nextStack.length
      ? nextStack
      : [{ name: 'dashboard', params: null }];
    const url = `${window.location.pathname}${window.location.hash || ''}`;
    window.history[replace ? 'replaceState' : 'pushState']({ immobotMobile: true, stack: safeStack }, '', url);
  }, [isDesktop, authed, sharedListing]);

  const applyBootstrap = React.useCallback((payload) => {
    const data = payload?.bootstrap || payload;
    if (!data) return;

    setUser(data.user || null);
    setPlan(data.plan || null);
    setTaskLimit(data.taskLimit || null);
    setAdmin(data.admin || null);
    setSearches(data.searches || []);
    setListings(data.listings || []);
    setEvaluations(data.evaluations || {});
    window.AI_EVALS = data.evaluations || {};
    setFavs(new Set((data.favorites || []).map(String)));
    setArchived(new Set((data.archived || []).map(String)));
    setNotifications(data.notifications || []);
  }, []);

  const loadSession = React.useCallback(async () => {
    setBooting(true);
    setError(null);
    try {
      const result = await RevampApi.session();
      setAuthed(!!result.authenticated);
      if (result.authenticated) applyBootstrap(result.bootstrap);
    } catch (err) {
      setError(err.message || 'Die Verbindung zur App konnte nicht hergestellt werden.');
    } finally {
      setBooting(false);
    }
  }, [applyBootstrap]);

  React.useEffect(() => {
    loadSession();
  }, [loadSession]);

  React.useEffect(() => {
    if (deepLinkHandled.current || booting || !authed || sharedListing) return;

    const params = new URLSearchParams(window.location.search || '');
    const adId = params.get('ad') || params.get('ad_id');
    if (!adId) return;

    deepLinkHandled.current = true;

    const mode = params.get('mode');
    const targetTab = mode === 'rental' ? 'mieten' : 'immobilien';
    setTab(targetTab);
    reset('listing', { id: adId }, true);
  }, [authed, booting, sharedListing, isDesktop]);

  const runMutation = async (fn, options = {}) => {
    setBusy(true);
    setError(null);
    try {
      const result = await fn();
      if (result?.bootstrap) applyBootstrap(result.bootstrap);
      if (result?.admin) setAdmin(result.admin);
      if (result?.message && !options.silent) setFlash(result.message);
      return result;
    } catch (err) {
      const msg = err.payload?.message || err.message || 'Die Aktion ist fehlgeschlagen.';
      setError(msg);
      throw err;
    } finally {
      setBusy(false);
    }
  };

  // Navigation API
  const navigate = (name, params = null, replace = false) => {
    setStack(s => {
      const nextStack = replace ? [...s.slice(0, -1), { name, params }] : [...s, { name, params }];
      writeDesktopHistory(name, params, replace);
      writeMobileHistory(nextStack, replace);
      return nextStack;
    });
  };
  const back = () => {
    if (authed && stack.length > 1 && window.history?.back) {
      window.history.back();
      return;
    }
    setStack(s => s.length > 1 ? s.slice(0, -1) : s);
  };
  const reset = (name, params = null, replace = false) => {
    const nextStack = [{ name, params }];
    setStack(nextStack);
    writeDesktopHistory(name, params, replace);
    writeMobileHistory(nextStack, replace);
  };

  const toggleFav = (id, forceOn) => {
    const stringId = String(id);
    const shouldAdd = forceOn || !favs.has(stringId);
    setFavs(s => {
      const ns = new Set(s);
      if (shouldAdd) ns.add(stringId);
      else ns.delete(stringId);
      return ns;
    });
    setArchived(s => {
      const ns = new Set(s);
      if (shouldAdd) ns.delete(stringId);
      return ns;
    });
    runMutation(
      () => shouldAdd ? RevampApi.setAdAction(id, 'favorite') : RevampApi.removeAdAction(id),
      { silent: true }
    ).catch(() => loadSession());
  };
  const archiveListing = (id) => {
    const stringId = String(id);
    setArchived(s => new Set([...s, stringId]));
    setFavs(s => {
      const ns = new Set(s);
      ns.delete(stringId);
      return ns;
    });
    runMutation(() => RevampApi.setAdAction(id, 'archive'), { silent: true }).catch(() => loadSession());
  };
  const addSearch = async (data) => {
    const result = await runMutation(() => RevampApi.createSearch(data));
    return result.search;
  };
  const deleteSearch = async (id) => {
    await runMutation(() => RevampApi.deleteSearch(id));
    setSearches(arr => arr.filter(s => s.id !== id));
  };
  const refreshSearch = (id) => runMutation(() => RevampApi.refreshSearch(id));
  const evaluateSearch = (id) => runMutation(() => RevampApi.evaluateSearch(id));
  const exportSearch = (id) => { window.location.href = RevampApi.exportSearchUrl(id); };
  const evaluateAd = (taskId, adId) => runMutation(() => RevampApi.evaluateAd(taskId, adId));
  const scrapeAdDetails = (taskId, adId) => runMutation(() => RevampApi.scrapeAdDetails(taskId, adId));
  const contactAd = (taskId, adId) => runMutation(() => RevampApi.contactAd(taskId, adId));
  const inquiryPreview = (taskId, adId) => RevampApi.inquiryPreview(taskId, adId);
  const toggleSharing = (taskId, adId) => runMutation(() => RevampApi.toggleSharing(taskId, adId));
  const updateProfile = (data) => runMutation(() => RevampApi.updateProfile(data));
  const toggleExpertMode = () => runMutation(() => RevampApi.toggleExpertMode());
  const updatePassword = (data) => runMutation(() => RevampApi.updatePassword(data));
  const resendVerification = () => runMutation(() => RevampApi.resendVerification());
  const startCheckout = async () => {
    const result = await runMutation(() => RevampApi.billingCheckout());
    if (result?.url) window.location.href = result.url;
  };
  const openBillingPortal = async () => {
    const result = await runMutation(() => RevampApi.billingPortal());
    if (result?.url) window.location.href = result.url;
  };
  const connectTelegram = async () => {
    const result = await runMutation(() => RevampApi.telegramLink());
    if (result?.url) window.open(result.url, '_blank', 'noopener');
    return result;
  };
  const disconnectTelegram = async () => {
    await runMutation(() => RevampApi.telegramDisconnect());
    await loadSession();
  };
  const deleteProfile = async (password) => {
    await runMutation(() => RevampApi.deleteProfile(password), { silent: true });
    setAuthed(false);
    setUser(null);
    setSearches([]);
    setListings([]);
    setFavs(new Set());
    setArchived(new Set());
    setNotifications([]);
    setInvestor(null);
    setPortfolioAnalytics(null);
    setNotificationSettings(null);
    reset('dashboard');
  };
  const loadInvestor = async () => {
    const result = await runMutation(() => RevampApi.investor(), { silent: true });
    setInvestor(result);
    window.INVESTOR = result;
    const investorItems = Array.isArray(result?.evaluations) ? result.evaluations : [];
    const investorListings = investorItems.map(item => item?.listing).filter(Boolean);
    if (investorListings.length) {
      setListings(current => {
        const map = new Map((current || []).map(item => [String(item.id ?? item.adId), item]));
        investorListings.forEach(item => map.set(String(item.id ?? item.adId), { ...(map.get(String(item.id ?? item.adId)) || {}), ...item }));
        const next = Array.from(map.values());
        window.LISTINGS = next;
        return next;
      });
    }
    const investorEvaluations = investorItems.filter(item => item?.evaluation).reduce((acc, item) => {
      const key = String(item.adId || item.listing?.id || item.listing?.adId || '');
      if (key) acc[key] = item.evaluation;
      return acc;
    }, {});
    if (Object.keys(investorEvaluations).length) {
      setEvaluations(current => {
        const next = { ...(current || {}), ...investorEvaluations };
        window.AI_EVALS = next;
        return next;
      });
    }
    if (result?.portfolio) setPortfolioAnalytics(result.portfolio);
    return result;
  };
  const loadInvestorCompare = (ids = []) => runMutation(() => RevampApi.investorCompare(ids), { silent: true });
  const loadPortfolioAnalytics = async () => {
    const result = await runMutation(() => RevampApi.portfolioAnalytics(), { silent: true });
    setPortfolioAnalytics(result);
    return result;
  };
  const exportPortfolio = () => { window.location.href = RevampApi.portfolioExportUrl(); };
  const loadNotificationSettings = async () => {
    const result = await runMutation(() => RevampApi.notificationSubscriptions(), { silent: true });
    setNotificationSettings(result);
    return result;
  };
  const storePushSubscription = async (subscription) => {
    const result = await runMutation(() => RevampApi.storePushSubscription(subscription));
    if (result?.notifications) setNotificationSettings(result.notifications);
    return result;
  };
  const revokePushSubscription = async (endpoint) => {
    const result = await runMutation(() => RevampApi.revokePushSubscription(endpoint));
    if (result?.notifications) setNotificationSettings(result.notifications);
    return result;
  };
  const revokeAllPushSubscriptions = async () => {
    const result = await runMutation(() => RevampApi.revokeAllPushSubscriptions());
    if (result?.notifications) setNotificationSettings(result.notifications);
    return result;
  };
  const sendTestNotification = () => runMutation(() => RevampApi.sendTestNotification());
  const reloadAdmin = async () => {
    const result = await runMutation(() => RevampApi.adminJobs(), { silent: true });
    setAdmin(result);
  };

  // Switching tabs resets the stack to the root of that tab
  const setActiveTab = (newTab) => {
    setTab(newTab);
    const roots = {
      immobilien: 'dashboard',
      mieten: 'mietenDashboard',
      investor: 'investor',
      portfolio: 'portfolio',
      notifications: 'notifications',
      profile: 'profile',
    };
    reset(roots[newTab]);
  };

  const ctx = {
    user, plan, taskLimit, admin, listings, searches, favs, archived, notifications, evaluations,
    investor, portfolioAnalytics, notificationSettings, notifBadge,
    busy, error, flash, setFlash, isDesktop,
    navigate, back, reset,
    toggleFav, archiveListing,
    addSearch, deleteSearch, refreshSearch, evaluateSearch, exportSearch,
    evaluateAd, scrapeAdDetails, contactAd, inquiryPreview, toggleSharing, updateProfile, updatePassword, deleteProfile,
    toggleExpertMode, resendVerification, startCheckout, openBillingPortal, connectTelegram, disconnectTelegram, reloadSession: loadSession,
    loadInvestor, loadInvestorCompare, loadPortfolioAnalytics, exportPortfolio,
    loadNotificationSettings, storePushSubscription, revokePushSubscription, revokeAllPushSubscriptions, sendTestNotification,
    reloadAdmin, setNotifications, setTab,
    signIn: async (email, password) => {
      const result = await runMutation(() => RevampApi.login(email, password), { silent: true });
      setAuthed(true);
      applyBootstrap(result.bootstrap);
      reset('dashboard');
    },
    register: async (name, email, password) => {
      const result = await runMutation(() => RevampApi.register(name, email, password), { silent: true });
      setAuthed(true);
      applyBootstrap(result.bootstrap);
      reset('dashboard');
    },
    signOut: async () => {
      await runMutation(() => RevampApi.logout(), { silent: true }).catch(() => {});
      setAuthed(false);
      setUser(null);
      setSearches([]);
      setListings([]);
      setFavs(new Set());
      setArchived(new Set());
      setNotifications([]);
      setInvestor(null);
      setPortfolioAnalytics(null);
      setNotificationSettings(null);
      reset('dashboard');
    },
  };

  React.useEffect(() => {
    if (!authed || booting || sharedListing) {
      desktopHistoryReady.current = false;
      mobileHistoryReady.current = false;
      return;
    }
    const parsed = parseDesktopRouteHash();
    if (parsed) {
      setStack([parsed]);
      desktopHistoryReady.current = isDesktop;
      mobileHistoryReady.current = false;
      return;
    }
    if (!isDesktop) {
      desktopHistoryReady.current = false;
      if (!mobileHistoryReady.current) {
        mobileHistoryReady.current = true;
        const existingStack = window.history.state?.immobotMobile && Array.isArray(window.history.state.stack)
          ? window.history.state.stack
          : null;
        const currentStack = existingStack?.length
          ? existingStack
          : (stackRef.current?.length ? stackRef.current : [{ name: 'dashboard', params: null }]);
        window.history.replaceState({ immobotMobile: true, stack: currentStack }, '', `${window.location.pathname}${window.location.hash || ''}`);
      }
      return;
    }
    mobileHistoryReady.current = false;
    if (desktopHistoryReady.current) return;
    desktopHistoryReady.current = true;
    const currentRoute = stack[stack.length - 1] || { name: 'dashboard', params: null };
    window.history.replaceState(
      { immobotDesktop: true, name: currentRoute.name, params: currentRoute.params },
      '',
      desktopRouteUrl(currentRoute.name, currentRoute.params)
    );
  }, [isDesktop, authed, booting, sharedListing]);

  React.useEffect(() => {
    if (!isDesktop || !authed || sharedListing) return undefined;
    const onPop = () => {
      const parsed = parseDesktopRouteHash() || { name: 'dashboard', params: null };
      setStack([parsed]);
      if (!parseDesktopRouteHash()) {
        window.history.replaceState({ immobotDesktop: true, name: parsed.name, params: parsed.params }, '', desktopRouteUrl(parsed.name, parsed.params));
      }
    };
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, [isDesktop, authed, sharedListing]);

  React.useEffect(() => {
    if (isDesktop || !authed || sharedListing) return undefined;
    const onPop = (event) => {
      const historyStack = event.state?.immobotMobile && Array.isArray(event.state.stack)
        ? event.state.stack
        : null;

      if (historyStack?.length) {
        setStack(historyStack);
        return;
      }

      const currentStack = stackRef.current || [];
      if (currentStack.length > 1) {
        setStack(currentStack.slice(0, -1));
      }
    };
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, [isDesktop, authed, sharedListing]);

  // Resolve current screen
  const current = stack[stack.length - 1];
  let screen = null;
  switch (current.name) {
    case 'dashboard':        screen = <DashboardScreen ctx={ctx} />; break;
    case 'searchBuilder':    screen = <SearchBuilderScreen ctx={ctx} type="kauf" />; break;
    case 'searchBuilderMiete': screen = <SearchBuilderScreen ctx={ctx} type="miete" />; break;
    case 'results':          screen = <ResultsScreen ctx={ctx} searchId={current.params?.searchId} />; break;
    case 'mietenResults':    screen = <ResultsScreen ctx={ctx} searchId={current.params?.searchId} />; break;
    case 'listing':          screen = <ListingDetailScreen ctx={ctx} id={current.params?.id} />; break;
    case 'aiEval':           screen = <AIEvalScreen ctx={ctx} id={current.params?.id} />; break;
    case 'mietenDashboard':  screen = <MietenDashboardScreen ctx={ctx} />; break;
    case 'swipe':            screen = <SwipeScreen ctx={ctx} />; break;
    case 'investor':         screen = <InvestorScreen ctx={ctx} />; break;
    case 'compare':          screen = <InvestorCompareScreen ctx={ctx} ids={current.params?.ids || []} />; break;
    case 'portfolio':        screen = <PortfolioScreen ctx={ctx} />; break;
    case 'notifications':    screen = <NotificationsScreen ctx={ctx} />; break;
    case 'profile':          screen = <ProfileScreen ctx={ctx} />; break;
    case 'security':         screen = <AccountSecurityScreen ctx={ctx} />; break;
    case 'admin':            screen = <AdminScreen ctx={ctx} />; break;
    default:                 screen = <DashboardScreen ctx={ctx} />;
  }

  // Hide bottom nav for fullscreen flows
  const hideNav = ['searchBuilder', 'searchBuilderMiete', 'listing', 'aiEval', 'swipe', 'compare', 'security', 'admin'].includes(current.name);
  // Status bar in dark mode on dark screens
  const statusDark = !authed || current.name === 'swipe';

  if (sharedListing) {
    return (
      <AppShell statusDark={false} isDesktop={isDesktop}>
        <SharedListingScreen />
      </AppShell>
    );
  }

  if (booting) {
    return (
      <AppShell statusDark={false} isDesktop={isDesktop}>
        <LoadingScreen error={error} onRetry={loadSession} />
      </AppShell>
    );
  }

  if (!authed) {
    return (
      <>
        <AppShell statusDark={true} isDesktop={isDesktop}>
          <LandingScreen ctx={ctx} onEnter={() => { setAuthed(true); reset('dashboard'); }} />
        </AppShell>
        <TweaksPanel title="Tweaks" noDeckControls>
          <TweakSection label="Akzentfarbe">
            <TweakColor
              label="Palette"
              value={PALETTES[t.palette].primary}
              options={PALETTES.map(p => [p.primary, p.deep, p.soft])}
              onChange={(v) => {
                const idx = PALETTES.findIndex(p => p.primary === (Array.isArray(v) ? v[0] : v));
                if (idx >= 0) setTweak('palette', idx);
              }}
            />
          </TweakSection>
          <TweakSection label="Schriftart">
            <FontBundlePicker value={t.font || 0} onChange={(i) => setTweak('font', i)} />
          </TweakSection>
        </TweaksPanel>
      </>
    );
  }

  if (isDesktop) {
    return (
      <>
        <AppShell statusDark={false} isDesktop={isDesktop}>
          <DesktopRouteScreen ctx={ctx} current={current} />
        </AppShell>
        <TweaksPanel title="Tweaks" noDeckControls>
          <TweakSection label="Akzentfarbe">
            <TweakColor
              label="Palette"
              value={PALETTES[t.palette].primary}
              options={PALETTES.map(p => [p.primary, p.deep, p.soft])}
              onChange={(v) => {
                const idx = PALETTES.findIndex(p => p.primary === (Array.isArray(v) ? v[0] : v));
                if (idx >= 0) setTweak('palette', idx);
              }}
            />
          </TweakSection>
          <TweakSection label="Schriftart">
            <FontBundlePicker value={t.font || 0} onChange={(i) => setTweak('font', i)} />
          </TweakSection>
        </TweaksPanel>
      </>
    );
  }

  return (
    <>
      <AppShell statusDark={statusDark} isDesktop={isDesktop}>
        <div
          key={current.name + JSON.stringify(current.params)}
          className="fade-in"
          style={{ height: '100%' }}
        >
          {screen}
        </div>
        {!hideNav && (
          <BottomNav active={tab} onTab={setActiveTab} notifBadge={notifBadge} />
        )}
      </AppShell>
      <TweaksPanel title="Tweaks" noDeckControls>
        <TweakSection label="Akzentfarbe">
          <TweakColor
            label="Palette"
            value={PALETTES[t.palette].primary}
            options={PALETTES.map(p => [p.primary, p.deep, p.soft])}
            onChange={(v) => {
              const idx = PALETTES.findIndex(p => p.primary === (Array.isArray(v) ? v[0] : v));
              if (idx >= 0) setTweak('palette', idx);
            }}
          />
        </TweakSection>
        <TweakSection label="Schriftart">
          <FontBundlePicker value={t.font || 0} onChange={(i) => setTweak('font', i)} />
        </TweakSection>
        <TweakSection label="Demo-Navigation">
          <TweakSelect
            label="Zu Screen springen"
            value={current.name}
            options={[
              { value: 'dashboard',          label: 'Immobilien Dashboard' },
              { value: 'searchBuilder',      label: 'Suche erstellen (Kauf)' },
              { value: 'results',            label: 'Suchergebnisse' },
              { value: 'listing',            label: 'Inserat-Detail' },
              { value: 'aiEval',             label: 'KI-Bewertung' },
              { value: 'mietenDashboard',    label: 'Mieten Dashboard' },
              { value: 'swipe',              label: 'Swipe entdecken' },
              { value: 'investor',           label: 'Investor' },
              { value: 'compare',            label: 'Vergleich' },
              { value: 'portfolio',          label: 'Merkliste / Portfolio' },
              { value: 'notifications',      label: 'Mitteilungen' },
              { value: 'profile',            label: 'Profil' },
              { value: 'admin',              label: 'Admin Job-Monitor' },
              { value: 'landing',            label: 'Landing / Login' },
            ]}
            onChange={(v) => {
              if (v === 'landing') { setAuthed(false); return; }
              const tabMap = {
                dashboard: 'immobilien', searchBuilder: 'immobilien', results: 'immobilien', listing: 'immobilien', aiEval: 'immobilien',
                mietenDashboard: 'mieten', mietenResults: 'mieten',
                investor: 'investor', compare: 'investor',
                portfolio: 'portfolio', notifications: 'notifications', profile: 'profile', security: 'profile',
                swipe: 'immobilien', admin: 'profile',
              };
              const params =
                v === 'results' ? { searchId: 's1' } :
                v === 'mietenResults' ? { searchId: 's4' } :
                v === 'listing' ? { id: 'l3' } :
                v === 'aiEval' ? { id: 'l3' } :
                null;
              setTab(tabMap[v] || 'immobilien');
              reset(v, params);
            }}
          />
        </TweakSection>
      </TweaksPanel>
    </>
  );
}

function LoadingScreen({ error, onRetry }) {
  if (!error) {
    return (
      <div style={{
        height: '100%',
        background: 'linear-gradient(180deg, #FAF7F2 0%, #F4EDE4 100%)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        overflow: 'hidden',
      }}>
        <style>{`
          @keyframes immobotIconPulse {
            0%, 100% { transform: scale(1); box-shadow: 0 18px 46px rgba(31,26,20,.13), 0 0 0 0 rgba(217,119,87,.22); }
            50% { transform: scale(1.055); box-shadow: 0 22px 56px rgba(31,26,20,.17), 0 0 0 18px rgba(217,119,87,0); }
          }
          @keyframes immobotSoftFade {
            0%, 100% { opacity: .48; transform: scale(.98); }
            50% { opacity: .82; transform: scale(1.02); }
          }
        `}</style>
        <div style={{
          width: 116,
          height: 116,
          borderRadius: 32,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          position: 'relative',
        }}>
          <div style={{
            position: 'absolute',
            inset: -18,
            borderRadius: 42,
            background: 'radial-gradient(circle, rgba(217,119,87,.16) 0%, rgba(217,119,87,0) 68%)',
            animation: 'immobotSoftFade 1.8s ease-in-out infinite',
          }} />
          <img
            src="/revamp/icon.svg"
            alt="ImmoBot"
            style={{
              width: 92,
              height: 92,
              borderRadius: 24,
              display: 'block',
              position: 'relative',
              animation: 'immobotIconPulse 1.45s ease-in-out infinite',
              willChange: 'transform, box-shadow',
            }}
          />
        </div>
      </div>
    );
  }

  return (
    <div style={{
      height: '100%', display: 'flex', flexDirection: 'column',
      alignItems: 'center', justifyContent: 'center', padding: 28,
      background: 'var(--bg)', color: 'var(--ink)', textAlign: 'center',
    }}>
      <img src="/revamp/icon.svg" alt="ImmoBot" style={{ width: 72, height: 72, borderRadius: 20, marginBottom: 18, boxShadow: '0 12px 32px rgba(31,26,20,.14)' }} />
      <h1 style={{ margin: 0, fontFamily: 'var(--font-display)', fontWeight: 400, fontSize: 34, letterSpacing: -0.02 }}>
        ImmoBot
      </h1>
      <p style={{ margin: '8px 0 0', color: 'var(--ink-muted)', fontSize: 14 }}>
        Die Verbindung zur App konnte nicht hergestellt werden.
      </p>
      <button onClick={onRetry} className="btn btn-accent" style={{ marginTop: 18 }}>
        Erneut versuchen
      </button>
    </div>
  );
}

// ─── Native app shell ──────────────────────────────────────────────────
function AppShell({ children, statusDark = false, isDesktop = false }) {
  return (
    <div
      className={`app-shell${statusDark ? ' app-shell-dark' : ''}${isDesktop ? ' app-shell-desktop' : ''}`}
      style={{ background: statusDark ? '#1F1A14' : 'var(--bg)' }}
    >
      <div className="app-viewport">
        {children}
      </div>
    </div>
  );
}

// Bootstrap
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
