// screens-immo.jsx — Immobilien dashboard, search builder wizard, search results

// ─── DASHBOARD ──────────────────────────────────────────────────────────
function DashboardScreen({ ctx }) {
  const { listings, searches, navigate, user, taskLimit } = ctx;
  const purchaseSearches = searches.filter(s => s.category === 'kauf');
  const bestDeals = listings
    .filter(l => l.type === 'kauf' && l.aiScore)
    .sort((a, b) => b.aiScore - a.aiScore)
    .slice(0, 4);
  const scoredListings = listings.filter(l => l.aiScore);
  const stats = {
    active: purchaseSearches.filter(s => s.active).length,
    matches: purchaseSearches.reduce((sum, s) => sum + s.matches, 0),
    newToday: purchaseSearches.reduce((sum, s) => sum + s.newToday, 0),
    avgScore: scoredListings.length ? Math.round(scoredListings.reduce((s, l) => s + l.aiScore, 0) / scoredListings.length) : 0,
  };

  return (
    <div className="phone-scroll fade-in" style={{ paddingBottom: 100, background: 'var(--bg)' }}>
      {/* Header */}
      <div style={{ padding: '60px 20px 0' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
          <div>
            <div style={{ fontSize: 13, color: 'var(--ink-muted)', fontWeight: 500 }}>
              {greeting()}, {firstName(user)}
            </div>
            <h1 style={{ margin: '6px 0 0', fontFamily: 'var(--font-display)', fontWeight: 400, fontSize: 38, lineHeight: 1.0, letterSpacing: -0.025 }}>
              Kaufobjekte
            </h1>
          </div>
          <IconBtn onClick={() => navigate('searchBuilder')}><I.plus style={{ width: 22, height: 22, strokeWidth: 2.4 }} /></IconBtn>
        </div>
      </div>

      {/* Stats grid */}
      <div style={{ padding: '20px 16px 0', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
        <StatTile value={stats.active} label="Aktive Suchen" />
        <StatTile value={stats.matches} label="Treffer gesamt" />
        <StatTile value={`+${stats.newToday}`} label="Neu heute" delta="seit Mitternacht" accent />
        <StatTile value={stats.avgScore ? `Ø ${stats.avgScore}` : '—'} label="KI-Score Mittelw." />
      </div>

      {/* Active searches */}
      <Section title="Ihre Suchen" trailing={`${purchaseSearches.length} insgesamt`}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {purchaseSearches.length === 0 ? (
            <EmptyState
              icon={<I.search />}
              title="Noch keine Kaufsuche"
              subtitle="Legen Sie eine Suche an, damit ImmoBot neue Treffer sammelt."
              cta={<button onClick={() => navigate('searchBuilder')} className="btn btn-accent">Kaufsuche erstellen</button>}
            />
          ) : purchaseSearches.map(s => (
            <SearchCard key={s.id} search={s} onTap={() => navigate('results', { searchId: s.id })} />
          ))}
        </div>
      </Section>

      {/* Best deals */}
      <Section title="Beste KI-Bewertungen" trailing="Alle ansehen" onTrailing={() => navigate('results', { searchId: purchaseSearches[0]?.id })}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {bestDeals.map((l, i) => (
            <ListingRow key={l.id} listing={l} rank={i+1} onTap={() => navigate('listing', { id: l.id })} />
          ))}
        </div>
      </Section>

      {user?.isAdmin && (
        <Section title="System">
          <div className="card" style={{ padding: 16 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
              <div style={{ fontSize: 14, fontWeight: 600 }}>Kontingent</div>
              <span className="chip chip-success">Aktiv</span>
            </div>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12 }}>
              <span className="chip">{taskLimit?.current_tasks ?? purchaseSearches.filter(s => s.active).length} aktive Suchen</span>
              <span className="chip">{taskLimit?.remaining_evaluations == null ? 'KI unbegrenzt' : `${taskLimit.remaining_evaluations} KI heute übrig`}</span>
            </div>
            <button
              onClick={() => navigate('admin')}
              style={{
                background: 'var(--surface-2)', border: 0, color: 'var(--ink)',
                padding: '10px 14px', borderRadius: 999, fontSize: 13, fontWeight: 600, cursor: 'pointer',
                width: '100%',
              }}
            >
              Job-Monitor öffnen
            </button>
          </div>
        </Section>
      )}
    </div>
  );
}


function firstName(user) {
  const value = (user?.name || user?.email || 'Chris').trim();
  return value.split(/\s+/)[0] || 'Chris';
}

function greeting(date = new Date()) {
  const hour = date.getHours();
  if (hour < 11) return 'Guten Morgen';
  if (hour < 17) return 'Guten Tag';
  return 'Guten Abend';
}

function slugify(value) {
  return String(value || '')
    .normalize('NFD').replace(/[\u0300-\u036f]/g, '')
    .toLowerCase().replace(/ä/g, 'ae').replace(/ö/g, 'oe').replace(/ü/g, 'ue').replace(/ß/g, 'ss')
    .replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
}

function IconBtn({ children, onClick, badge }) {
  return (
    <button onClick={onClick} style={{
      width: 40, height: 40, borderRadius: 999, border: 0, background: 'var(--surface)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      cursor: 'pointer', color: 'var(--ink)',
      boxShadow: '0 1px 4px rgba(0,0,0,.06)', position: 'relative',
    }}>
      {children}
      {badge > 0 && (
        <div style={{
          position: 'absolute', top: -2, right: -2,
          background: 'var(--danger)', color: '#fff', fontSize: 9, fontWeight: 800,
          minWidth: 16, height: 16, padding: '0 4px', borderRadius: 999,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          boxShadow: '0 0 0 2px var(--bg)',
        }}>{badge}</div>
      )}
    </button>
  );
}

function Section({ title, trailing, onTrailing, children }) {
  return (
    <div style={{ padding: '28px 16px 0' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', padding: '0 4px 12px', gap: 12 }}>
        <div style={{ fontFamily: 'var(--font-display)', fontSize: 22, fontWeight: 400, color: 'var(--ink)', letterSpacing: -0.01, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0 }}>
          {title}
        </div>
        {trailing && (
          <button
            onClick={onTrailing}
            style={{
              background: 'transparent', border: 0,
              fontSize: 12, fontWeight: 600, color: 'var(--ink-muted)', cursor: 'pointer',
              padding: 4, whiteSpace: 'nowrap', flexShrink: 0,
            }}
          >
            {trailing}
          </button>
        )}
      </div>
      {children}
    </div>
  );
}

function SearchCard({ search, onTap }) {
  return (
    <div className="card" onClick={onTap} style={{ padding: '14px 16px', cursor: 'pointer' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
        <div style={{ flex: 1 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
            <span style={{
              width: 8, height: 8, borderRadius: 999,
              background: search.active ? 'var(--success)' : 'var(--ink-faint)',
              boxShadow: search.active ? '0 0 0 3px rgba(47,143,90,.18)' : 'none',
            }} />
            <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--ink)', letterSpacing: -0.01 }}>{search.name}</div>
          </div>
          <div style={{ fontSize: 12, color: 'var(--ink-muted)' }}>
            {search.city} +{search.radius}km · {fmtPriceShort(search.priceMin)}–{fmtPriceShort(search.priceMax)} · {search.roomsMin}–{search.roomsMax} Zi.
          </div>
        </div>
        <I.chevR style={{ color: 'var(--ink-faint)' }} />
      </div>
      <div style={{ display: 'flex', gap: 6, marginTop: 12, alignItems: 'center', flexWrap: 'wrap' }}>
        <span className="chip" style={{ fontSize: 11 }}>
          <strong style={{ color: 'var(--ink)' }}>{search.matches}</strong>&nbsp;Treffer
        </span>
        {search.newToday > 0 && (
          <span className="chip chip-accent" style={{ fontSize: 11 }}>+{search.newToday} neu</span>
        )}
        {search.aiEnabled && (
          <span className="chip chip-info" style={{ fontSize: 11 }}>KI</span>
        )}
        <span style={{ fontSize: 11, color: 'var(--ink-faint)', marginLeft: 'auto' }}>
          {fmtRelative(search.lastRun)}
        </span>
      </div>
    </div>
  );
}

// ─── SEARCH BUILDER WIZARD (4 steps) ───────────────────────────────────
function SearchBuilderScreen({ ctx, onDone, type = 'kauf' }) {
  const { navigate, back, addSearch } = ctx;
  const [step, setStep] = React.useState(1);
  const [saving, setSaving] = React.useState(false);
  const [saveError, setSaveError] = React.useState(null);
  const [data, setData] = React.useState({
    name: '',
    type,
    city: '',
    locationId: '',
    locationSlug: '',
    locationDisplay: '',
    radius: 10,
    priceMin: type === 'kauf' ? 250000 : 800,
    priceMax: type === 'kauf' ? 550000 : 1800,
    roomsMin: 2, roomsMax: 4,
    areaMin: 60, areaMax: 120,
    keywords: [],
    excludeKeywords: [],
    platforms: ['immoscout24', 'kleinanzeigen'],
    aiEnabled: type === 'kauf',
  });
  const total = 4;

  const update = (k, v) => setData(d => ({ ...d, [k]: v }));
  const canContinue = step !== 1 || !!data.locationId;
  const next = () => {
    if (!canContinue) {
      setSaveError('Bitte Stadt, Stadtteil oder PLZ aus der Standortsuche auswählen.');
      return;
    }
    setSaveError(null);
    return step < total ? setStep(step + 1) : finish();
  };
  const prev = () => step > 1 ? setStep(step - 1) : back();
  const finish = async () => {
    setSaving(true);
    setSaveError(null);
    try {
      const created = await addSearch({
        type: data.type,
        property_type: 'wohnung',
        city: data.locationDisplay || data.city,
        location_id: data.locationId || null,
        location_slug: data.locationSlug || null,
        radius: data.radius,
        price_min: data.priceMin,
        price_max: data.priceMax,
        rooms_min: data.roomsMin,
        rooms_max: data.roomsMax,
        area_min: data.areaMin,
        area_max: data.areaMax,
        require_keywords: data.keywords,
        exclude_keywords: data.excludeKeywords,
        active: true,
        run_now: true,
      });
      const id = created?.id;
      if (data.type === 'miete') {
        navigate('mietenResults', { searchId: id }, true);
      } else {
        navigate('results', { searchId: id }, true);
      }
    } catch (error) {
      setSaveError(error.payload?.message || error.message || 'Suche konnte nicht gespeichert werden.');
    } finally {
      setSaving(false);
    }
  };

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--bg)' }}>
      <TopBar
        title={`Schritt ${step}/${total}`} onBack={prev}
        trailing={<button onClick={back} style={{ background: 'transparent', border: 0, color: 'var(--ink-muted)', fontSize: 14, fontWeight: 600, cursor: 'pointer' }}>Abbrechen</button>}
      />
      {/* Progress */}
      <div style={{ padding: '0 20px' }}>
        <div style={{ display: 'flex', gap: 6 }}>
          {[1,2,3,4].map(i => (
            <div key={i} style={{
              flex: 1, height: 4, borderRadius: 999,
              background: i <= step ? 'var(--primary)' : 'var(--border)',
              transition: 'background .3s ease',
            }} />
          ))}
        </div>
      </div>

      <div className="phone-scroll fade-in" key={step} style={{ flex: 1, padding: '24px 20px 120px' }}>
        {step === 1 && <BuilderStep1 data={data} update={update} />}
        {step === 2 && <BuilderStep2 data={data} update={update} />}
        {step === 3 && <BuilderStep3 data={data} update={update} />}
        {step === 4 && <BuilderStep4 data={data} update={update} />}
        {saveError && (
          <div className="card" style={{ marginTop: 16, padding: 14, color: 'var(--danger)', background: 'var(--danger-soft)', fontSize: 13, lineHeight: 1.45 }}>
            {saveError}
          </div>
        )}
      </div>

      {/* Footer */}
      <div style={{
        position: 'absolute', bottom: 0, left: 0, right: 0, zIndex: 30,
        padding: '14px 20px 36px',
        background: 'linear-gradient(0deg, var(--bg) 60%, transparent)',
      }}>
        <button onClick={next} disabled={saving || !canContinue} className="btn btn-primary" style={{ width: '100%', padding: '16px', fontSize: 16, opacity: (saving || !canContinue) ? .72 : 1 }}>
          {saving ? 'Speichern...' : (step < total ? 'Weiter' : 'Suche speichern')}
          {!saving && <I.chevR style={{ marginLeft: 6 }} />}
        </button>
      </div>
    </div>
  );
}

function StepHeader({ overline, title, subtitle }) {
  return (
    <div style={{ marginBottom: 24 }}>
      <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--primary)', letterSpacing: 0.05, textTransform: 'uppercase', marginBottom: 8 }}>
        {overline}
      </div>
      <h2 style={{ margin: 0, fontFamily: 'var(--font-display)', fontWeight: 400, fontSize: 32, lineHeight: 1.05, letterSpacing: -0.02 }}>
        {title}
      </h2>
      {subtitle && (
        <p style={{ margin: '10px 0 0', fontSize: 14, color: 'var(--ink-muted)', lineHeight: 1.5 }}>
          {subtitle}
        </p>
      )}
    </div>
  );
}

function BuilderStep1({ data, update }) {
  const selectLocation = (location) => {
    const display = location.display_name || location.name || '';
    update('locationId', location.id || '');
    update('locationSlug', location.slug || slugify(display));
    update('locationDisplay', display);
    update('city', display);
    if (!data.name) update('name', `${data.type === 'kauf' ? 'Kaufsuche' : 'Mietsuche'} ${display}`);
  };

  return (
    <div>
      <StepHeader
        overline="Standort"
        title="Wo soll ich suchen?"
        subtitle="Stadt, Stadtteil oder PLZ eingeben und den passenden Standort übernehmen."
      />
      <Label>Suchname</Label>
      <Input value={data.name} onChange={v => update('name', v)} placeholder="z.B. „Altbau Rostock KTV“" />

      <Label style={{ marginTop: 24 }}>Standort</Label>
      <LocationSuggestInput
        value={data.city}
        selected={data.locationDisplay}
        onInput={value => {
          update('city', value);
          update('locationId', '');
          update('locationSlug', '');
          update('locationDisplay', '');
        }}
        onSelect={selectLocation}
      />

      <Label style={{ marginTop: 24 }}>Umkreis: <strong>{data.radius} km</strong></Label>
      <input
        type="range" min="0" max="50" step="5" value={data.radius}
        onChange={e => update('radius', +e.target.value)}
        style={{ width: '100%', accentColor: 'var(--primary)' }}
      />
      <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--ink-muted)', marginTop: 2 }}>
        <span>nur Stadt</span><span>25 km</span><span>50 km</span>
      </div>
    </div>
  );
}


function LocationSuggestInput({ value, selected, onInput, onSelect }) {
  const [suggestions, setSuggestions] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);
  const abortRef = React.useRef(null);

  React.useEffect(() => {
    const query = String(value || '').trim();
    if (selected && query === selected) return;
    if (query.length < 2) {
      setSuggestions([]);
      setError(null);
      return undefined;
    }

    const handle = setTimeout(async () => {
      abortRef.current?.abort?.();
      const controller = new AbortController();
      abortRef.current = controller;
      setLoading(true);
      setError(null);
      try {
        const response = await fetch(`/revamp-api/locations?q=${encodeURIComponent(query)}`, {
          headers: { Accept: 'application/json' },
          signal: controller.signal,
        });
        if (!response.ok) throw new Error('Standortsuche derzeit nicht verfügbar');
        const payload = await response.json();
        setSuggestions(Array.isArray(payload.locations) ? payload.locations : []);
        if (payload.available === false) setError(payload.message || 'Standortsuche derzeit nicht verfügbar');
      } catch (err) {
        if (err.name !== 'AbortError') {
          setSuggestions([]);
          setError(err.message || 'Standortsuche derzeit nicht verfügbar');
        }
      } finally {
        setLoading(false);
      }
    }, 250);

    return () => clearTimeout(handle);
  }, [value, selected]);

  return (
    <div style={{ position: 'relative' }}>
      <Input value={value} onChange={onInput} placeholder="Stadt, Stadtteil oder PLZ" />
      {selected && (
        <div className="chip chip-success" style={{ marginTop: 8, fontSize: 12 }}>
          <I.check style={{ width: 14, height: 14 }} /> {selected}
        </div>
      )}
      {loading && <div style={{ fontSize: 12, color: 'var(--ink-muted)', marginTop: 8 }}>Suche nach Standorten…</div>}
      {error && <div style={{ fontSize: 12, color: 'var(--danger)', marginTop: 8 }}>{error}</div>}
      {!selected && !loading && String(value || '').trim().length >= 2 && suggestions.length === 0 && !error && (
        <div style={{ fontSize: 12, color: 'var(--ink-muted)', marginTop: 8 }}>Keine Treffer gefunden.</div>
      )}
      {!selected && suggestions.length > 0 && (
        <div className="card" style={{ marginTop: 8, padding: 6, maxHeight: 240, overflowY: 'auto' }}>
          {suggestions.map(location => {
            const display = location.display_name || location.name || '';
            return (
              <button key={`${location.id}-${display}`} type="button" onClick={() => onSelect(location)} style={{
                width: '100%', background: 'transparent', border: 0, padding: '10px 12px', borderRadius: 10,
                textAlign: 'left', cursor: 'pointer', color: 'var(--ink)', display: 'flex', justifyContent: 'space-between', gap: 8,
              }}>
                <span style={{ fontSize: 14, fontWeight: 700 }}>{display}</span>
                <span style={{ fontSize: 11, color: 'var(--ink-muted)' }}>ID {location.id}</span>
              </button>
            );
          })}
        </div>
      )}
      <p style={{ fontSize: 11, color: 'var(--ink-muted)', margin: '8px 4px 0', lineHeight: 1.45 }}>
        Wie in der alten App wird die Kleinanzeigen-Ortssuche verwendet. Bitte einen Vorschlag übernehmen, damit PLZ/Stadtteil und Location-ID korrekt sind.
      </p>
    </div>
  );
}

function BuilderStep2({ data, update }) {
  const isKauf = data.type === 'kauf';
  return (
    <div>
      <StepHeader
        overline="Budget & Größe"
        title="Welche Maße passen?"
        subtitle="Preis, Zimmer, Wohnfläche. Bereiche statt fester Werte funktionieren am besten."
      />
      <Label>{isKauf ? 'Kaufpreis' : 'Warmmiete'}</Label>
      <RangeRow
        min={data.priceMin} max={data.priceMax}
        onMin={v => update('priceMin', v)} onMax={v => update('priceMax', v)}
        fmt={isKauf ? fmtPriceShort : v => v + ' €'}
        absMin={isKauf ? 50000 : 300} absMax={isKauf ? 2000000 : 4000}
        step={isKauf ? 25000 : 50}
      />
      <Label style={{ marginTop: 24 }}>Zimmer</Label>
      <RangeRow
        min={data.roomsMin} max={data.roomsMax}
        onMin={v => update('roomsMin', v)} onMax={v => update('roomsMax', v)}
        fmt={v => v + ' Zi.'}
        absMin={1} absMax={8}
        step={0.5}
      />
      <Label style={{ marginTop: 24 }}>Wohnfläche</Label>
      <RangeRow
        min={data.areaMin} max={data.areaMax}
        onMin={v => update('areaMin', v)} onMax={v => update('areaMax', v)}
        fmt={v => v + ' m²'}
        absMin={20} absMax={300}
        step={5}
      />
    </div>
  );
}

function BuilderStep3({ data, update }) {
  const toggle = (kw, list, listKey) => {
    const set = new Set(list);
    if (set.has(kw)) set.delete(kw); else set.add(kw);
    update(listKey, [...set]);
  };
  const presets = ['altbau', 'balkon', 'stuck', 'dielen', 'aufzug', 'garten', 'einbauküche', 'saniert', 'erstbezug', 'denkmal'];
  const exPresets = ['erbpacht', 'sanierungsbedürftig', 'wbs', 'möbliert', 'tausch'];

  const [kwInput, setKwInput] = React.useState('');
  const [exInput, setExInput] = React.useState('');

  return (
    <div>
      <StepHeader
        overline="Stichwörter"
        title="Was darf nicht fehlen?"
        subtitle="Suchwörter in Titel oder Beschreibung. Mehrere mit Komma trennen."
      />
      <Label>Muss enthalten</Label>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10 }}>
        {data.keywords.map(k => (
          <span key={k} className="chip chip-success" style={{ paddingRight: 6 }}>
            {k}
            <button onClick={() => toggle(k, data.keywords, 'keywords')} style={{
              background: 'transparent', border: 0, padding: 0, marginLeft: 4, cursor: 'pointer', display: 'flex',
            }}><I.x style={{ width: 14, height: 14, color: 'var(--success)' }} /></button>
          </span>
        ))}
      </div>
      <Input
        value={kwInput} onChange={setKwInput}
        placeholder="Stichwort eingeben + ↵"
        onKeyDown={e => {
          if (e.key === 'Enter' && kwInput.trim()) {
            update('keywords', [...data.keywords, kwInput.trim().toLowerCase()]);
            setKwInput('');
          }
        }}
      />
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 8 }}>
        {presets.filter(p => !data.keywords.includes(p)).map(p => (
          <button key={p}
            onClick={() => update('keywords', [...data.keywords, p])}
            style={{ background: 'transparent', border: '1px dashed var(--border-strong)', color: 'var(--ink-muted)', padding: '4px 10px', borderRadius: 999, fontSize: 12, fontWeight: 500, cursor: 'pointer' }}
          >+ {p}</button>
        ))}
      </div>

      <Label style={{ marginTop: 28 }}>Ausschließen</Label>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10 }}>
        {data.excludeKeywords.map(k => (
          <span key={k} className="chip chip-danger" style={{ paddingRight: 6 }}>
            – {k}
            <button onClick={() => toggle(k, data.excludeKeywords, 'excludeKeywords')} style={{
              background: 'transparent', border: 0, padding: 0, marginLeft: 4, cursor: 'pointer', display: 'flex',
            }}><I.x style={{ width: 14, height: 14, color: 'var(--danger)' }} /></button>
          </span>
        ))}
      </div>
      <Input
        value={exInput} onChange={setExInput}
        placeholder="Ausschluss eingeben + ↵"
        onKeyDown={e => {
          if (e.key === 'Enter' && exInput.trim()) {
            update('excludeKeywords', [...data.excludeKeywords, exInput.trim().toLowerCase()]);
            setExInput('');
          }
        }}
      />
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 8 }}>
        {exPresets.filter(p => !data.excludeKeywords.includes(p)).map(p => (
          <button key={p}
            onClick={() => update('excludeKeywords', [...data.excludeKeywords, p])}
            style={{ background: 'transparent', border: '1px dashed var(--border-strong)', color: 'var(--ink-muted)', padding: '4px 10px', borderRadius: 999, fontSize: 12, fontWeight: 500, cursor: 'pointer' }}
          >+ {p}</button>
        ))}
      </div>
    </div>
  );
}

function BuilderStep4({ data, update }) {
  const togglePlatform = (p) => {
    const set = new Set(data.platforms);
    if (set.has(p)) set.delete(p); else set.add(p);
    update('platforms', [...set]);
  };
  return (
    <div>
      <StepHeader
        overline="Quellen & KI"
        title="Wo & wie suchen?"
        subtitle="Plattformen und automatische KI-Bewertung."
      />
      <Label>Plattformen</Label>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        <PlatformOption
          name="ImmoScout24"
          desc="Großes Angebot, regelmäßige Updates"
          active={data.platforms.includes('immoscout24')}
          onToggle={() => togglePlatform('immoscout24')}
          color="#1F6B3A"
        />
        <PlatformOption
          name="Kleinanzeigen"
          desc="Oft provisionsfrei, kleinere Anbieter"
          active={data.platforms.includes('kleinanzeigen')}
          onToggle={() => togglePlatform('kleinanzeigen')}
          color="#C28428"
        />
      </div>

      {data.type === 'kauf' && (
        <>
          <Label style={{ marginTop: 24 }}>KI-Bewertung</Label>
          <div
            onClick={() => update('aiEnabled', !data.aiEnabled)}
            className="card" style={{ padding: 16, cursor: 'pointer' }}
          >
            <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
              <div style={{
                width: 40, height: 40, borderRadius: 12,
                background: data.aiEnabled ? 'var(--primary)' : 'var(--surface-2)',
                color: data.aiEnabled ? '#fff' : 'var(--ink-muted)',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                flexShrink: 0,
              }}>
                <I.spark />
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--ink)' }}>Automatische KI-Analyse</div>
                <div style={{ fontSize: 12, color: 'var(--ink-muted)', marginTop: 4, lineHeight: 1.5 }}>
                  Jedes neue Inserat erhält einen Profitabilitäts-Score (0–100), inkl. Stärken, Risiken & Renditeschätzung.
                </div>
              </div>
              <Toggle on={data.aiEnabled} />
            </div>
          </div>
          {data.aiEnabled && (
            <p style={{ fontSize: 11, color: 'var(--ink-muted)', marginTop: 8, padding: '0 4px', lineHeight: 1.5 }}>
              Verbrauch: ca. 1 KI-Token pro Inserat. Bewertungen ≥ 80 erhalten Sie als Push-Mitteilung.
            </p>
          )}
        </>
      )}

      <div className="card" style={{ marginTop: 24, padding: 16, background: 'var(--surface-2)' }}>
        <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink-muted)', textTransform: 'uppercase', letterSpacing: 0.05, marginBottom: 8 }}>
          Zusammenfassung
        </div>
        <div style={{ fontSize: 14, color: 'var(--ink)', lineHeight: 1.6 }}>
          {data.type === 'kauf' ? 'Kauf' : 'Miete'} in <strong>{data.locationDisplay || data.city || '—'}</strong> +{data.radius}km<br/>
          <strong>{fmtPriceShort(data.priceMin)}–{fmtPriceShort(data.priceMax)}</strong>, {data.roomsMin}–{data.roomsMax} Zi., {data.areaMin}–{data.areaMax} m²<br/>
          {data.keywords.length > 0 && <>Stichwörter: {data.keywords.join(', ')}<br/></>}
          Plattformen: {data.platforms.length}
        </div>
      </div>
    </div>
  );
}

function PlatformOption({ name, desc, active, onToggle, color }) {
  return (
    <div onClick={onToggle} className="card" style={{ padding: 14, cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 12 }}>
      <div style={{ width: 36, height: 36, borderRadius: 10, background: color + '20', color, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <I.globe />
      </div>
      <div style={{ flex: 1 }}>
        <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--ink)' }}>{name}</div>
        <div style={{ fontSize: 12, color: 'var(--ink-muted)' }}>{desc}</div>
      </div>
      <div style={{
        width: 24, height: 24, borderRadius: 7, flexShrink: 0,
        background: active ? 'var(--ink)' : 'transparent',
        border: active ? '0' : '2px solid var(--border-strong)',
        display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff',
      }}>{active && <I.check style={{ width: 16, height: 16 }} />}</div>
    </div>
  );
}

function Toggle({ on }) {
  return (
    <div style={{
      width: 44, height: 26, borderRadius: 999, flexShrink: 0,
      background: on ? 'var(--primary)' : 'var(--border-strong)',
      position: 'relative', transition: 'background .2s ease',
    }}>
      <div style={{
        position: 'absolute', top: 3, left: on ? 21 : 3,
        width: 20, height: 20, borderRadius: 999, background: '#fff',
        boxShadow: '0 1px 3px rgba(0,0,0,.2)', transition: 'left .2s ease',
      }} />
    </div>
  );
}

// ─── Form primitives ───────────────────────────────────────────────────
function Label({ children, style }) {
  return <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink-muted)', textTransform: 'uppercase', letterSpacing: 0.04, marginBottom: 8, ...style }}>{children}</div>;
}
function Input({ value, onChange, placeholder, onKeyDown, type = 'text' }) {
  return (
    <input
      value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder}
      type={type} onKeyDown={onKeyDown}
      style={{
        width: '100%', padding: '13px 14px', fontSize: 15, borderRadius: 12,
        background: 'var(--surface)', border: '1px solid var(--border)',
        fontFamily: 'var(--font-sans)', color: 'var(--ink)', outline: 'none',
        boxSizing: 'border-box',
      }}
    />
  );
}
function Pill({ children, active, onClick }) {
  return (
    <button onClick={onClick} style={{
      padding: '9px 14px', borderRadius: 999, border: 0, cursor: 'pointer',
      background: active ? 'var(--ink)' : 'var(--surface)',
      color: active ? '#fff' : 'var(--ink)',
      fontSize: 13, fontWeight: 600,
      boxShadow: active ? 'none' : 'inset 0 0 0 1px var(--border)',
    }}>{children}</button>
  );
}
function RangeRow({ min, max, onMin, onMax, fmt, absMin, absMax, step }) {
  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 16, fontWeight: 700, marginBottom: 10 }}>
        <span>{fmt(min)}</span>
        <span style={{ color: 'var(--ink-muted)' }}>—</span>
        <span>{fmt(max)}</span>
      </div>
      <div style={{ display: 'flex', gap: 8 }}>
        <input type="range" min={absMin} max={absMax} step={step} value={min}
          onChange={e => onMin(Math.min(+e.target.value, max))}
          style={{ flex: 1, accentColor: 'var(--primary)' }}
        />
        <input type="range" min={absMin} max={absMax} step={step} value={max}
          onChange={e => onMax(Math.max(+e.target.value, min))}
          style={{ flex: 1, accentColor: 'var(--primary)' }}
        />
      </div>
    </div>
  );
}

// ─── SEARCH RESULTS ────────────────────────────────────────────────────
function ResultsScreen({ ctx, searchId }) {
  const { listings, searches, navigate, back, favs, toggleFav, deleteSearch, refreshSearch, evaluateSearch, exportSearch, busy } = ctx;
  const search = searches.find(s => s.id === searchId) || searches[0];
  const [sort, setSort] = React.useState('score'); // score | price | newest
  const [view, setView] = React.useState('cards'); // cards | table
  const [filterOpen, setFilterOpen] = React.useState(false);
  const [filters, setFilters] = React.useState({
    platforms: { immoscout24: true, kleinanzeigen: true },
    minScore: 0,
    provFreeOnly: false,
  });
  const [refreshing, setRefreshing] = React.useState(false);

  // Apply filters
  if (!search) {
    return (
      <div style={{ height: '100%', background: 'var(--bg)' }}>
        <TopBar title="Suchergebnisse" onBack={back} />
        <EmptyState icon={<I.search />} title="Keine Suche gefunden" subtitle="Legen Sie zuerst eine Suche an." />
      </div>
    );
  }

  let filtered = listings.filter(l => String(l.searchId) === String(search.id));
  if (search.category === 'kauf') {
    if (search.priceMin) filtered = filtered.filter(l => l.price >= search.priceMin);
    if (search.priceMax) filtered = filtered.filter(l => l.price <= search.priceMax);
  }
  filtered = filtered.filter(l => filters.platforms[l.platform]);
  if (filters.minScore > 0) filtered = filtered.filter(l => Number(l.aiScore ?? 0) >= Number(filters.minScore));
  if (filters.provFreeOnly) filtered = filtered.filter(l => l.provisionsfrei);

  filtered = [...filtered].sort((a, b) => {
    if (sort === 'score') return (b.aiScore || 0) - (a.aiScore || 0);
    if (sort === 'price') return a.price - b.price;
    if (sort === 'newest') return new Date(b.posted) - new Date(a.posted);
    return 0;
  });

  const doRefresh = async () => {
    setRefreshing(true);
    try {
      await refreshSearch(search.taskId || search.id);
    } finally {
      setRefreshing(false);
    }
  };
  const doEvaluate = async () => {
    await evaluateSearch(search.taskId || search.id);
  };
  const doExport = () => {
    exportSearch(search.taskId || search.id);
  };
  const doDelete = async () => {
    if (confirm(`Suche „${search.name}" wirklich löschen?`)) {
      await deleteSearch(search.taskId || search.id);
      back();
    }
  };

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--bg)' }}>
      <TopBar
        title={search.name}
        onBack={back}
        trailing={<>
          <IconBtn onClick={doRefresh}>
            <I.refresh style={{
              animation: refreshing ? 'spin .8s linear infinite' : 'none',
            }} />
          </IconBtn>
          <ResultsMoreMenu onExport={doExport} onEvaluate={doEvaluate} onDelete={doDelete} />
        </>}
      />
      <style>{`@keyframes spin { from { transform: rotate(0) } to { transform: rotate(360deg) } }`}</style>

      {/* Filter / sort bar */}
      <div style={{
        position: 'sticky', top: 'auto', zIndex: 10,
        padding: '4px 16px 12px', display: 'flex', gap: 8, alignItems: 'center',
        background: 'var(--bg)', borderBottom: '0.5px solid var(--border)',
        overflowX: 'auto',
      }} className="no-scrollbar">
        <button onClick={() => setFilterOpen(true)} className="chip" style={{ flexShrink: 0, padding: '7px 12px', background: 'var(--surface)', border: '1px solid var(--border)' }}>
          <I.filter style={{ width: 14, height: 14 }} /> Filter
          {(filters.minScore > 0 || filters.provFreeOnly) && (
            <span style={{ background: 'var(--primary)', color: '#fff', borderRadius: 999, fontSize: 9, padding: '1px 5px', marginLeft: 2 }}>•</span>
          )}
        </button>
        <SortPill active={sort === 'score'} onClick={() => setSort('score')}>KI-Score</SortPill>
        <SortPill active={sort === 'price'} onClick={() => setSort('price')}>Preis ↑</SortPill>
        <SortPill active={sort === 'newest'} onClick={() => setSort('newest')}>Neueste</SortPill>
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 0, background: 'var(--surface)', borderRadius: 999, padding: 3, border: '1px solid var(--border)' }}>
          <ViewBtn active={view === 'cards'} onClick={() => setView('cards')}><I.grid style={{ width: 14, height: 14 }} /></ViewBtn>
          <ViewBtn active={view === 'table'} onClick={() => setView('table')}><I.list style={{ width: 14, height: 14 }} /></ViewBtn>
        </div>
      </div>

      <div className="phone-scroll" style={{ flex: 1, padding: '12px 16px 100px' }}>
        {/* Summary */}
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '4px 4px 12px' }}>
          <div style={{ fontSize: 13, color: 'var(--ink-muted)' }}>
            <strong style={{ color: 'var(--ink)' }}>{filtered.length}</strong> Treffer · zuletzt aktualisiert {fmtRelative(search.lastRun)}
            {busy && <span> · arbeitet...</span>}
          </div>
          {search.newToday > 0 && <span className="chip chip-accent" style={{ fontSize: 10 }}>+{search.newToday} neu</span>}
        </div>

        {filtered.length === 0 ? (
          <EmptyState
            icon={<I.search />}
            title="Keine Treffer"
            subtitle="Lockern Sie die Filter oder fügen Sie weitere Plattformen hinzu."
            cta={<button onClick={() => setFilters({ platforms: { immoscout24: true, kleinanzeigen: true }, minScore: 0, provFreeOnly: false })} className="btn btn-outline">Filter zurücksetzen</button>}
          />
        ) : view === 'cards' ? (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {filtered.map(l => (
              <ListingCard key={l.id} listing={l} onTap={() => navigate('listing', { id: l.id })} isFav={favs.has(l.id)} onFav={toggleFav} />
            ))}
          </div>
        ) : (
          <ResultsTable listings={filtered} navigate={navigate} favs={favs} toggleFav={toggleFav} />
        )}
      </div>

      {/* Filter sheet */}
      <Sheet open={filterOpen} onClose={() => setFilterOpen(false)} title="Filter" height="62%">
        <div style={{ padding: '4px 20px 24px' }}>
          <Label>Plattformen</Label>
          <div style={{ display: 'flex', gap: 8, marginBottom: 24 }}>
            <FilterToggleCard
              label="ImmoScout24" active={filters.platforms.immoscout24}
              onClick={() => setFilters(f => ({ ...f, platforms: { ...f.platforms, immoscout24: !f.platforms.immoscout24 } }))}
            />
            <FilterToggleCard
              label="Kleinanzeigen" active={filters.platforms.kleinanzeigen}
              onClick={() => setFilters(f => ({ ...f, platforms: { ...f.platforms, kleinanzeigen: !f.platforms.kleinanzeigen } }))}
            />
          </div>

          {search.category === 'kauf' && (
            <>
              <Label>Mindest-KI-Score: <strong>{filters.minScore || 'alle'}</strong></Label>
              <input
                type="range" min="0" max="90" step="10" value={filters.minScore}
                onChange={e => setFilters(f => ({ ...f, minScore: +e.target.value }))}
                style={{ width: '100%', accentColor: 'var(--primary)' }}
              />
              <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--ink-muted)', marginTop: 2, marginBottom: 24 }}>
                <span>alle</span><span>50</span><span>80+</span>
              </div>
            </>
          )}

          <Label>Nur provisionsfrei</Label>
          <div onClick={() => setFilters(f => ({ ...f, provFreeOnly: !f.provFreeOnly }))} className="card" style={{ padding: 14, cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 10 }}>
            <div style={{ flex: 1, fontSize: 14, fontWeight: 600 }}>Maklerprovision ausschließen</div>
            <Toggle on={filters.provFreeOnly} />
          </div>

          <button
            onClick={() => setFilterOpen(false)}
            className="btn btn-primary" style={{ width: '100%', marginTop: 24, padding: 14 }}
          >
            {filtered.length} Treffer anzeigen
          </button>
        </div>
      </Sheet>
    </div>
  );
}

function SortPill({ children, active, onClick }) {
  return (
    <button onClick={onClick} className="chip" style={{
      flexShrink: 0, padding: '7px 12px',
      background: active ? 'var(--ink)' : 'var(--surface)',
      color: active ? '#fff' : 'var(--ink)',
      border: active ? '1px solid var(--ink)' : '1px solid var(--border)',
    }}>{children}</button>
  );
}
function ViewBtn({ active, onClick, children }) {
  return (
    <button onClick={onClick} style={{
      border: 0, padding: '6px 10px', borderRadius: 999, cursor: 'pointer',
      background: active ? 'var(--ink)' : 'transparent',
      color: active ? '#fff' : 'var(--ink-muted)',
      display: 'flex', alignItems: 'center', gap: 4,
    }}>{children}</button>
  );
}
function FilterToggleCard({ label, active, onClick }) {
  return (
    <div onClick={onClick} style={{
      flex: 1, padding: '14px 12px', borderRadius: 12, cursor: 'pointer',
      background: active ? 'var(--ink)' : 'var(--surface)',
      color: active ? '#fff' : 'var(--ink)',
      border: active ? '0' : '1px solid var(--border)',
      fontSize: 13, fontWeight: 600, textAlign: 'center',
      display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
    }}>
      <span style={{ width: 8, height: 8, borderRadius: 999, background: active ? '#fff' : 'var(--border-strong)' }} />
      {label}
    </div>
  );
}
function ResultsMoreMenu({ onExport, onEvaluate, onDelete }) {
  const [open, setOpen] = React.useState(false);
  return (
    <div style={{ position: 'relative' }}>
      <IconBtn onClick={() => setOpen(!open)}><I.more /></IconBtn>
      {open && (
        <>
          <div onClick={() => setOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 50 }} />
          <div style={{
            position: 'absolute', top: 46, right: 0, zIndex: 60,
            background: 'var(--surface)', borderRadius: 14, padding: 6,
            boxShadow: 'var(--shadow-pop)', minWidth: 200,
            border: '1px solid var(--border)',
          }}>
            <MenuItem icon={<I.spark />} onClick={() => { setOpen(false); onEvaluate(); }}>KI-Bewertung starten</MenuItem>
            <MenuItem icon={<I.download />} onClick={() => { setOpen(false); onExport(); }}>Als CSV exportieren</MenuItem>
            <div style={{ height: 1, background: 'var(--border)', margin: '4px 6px' }} />
            <MenuItem icon={<I.trash />} danger onClick={() => { setOpen(false); onDelete(); }}>Suche löschen</MenuItem>
          </div>
        </>
      )}
    </div>
  );
}
function MenuItem({ icon, children, onClick, danger }) {
  return (
    <button onClick={onClick} style={{
      width: '100%', padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 10,
      background: 'transparent', border: 0, cursor: 'pointer',
      color: danger ? 'var(--danger)' : 'var(--ink)',
      fontSize: 14, fontWeight: 500, borderRadius: 9, textAlign: 'left',
    }}>{icon}{children}</button>
  );
}

function ResultsTable({ listings, navigate, favs, toggleFav }) {
  return (
    <div className="card" style={{ overflow: 'hidden' }}>
      {listings.map((l, i) => (
        <div
          key={l.id} onClick={() => navigate('listing', { id: l.id })}
          style={{
            display: 'flex', gap: 12, padding: 12, alignItems: 'center', cursor: 'pointer',
            borderBottom: i < listings.length - 1 ? '0.5px solid var(--border)' : 'none',
          }}
        >
          <div className="photo" style={{ width: 64, height: 64, borderRadius: 10, backgroundImage: `url(${l.photos[0]})`, flexShrink: 0 }} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--ink)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{l.title}</div>
            <div style={{ fontSize: 11, color: 'var(--ink-muted)', marginTop: 2 }}>
              {l.district} · {fmtArea(l.area)} · {l.rooms} Zi.
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 6 }}>
              <PlatformBadge platform={l.platform} />
              <span style={{ fontSize: 13, fontWeight: 700 }}>{fmtPriceShort(l.price)}</span>
            </div>
          </div>
          {l.aiScore !== null && l.aiScore !== undefined && (
            <div style={{
              width: 32, height: 32, borderRadius: 999, color: '#fff', fontSize: 12, fontWeight: 800,
              background: l.aiScore >= 80 ? '#2F8F5A' : l.aiScore >= 60 ? '#C28428' : '#C8331C',
              display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
            }}>{l.aiScore}</div>
          )}
        </div>
      ))}
    </div>
  );
}

Object.assign(window, { DashboardScreen, SearchBuilderScreen, ResultsScreen, IconBtn, Section, Toggle, Label });
