/* global React */
// Bike-Konfigurator — UI-Komponenten

const { useState, useEffect, useMemo, useCallback, useRef } = React;
const { fmtPrice, fmtNum, SLOT_LABELS, SLOT_TO_POOL, PRIMARY_SLOTS, SECONDARY_SLOTS, TERRAIN_OPTIONS, STYLE_OPTIONS, SKILL_OPTIONS } = window.BikeFmt;
const Icon = window.BikeIcon;

// ----- Brand registry -----
const BRAND_MAP = {
  "Shimano":      { url: "https://www.shimano.com",           logo: "https://logo.clearbit.com/shimano.com" },
  "SRAM":         { url: "https://www.sram.com",              logo: "https://logo.clearbit.com/sram.com" },
  "RockShox":     { url: "https://www.sram.com/en/rockshox",  logo: "https://logo.clearbit.com/sram.com" },
  "Fox":          { url: "https://www.ridefox.com",           logo: "https://logo.clearbit.com/ridefox.com" },
  "Maxxis":       { url: "https://www.maxxis.com",            logo: "https://logo.clearbit.com/maxxis.com" },
  "Schwalbe":     { url: "https://www.schwalbe.com",          logo: "https://logo.clearbit.com/schwalbe.com" },
  "Crankbrothers":{ url: "https://www.crankbrothers.com",     logo: "https://logo.clearbit.com/crankbrothers.com" },
  "OneUp":        { url: "https://www.oneupcomponents.com",   logo: "https://logo.clearbit.com/oneupcomponents.com" },
  "Ergon":        { url: "https://www.ergon-bike.com",        logo: "https://logo.clearbit.com/ergon-bike.com" },
  "BikeYoke":     { url: "https://bikeyoke.de",               logo: "https://logo.clearbit.com/bikeyoke.de" },
  "Bosch":        { url: "https://www.bosch-ebike.com",       logo: "https://logo.clearbit.com/bosch-ebike.com" },
  "DT Swiss":     { url: "https://www.dtswiss.com",           logo: "https://logo.clearbit.com/dtswiss.com" },
  "Suntour":      { url: "https://www.srsuntour-cycling.com", logo: "https://logo.clearbit.com/srsuntour-cycling.com" },
  "ODI":          { url: "https://www.odigrips.com",          logo: "https://logo.clearbit.com/odigrips.com" },
  "SQlab":        { url: "https://www.sq-lab.com",            logo: "https://logo.clearbit.com/sq-lab.com" },
  "X-Fusion":     { url: "https://www.xfusionshox.com",       logo: "https://logo.clearbit.com/xfusionshox.com" },
  "KS":           { url: "https://www.kindshock.com",         logo: "https://logo.clearbit.com/kindshock.com" },
  "Magura":       { url: "https://www.magura.com",            logo: "https://logo.clearbit.com/magura.com" },
  "TRP":          { url: "https://www.trpcycling.com",        logo: "https://logo.clearbit.com/trpcycling.com" },
  "Enve":         { url: "https://www.enve.com",              logo: "https://logo.clearbit.com/enve.com" },
  "Brand-X":      { url: "https://www.chainreactioncycles.com", logo: "https://logo.clearbit.com/chainreactioncycles.com" },
};

const FALLBACK_MARKETPLACE_PARTNERS = [
  {
    id: "bike_discount",
    name: "Bike-Discount",
    status: "pending",
    search_url_template: "https://www.bike-discount.de/de/search?sSearch={query_encoded}",
    tracking_url_template: "",
    priority: 10
  },
  {
    id: "bike24",
    name: "Bike24",
    status: "pending",
    search_url_template: "https://www.bike24.de/search?searchTerm={query_encoded}",
    tracking_url_template: "",
    priority: 20
  },
  {
    id: "mantel",
    name: "Mantel",
    status: "pending",
    search_url_template: "https://www.mantel.com/de/search?search={query_encoded}",
    tracking_url_template: "",
    priority: 50
  }
];

function detectBrand(name) {
  for (const brand of Object.keys(BRAND_MAP)) {
    if (name && name.toLowerCase().includes(brand.toLowerCase())) return brand;
  }
  return null;
}

function getMarketplacePartners() {
  const registry = window.BikeAffiliatePartners;
  const partners = Array.isArray(registry?.partners) ? registry.partners : FALLBACK_MARKETPLACE_PARTNERS;
  const usable = partners
    .filter(p => p.status !== "disabled" && p.search_url_template)
    .sort((a, b) => (a.priority || 999) - (b.priority || 999));
  return usable.length ? usable : FALLBACK_MARKETPLACE_PARTNERS;
}

function fillMarketplaceTemplate(template, item, partner, destinationUrl) {
  const rawQuery = item?.name || "mountainbike komponenten";
  const encodedQuery = encodeURIComponent(rawQuery);
  const campaign = "component_offer";
  const content = item?.id || "component";
  return template
    .replaceAll("{query}", rawQuery)
    .replaceAll("{query_encoded}", encodedQuery)
    .replaceAll("{item_id}", content)
    .replaceAll("{partner_id}", partner.id || partner.name || "partner")
    .replaceAll("{campaign}", campaign)
    .replaceAll("{content}", content)
    .replaceAll("{destination_url}", destinationUrl)
    .replaceAll("{destination_url_encoded}", encodeURIComponent(destinationUrl));
}

function appendMarketplaceParams(urlText, item, partner) {
  const url = new URL(urlText);
  const defaults = window.BikeAffiliatePartners?.tracking_defaults || {};
  url.searchParams.set("utm_source", defaults.utm_source || "bikeforge");
  url.searchParams.set("utm_medium", defaults.utm_medium || "marketplace");
  url.searchParams.set("utm_campaign", defaults.utm_campaign || "component_offer");
  url.searchParams.set("utm_content", item?.id || "component");
  url.searchParams.set("partner", partner.id || partner.name || "partner");
  return url.toString();
}

function marketplaceUrlFor(item, partner = getMarketplacePartners()[0]) {
  const destination = fillMarketplaceTemplate(partner.search_url_template, item, partner, "");
  const destinationWithParams = appendMarketplaceParams(destination, item, partner);
  if (partner.status === "active" && partner.tracking_url_template) {
    return fillMarketplaceTemplate(partner.tracking_url_template, item, partner, destinationWithParams);
  }
  return destinationWithParams;
}

function MarketplaceButton({ item, compact = false }) {
  if (!item) return null;
  return (
    <a
      href={marketplaceUrlFor(item)}
      target="_blank"
      rel="noopener noreferrer sponsored"
      onClick={e => e.stopPropagation()}
      title={`${item.name} Angebote bei ${getMarketplacePartners()[0]?.name || "Partnern"} prüfen`}
      style={{
        display: "inline-flex", alignItems: "center", gap: compact ? 4 : 7,
        background: compact ? "transparent" : "var(--accent-soft)",
        color: compact ? "var(--accent)" : "var(--ink)",
        border: compact ? "none" : "1px solid var(--accent)",
        padding: compact ? 0 : "6px 10px",
        textDecoration: "none",
        font: `700 ${compact ? 10 : 11}px/1 var(--font-sans)`,
        letterSpacing: "0.7px",
        textTransform: "uppercase",
        whiteSpace: "nowrap"
      }}
    >
      Angebote
      <svg width={compact ? 8 : 10} height={compact ? 8 : 10} viewBox="0 0 10 10" fill="none" aria-hidden="true">
        <path d="M2 8L8 2M8 2H4M8 2V6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square"/>
      </svg>
    </a>
  );
}

function BrandBadge({ name, size = "sm" }) {
  const brand = detectBrand(name);
  if (!brand) return null;
  const { url, logo } = BRAND_MAP[brand];
  const [imgOk, setImgOk] = useState(true);
  const isLarge = size === "lg";
  return (
    <a href={url} target="_blank" rel="noopener noreferrer"
      onClick={e => e.stopPropagation()}
      title={`${brand} Website`}
      style={{
        display: "inline-flex", alignItems: "center", gap: isLarge ? 8 : 5,
        background: "rgba(255,255,255,0.06)", border: "1px solid var(--hairline)",
        padding: isLarge ? "6px 12px" : "3px 8px",
        textDecoration: "none", flexShrink: 0,
      }}>
      {imgOk && (
        <img src={logo} alt={brand}
          onError={() => setImgOk(false)}
          style={{ height: isLarge ? 18 : 12, width: "auto", objectFit: "contain", filter: "brightness(0) invert(1)" }} />
      )}
      <span style={{ font: `600 ${isLarge ? 11 : 9}px/1 var(--font-sans)`, letterSpacing: "0.6px", color: "var(--ink-muted)", textTransform: "uppercase" }}>
        {imgOk ? "" : brand}
      </span>
      <svg width={isLarge ? 10 : 8} height={isLarge ? 10 : 8} viewBox="0 0 10 10" fill="none" style={{ opacity: 0.5 }}>
        <path d="M2 8L8 2M8 2H4M8 2V6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square"/>
      </svg>
    </a>
  );
}

// ----- Brand Ticker -----
const TICKER_BRANDS = Object.entries(BRAND_MAP).map(([name, { url, logo }]) => ({ name, url, logo }));

function BrandTicker() {
  // Inject keyframes once
  useEffect(() => {
    if (document.getElementById("bf-ticker-style")) return;
    const s = document.createElement("style");
    s.id = "bf-ticker-style";
    s.textContent = `
      @keyframes bf-marquee {
        0%   { transform: translateX(0); }
        100% { transform: translateX(-50%); }
      }
      .bf-ticker-track { animation: bf-marquee 28s linear infinite; }
      .bf-ticker-track:hover { animation-play-state: paused; }
    `;
    document.head.appendChild(s);
  }, []);

  const items = [...TICKER_BRANDS, ...TICKER_BRANDS]; // seamless loop

  return (
    <div style={{
      overflow: "hidden",
      borderTop: "1px solid var(--hairline)",
      borderBottom: "1px solid var(--hairline)",
      padding: "18px 0",
      background: "rgba(0,0,0,0.25)",
      position: "relative",
    }}>
      {/* fade edges */}
      <div style={{ position: "absolute", inset: 0, zIndex: 2, pointerEvents: "none",
        background: "linear-gradient(90deg, var(--canvas) 0%, transparent 8%, transparent 92%, var(--canvas) 100%)" }} />
      <div className="bf-ticker-track" style={{ display: "flex", gap: 0, width: "max-content" }}>
        {items.map(({ name, url, logo }, i) => (
          <a key={i} href={url} target="_blank" rel="noopener noreferrer"
            title={name}
            style={{
              display: "inline-flex", alignItems: "center", gap: 10,
              padding: "0 36px", textDecoration: "none", flexShrink: 0,
              borderRight: "1px solid var(--hairline)",
            }}>
            <img
              src={logo} alt={name}
              style={{ height: 22, width: "auto", maxWidth: 80, objectFit: "contain",
                filter: "brightness(0) invert(1)", opacity: 0.55,
                transition: "opacity 0.2s" }}
              onMouseEnter={e => e.target.style.opacity = "1"}
              onMouseLeave={e => e.target.style.opacity = "0.55"}
              onError={e => {
                e.target.style.display = "none";
                e.target.nextSibling.style.display = "block";
              }}
            />
            <span style={{ display: "none", font: "700 11px/1 var(--font-sans)", letterSpacing: "1.2px",
              textTransform: "uppercase", color: "var(--ink-muted)" }}>{name}</span>
          </a>
        ))}
      </div>
    </div>
  );
}

// ----- Top Nav -----
function TopNav({ onOpenGarage, savedCount, onReset, user, onLogout, plan, onUpgrade, onOpenExistingBike }) {
  return (
    <div className="topnav">
      <div className="brand-mark">
        <span className="brand-mark-icon"><Icon name="bolt" size={14} /></span>
        BIKEFORGE
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 4 }}>
        {user && (
          <span style={{
            font: "600 11px/1 var(--font-sans)",
            letterSpacing: "0.6px",
            color: "var(--ink-soft)",
            marginRight: 8,
            textTransform: "uppercase"
          }}>
            {user.name}
          </span>
        )}
        {plan === "pro" ? (
          <span style={{
            background: "var(--accent)", color: "var(--accent-ink)",
            font: "700 10px/1 var(--font-sans)", letterSpacing: "1.2px",
            textTransform: "uppercase", padding: "5px 10px", marginRight: 4
          }}>PRO</span>
        ) : (
          <button className="btn btn-ghost btn-sm" onClick={onUpgrade} style={{ marginRight: 4, boxShadow: "inset 0 0 0 1px var(--accent)", color: "var(--accent)" }}>
            Upgrade → Pro
          </button>
        )}
        <button className="btn btn-ghost btn-sm" onClick={onOpenExistingBike} title="Bestandsbike analysieren">
          <Icon name="upload" size={14} /> Bestandsbike
        </button>
        <button className="btn btn-ghost btn-sm" onClick={onReset} title="Profil zurücksetzen">
          <Icon name="refresh" size={14} /> Reset
        </button>
        <button className="btn btn-ghost btn-sm" onClick={onOpenGarage}>
          <Icon name="list" size={14} /> Garage
          {savedCount > 0 && (
            <span style={{
              background: "var(--accent)", color: "var(--accent-ink)",
              padding: "2px 8px", fontSize: 10, fontWeight: 700,
              letterSpacing: "0.6px", marginLeft: 4
            }}>{savedCount}</span>
          )}
        </button>
        {onLogout && (
          <button className="btn btn-ghost btn-sm" onClick={onLogout} title="Abmelden">
            <Icon name="close" size={14} />
          </button>
        )}
        <a href="/legal/datenschutz.html" className="btn btn-ghost btn-sm" style={{ textDecoration: "none" }} title="Datenschutz">
          Legal
        </a>
      </div>
    </div>
  );
}

const EXISTING_BIKE_FIELDS = [
  { key: "fork", label: "Gabel", placeholder: "Fox 36 Performance" },
  { key: "shock", label: "Dämpfer", placeholder: "Fox Float X" },
  { key: "brakes", label: "Bremsen", placeholder: "SRAM Code R" },
  { key: "drivetrain", label: "Antrieb", placeholder: "SRAM GX Eagle" },
  { key: "wheels", label: "Laufräder", placeholder: "DT Swiss EX1700" },
  { key: "tires", label: "Reifen", placeholder: "Maxxis Minion DHF" },
  { key: "dropper", label: "Dropper", placeholder: "OneUp V2 150" },
  { key: "cockpit", label: "Cockpit", placeholder: "Race Face Turbine" },
  { key: "grips", label: "Griffe", placeholder: "ODI Elite Pro" },
  { key: "saddle", label: "Sattel", placeholder: "Ergon SM Pro" },
  { key: "chain", label: "Kette", placeholder: "SRAM GX Eagle Chain" },
  { key: "pedals", label: "Pedale", placeholder: "Crankbrothers Stamp" }
];

const PHOTO_HINTS_BY_SLOT = {
  fork: "Gabel-Decals und linke/rechte Seite freier sichtbar fotografieren.",
  shock: "Daempferbereich im Rahmendreieck heller aufnehmen.",
  brakes: "Bremssattel und Bremshebel naeher sichtbar machen.",
  drivetrain: "Rechte Seite mit Schaltwerk, Kassette und Kurbel fotografieren.",
  wheels: "Naben und Felgenprofil seitlich klar sichtbar lassen.",
  tires: "Reifenflanke lesbar aufnehmen.",
  dropper: "Sattelstuetze und Remote-Hebel heller zeigen.",
  cockpit: "Lenker, Vorbau und Hebel nicht vom Rahmen verdecken lassen.",
  grips: "Lenkerenden und Griffe naeher sichtbar machen.",
  saddle: "Sattel seitlich und von oben nicht verdecken.",
  chain: "Kette und Kassette auf der Antriebsseite sichtbar machen.",
  pedals: "Pedale seitlich freistellen, nicht vom Kurbelarm verdecken lassen."
};

function confidenceLevel(value) {
  const confidence = Math.max(0, Math.min(1, Number(value || 0)));
  if (confidence >= 0.75) return "ok";
  if (confidence >= 0.45) return "check";
  return "low";
}

function confidenceHintFor(field, confidence) {
  const percent = Math.round(Math.max(0, Math.min(1, Number(confidence || 0))) * 100);
  const base = PHOTO_HINTS_BY_SLOT[field.key] || "Komponente manuell pruefen.";
  return `${field.label}: ${percent}% - ${base}`;
}

function ExistingBikeModal({ profile, onApply, onClose }) {
  const [preview, setPreview] = useState(null);
  const [modelName, setModelName] = useState("");
  const [terrain, setTerrain] = useState(profile.terrain || "trail");
  const [bikeType, setBikeType] = useState(profile.bike_type || "analog");
  const [components, setComponents] = useState({});
  const [componentActions, setComponentActions] = useState({});
  const [componentConfidence, setComponentConfidence] = useState({});
  const [analyzing, setAnalyzing] = useState(false);
  const [detailAnalyzingSlot, setDetailAnalyzingSlot] = useState(null);
  const [detailMessage, setDetailMessage] = useState(null);
  const [analysisError, setAnalysisError] = useState(null);
  const [analysisMeta, setAnalysisMeta] = useState(null);

  const setComponent = (key, value) => {
    setComponents(prev => ({ ...prev, [key]: value }));
    if (String(value || "").trim()) {
      setComponentActions(prev => ({ ...prev, [key]: prev[key] || "keep" }));
    } else {
      setComponentConfidence(prev => {
        const next = { ...prev };
        delete next[key];
        return next;
      });
    }
  };

  const applyVisionAnalysis = (payload = {}) => {
    const analysis = payload.analysis || {};
    if (analysis.bike_model_name) setModelName(analysis.bike_model_name);
    if (analysis.frame_category) setTerrain(analysis.frame_category);
    setBikeType(analysis.is_ebike ? "ebike" : "analog");

    const recognized = Object.entries(analysis.components || {})
      .map(([key, value]) => [key, String(value || "").trim()])
      .filter(([, value]) => value);

    if (recognized.length) {
      setComponents(prev => ({ ...prev, ...Object.fromEntries(recognized) }));
      setComponentActions(prev => ({
        ...prev,
        ...Object.fromEntries(recognized.map(([key]) => [key, prev[key] || "keep"]))
      }));
      setComponentConfidence(prev => ({
        ...prev,
        ...Object.fromEntries(
          recognized.map(([key]) => [key, Math.max(0, Math.min(1, Number(analysis.component_confidence?.[key] || 0)))])
        )
      }));
    }

    setAnalysisMeta({
      provider: payload.provider || "vision",
      model: payload.model || "",
      confidence: Number(analysis.confidence || 0),
      observations: Array.isArray(analysis.observations) ? analysis.observations.filter(Boolean) : []
    });
  };

  const applyDetailAnalysis = (slot, payload = {}) => {
    const analysis = payload.analysis || {};
    const value = String(analysis.components?.[slot] || "").trim();
    const confidence = Math.max(0, Math.min(1, Number(analysis.component_confidence?.[slot] || 0)));
    const field = EXISTING_BIKE_FIELDS.find(item => item.key === slot);

    if (!value) {
      setDetailMessage({
        kind: "warn",
        text: `${field?.label || slot}: Detailfoto konnte kein eindeutiges Teil erkennen. Feld bitte manuell pruefen.`
      });
      setComponentConfidence(prev => ({ ...prev, [slot]: confidence }));
      return;
    }

    setComponents(prev => ({ ...prev, [slot]: value }));
    setComponentActions(prev => ({ ...prev, [slot]: prev[slot] || "keep" }));
    setComponentConfidence(prev => ({ ...prev, [slot]: confidence }));
    setDetailMessage({
      kind: confidence >= 0.75 ? "ok" : "warn",
      text: `${field?.label || slot}: Detailfoto erkannt - ${value} (${Math.round(confidence * 100)}%).`
    });
  };

  const analyzeImage = async (file) => {
    setAnalyzing(true);
    setAnalysisError(null);
    setDetailMessage(null);
    setAnalysisMeta(null);
    try {
      const body = new FormData();
      body.append("image", file);
      const response = await fetch(`${window.BIKEFORGE_API_URL}/vision/analyze`, { method: "POST", body });
      const payload = await response.json().catch(() => ({}));
      if (!response.ok) {
        throw new Error(payload.detail || payload.error || "Bildanalyse fehlgeschlagen.");
      }
      applyVisionAnalysis(payload);
    } catch (error) {
      setAnalysisError(error.message || "Bildanalyse fehlgeschlagen.");
    } finally {
      setAnalyzing(false);
    }
  };

  const analyzeDetailImage = async (slot, file) => {
    setDetailAnalyzingSlot(slot);
    setAnalysisError(null);
    setDetailMessage(null);
    try {
      const body = new FormData();
      body.append("image", file);
      body.append("slot", slot);
      const response = await fetch(`${window.BIKEFORGE_API_URL}/vision/analyze`, { method: "POST", body });
      const payload = await response.json().catch(() => ({}));
      if (!response.ok) {
        throw new Error(payload.detail || payload.error || "Detailanalyse fehlgeschlagen.");
      }
      applyDetailAnalysis(slot, payload);
    } catch (error) {
      const field = EXISTING_BIKE_FIELDS.find(item => item.key === slot);
      setDetailMessage({
        kind: "error",
        text: `${field?.label || slot}: ${error.message || "Detailanalyse fehlgeschlagen."}`
      });
    } finally {
      setDetailAnalyzingSlot(null);
    }
  };

  const handleFile = (event) => {
    const file = event.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => setPreview(reader.result);
    reader.readAsDataURL(file);
    analyzeImage(file);
    event.target.value = "";
  };

  const handleDetailFile = (slot, event) => {
    const file = event.target.files?.[0];
    if (!file) return;
    analyzeDetailImage(slot, file);
    event.target.value = "";
  };

  const apply = () => {
    onApply({
      model_name: modelName.trim() || "Bestandsbike",
      terrain,
      is_ebike: bikeType === "ebike",
      bike_type: bikeType,
      style: profile.riding_style || "balanced",
      photo_preview: preview,
      components: Object.fromEntries(
        Object.entries(components)
          .map(([key, value]) => [key, String(value || "").trim()])
          .filter(([, value]) => value)
      ),
      component_actions: Object.fromEntries(
        Object.entries(components)
          .map(([key, value]) => [key, String(value || "").trim()])
          .filter(([, value]) => value)
          .map(([key]) => [key, componentActions[key] || "keep"])
      ),
      component_confidence: Object.fromEntries(
        Object.entries(components)
          .map(([key, value]) => [key, String(value || "").trim()])
          .filter(([, value]) => value)
          .map(([key]) => [key, Math.max(0, Math.min(1, Number(componentConfidence[key] || 0)))])
      )
    });
  };

  const confidenceHints = EXISTING_BIKE_FIELDS
    .filter(field => components[field.key] && componentConfidence[field.key] > 0 && componentConfidence[field.key] < 0.75)
    .map(field => ({
      key: field.key,
      level: confidenceLevel(componentConfidence[field.key]),
      text: confidenceHintFor(field, componentConfidence[field.key])
    }));
  const lowConfidenceCount = confidenceHints.filter(hint => hint.level === "low").length;

  return (
    <>
      <div className="drawer-backdrop" onClick={onClose} style={{ zIndex: 920 }} />
      <div style={{
        position: "fixed", inset: "5vh auto 5vh 50%", transform: "translateX(-50%)",
        zIndex: 921, width: "min(980px, 94vw)", overflow: "hidden",
        background: "var(--canvas-card)", border: "1px solid var(--hairline-strong)",
        display: "grid", gridTemplateColumns: "minmax(280px, 0.85fr) 1.15fr"
      }}>
        <div style={{ background: "var(--canvas-deep)", minHeight: 620, position: "relative", borderRight: "1px solid var(--hairline)" }}>
          {preview ? (
            <img src={preview} alt="Bestandsbike Vorschau" style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", filter: "brightness(0.72) saturate(0.95)" }} />
          ) : (
            <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", padding: 28, color: "var(--ink-muted)" }}>
              <img
                src="assets/bike-photo-guide.svg"
                alt="Foto-Anleitung: Bike vollstaendig seitlich, hell und auf Nabenhoehe fotografieren"
                style={{ width: "100%", maxWidth: 430, border: "1px solid var(--hairline-strong)", background: "rgba(0,0,0,0.22)" }}
              />
            </div>
          )}
          <div style={{ position: "absolute", inset: 0, background: "linear-gradient(180deg, rgba(0,0,0,0.15), rgba(0,0,0,0.82))" }} />
          <label style={{
            position: "absolute", left: 28, right: 28, bottom: 28,
            display: "flex", alignItems: "center", justifyContent: "center", gap: 10,
            padding: "16px 18px", background: "rgba(24,24,24,0.82)",
            border: "1px solid var(--hairline-strong)", color: "var(--ink)",
            font: "700 12px/1 var(--font-sans)", letterSpacing: "1.2px",
            textTransform: "uppercase", cursor: "pointer"
          }}>
            <Icon name="upload" size={14} /> {analyzing ? "Analysiere ..." : "Foto wählen"}
            <input type="file" accept="image/*" onChange={handleFile} style={{ display: "none" }} />
          </label>
        </div>

        <div className="scroll-area" style={{ maxHeight: "90vh", padding: "32px 36px 36px" }}>
          <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 18, marginBottom: 28 }}>
            <div>
              <div className="eyebrow eyebrow-accent">Bestandsbike</div>
              <h2 style={{ marginTop: 8, fontSize: 30, lineHeight: 1.1 }}>Ausstattung als Startpunkt.</h2>
              <p style={{ marginTop: 12, color: "var(--ink-soft)", maxWidth: 560 }}>
                Foto hochladen, Vision-Analyse prüfen und sichtbare Teile korrigieren. BikeForge behandelt den Rahmen als vorhandene Basis.
              </p>
              <div style={{
                marginTop: 14, display: "flex", gap: 8, flexWrap: "wrap",
                color: "var(--ink-muted)", font: "700 10px/1 var(--font-sans)",
                letterSpacing: "0.8px", textTransform: "uppercase"
              }}>
                <span style={{ border: "1px solid var(--hairline)", padding: "7px 9px" }}>Seitlich fotografieren</span>
                <span style={{ border: "1px solid var(--hairline)", padding: "7px 9px" }}>Ganzes Bike sichtbar</span>
                <span style={{ border: "1px solid var(--hairline)", padding: "7px 9px" }}>Helles Licht</span>
                <span style={{ border: "1px solid var(--hairline)", padding: "7px 9px" }}>ruhiger Hintergrund</span>
              </div>
            </div>
            <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="close" size={16} /></button>
          </div>

          {(analysisMeta || analysisError || analyzing) && (
            <div style={{
              marginBottom: 22, padding: 14, border: `1px solid ${analysisError ? "rgba(255,98,98,0.45)" : "var(--hairline)"}`,
              background: analysisError ? "rgba(255,98,98,0.08)" : "rgba(255,255,255,0.035)",
              color: analysisError ? "var(--danger)" : "var(--ink-soft)",
              font: "400 13px/1.5 var(--font-sans)"
            }}>
              {analyzing && "Vision-Analyse laeuft. Du kannst die Felder danach weiter bearbeiten."}
              {analysisError && `Vision-Analyse nicht verfuegbar: ${analysisError}`}
              {analysisMeta && !analysisError && (
                <>
                  <strong style={{ color: "var(--ink)" }}>
                    Vision erkannt ({Math.round(Math.max(0, Math.min(1, analysisMeta.confidence)) * 100)}% Sicherheit)
                  </strong>
                  {analysisMeta.observations.length > 0 && (
                    <ul style={{ margin: "8px 0 0", paddingLeft: 18 }}>
                      {analysisMeta.observations.map((item, index) => <li key={index}>{item}</li>)}
                    </ul>
                  )}
                </>
              )}
            </div>
          )}

          {confidenceHints.length > 0 && (
            <div style={{
              marginBottom: 22, padding: 14, border: "1px solid rgba(218,41,28,0.38)",
              background: "rgba(218,41,28,0.07)", color: "var(--ink-soft)",
              font: "400 13px/1.5 var(--font-sans)"
            }}>
              <strong style={{ color: "var(--ink)" }}>
                {lowConfidenceCount >= 3 ? "Foto wahrscheinlich neu aufnehmen" : "Bitte manuell pruefen"}
              </strong>
              <div style={{ marginTop: 6 }}>
                {lowConfidenceCount >= 3
                  ? "Mehrere Teile wurden unsicher erkannt. Seitlicher, heller und mit ruhigem Hintergrund fotografieren."
                  : "Einige erkannte Teile sind unsicher. Pruefe diese Felder vor dem Uebernehmen."}
              </div>
              <ul style={{ margin: "10px 0 0", paddingLeft: 18 }}>
                {confidenceHints.slice(0, 5).map(hint => (
                  <li key={hint.key}>{hint.text}</li>
                ))}
              </ul>
            </div>
          )}

          {detailMessage && (
            <div style={{
              marginBottom: 22, padding: 12, border: `1px solid ${detailMessage.kind === "error" ? "rgba(255,98,98,0.45)" : "var(--hairline)"}`,
              background: detailMessage.kind === "ok" ? "rgba(255,255,255,0.04)" : "rgba(218,41,28,0.07)",
              color: detailMessage.kind === "error" ? "var(--danger)" : "var(--ink-soft)",
              font: "500 13px/1.45 var(--font-sans)"
            }}>
              {detailMessage.text}
            </div>
          )}

          <div style={{ display: "grid", gridTemplateColumns: "1.1fr 0.9fr 0.9fr", gap: 14, marginBottom: 22 }}>
            <div className="field">
              <div className="field-label">Bike / Modell</div>
              <input className="field-input" value={modelName} onChange={e => setModelName(e.target.value)} placeholder="z.B. Cube Stereo Hybrid 140" />
            </div>
            <div className="field">
              <div className="field-label">Typ</div>
              <Segmented options={[{ value: "analog", label: "Bio" }, { value: "ebike", label: "E-Bike" }]} value={bikeType} onChange={setBikeType} />
            </div>
            <div className="field">
              <div className="field-label">Einsatz</div>
              <Segmented options={[{ value: "trail", label: "Trail" }, { value: "enduro", label: "Enduro" }, { value: "xc", label: "XC" }]} value={terrain} onChange={setTerrain} />
            </div>
          </div>

          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
            {EXISTING_BIKE_FIELDS.map(field => (
              <div className="field" key={field.key}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10, marginBottom: 8 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
                    <div className="field-label" style={{ margin: 0 }}>{field.label}</div>
                    {componentConfidence[field.key] > 0 && (
                      <span title="Vision-Sicherheit fuer diese Erkennung" style={{
                        border: "1px solid var(--hairline)", color: componentConfidence[field.key] >= 0.75 ? "var(--accent)" : componentConfidence[field.key] < 0.45 ? "var(--danger)" : "var(--ink-muted)",
                        padding: "3px 6px", font: "700 9px/1 var(--font-sans)", letterSpacing: "0.6px",
                        textTransform: "uppercase", whiteSpace: "nowrap"
                      }}>
                        {Math.round(componentConfidence[field.key] * 100)}%
                      </span>
                    )}
                  </div>
                  <Segmented
                    options={[{ value: "keep", label: "Behalten" }, { value: "replace", label: "Ersetzen" }]}
                    value={componentActions[field.key] || "keep"}
                    onChange={value => setComponentActions(prev => ({ ...prev, [field.key]: value }))}
                  />
                </div>
                <input
                  className="field-input"
                  value={components[field.key] || ""}
                  onChange={e => setComponent(field.key, e.target.value)}
                  placeholder={field.placeholder}
                  style={{ fontSize: 14 }}
                />
                {components[field.key] && componentConfidence[field.key] > 0 && componentConfidence[field.key] < 0.75 && (
                  <label style={{
                    marginTop: 8, display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8,
                    border: "1px solid var(--hairline-strong)", padding: "8px 10px",
                    color: "var(--ink-soft)", font: "700 10px/1 var(--font-sans)",
                    letterSpacing: "0.8px", textTransform: "uppercase", cursor: "pointer"
                  }}>
                    <Icon name="upload" size={12} />
                    {detailAnalyzingSlot === field.key ? "Detailanalyse ..." : "Detailfoto"}
                    <input type="file" accept="image/*" onChange={event => handleDetailFile(field.key, event)} style={{ display: "none" }} />
                  </label>
                )}
              </div>
            ))}
          </div>

          <div style={{
            marginTop: 24, padding: 16, border: "1px solid var(--hairline)",
            background: "rgba(255,255,255,0.03)", color: "var(--ink-soft)",
            font: "400 13px/1.5 var(--font-sans)"
          }}>
            Die Vision-Analyse ist ein Startpunkt, keine technische Garantie. Markiere gute Teile mit Behalten; bei Ersetzen nutzt BikeForge die erkannten Daten nur als Kontext und sucht eine passende neue Komponente.
          </div>

          <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 28 }}>
            <button className="btn btn-ghost" onClick={onClose}>Abbrechen</button>
            <button className="btn btn-primary" onClick={apply}>
              <Icon name="check" size={14} /> Als Basis übernehmen
            </button>
          </div>
        </div>
      </div>
    </>
  );
}

// ----- Upgrade Modal -----
function UpgradeModal({ plan, token, onClose }) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const handleCheckout = async () => {
    setLoading(true);
    setError(null);
    try {
      const res = await fetch("/api/checkout/session", {
        method: "POST",
        headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
      });
      const data = await res.json();
      if (!res.ok) { setError(data.error || "Fehler beim Erstellen der Checkout-Session."); setLoading(false); return; }
      window.location.href = data.url;
    } catch {
      setError("Netzwerkfehler. Bitte versuche es erneut.");
      setLoading(false);
    }
  };

  const features = [
    { label: "Builds speichern",     free: "3 Builds",    pro: "Unbegrenzt" },
    { label: "Komponenten-Tausch",   free: true,          pro: true },
    { label: "Marketplace-Angebote", free: true,          pro: true },
    { label: "Garage & Verlauf",     free: true,          pro: true },
    { label: "Build-Vergleich",      free: false,         pro: true },
    { label: "PDF-Export",           free: false,         pro: true },
    { label: "Prioritäts-Support",   free: false,         pro: true },
  ];

  return (
    <>
      <div className="drawer-backdrop" onClick={onClose} style={{ zIndex: 900 }} />
      <div style={{
        position: "fixed", top: "50%", left: "50%",
        transform: "translate(-50%, -50%)",
        zIndex: 901, background: "var(--canvas-card)",
        border: "1px solid var(--hairline)",
        width: "min(520px, 95vw)", maxHeight: "90vh", overflowY: "auto"
      }}>
        <div style={{ padding: "32px 40px 40px" }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 32 }}>
            <div>
              <div className="eyebrow eyebrow-accent" style={{ marginBottom: 8 }}>Upgrade</div>
              <h2 style={{ font: "500 28px/1.1 var(--font-sans)", letterSpacing: "-0.56px" }}>BikeForge Pro</h2>
            </div>
            <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="close" size={16} /></button>
          </div>

          <div style={{ display: "grid", gridTemplateColumns: "1fr auto auto", gap: "0 24px", marginBottom: 32 }}>
            <div style={{ font: "600 10px/1 var(--font-sans)", letterSpacing: "1px", color: "var(--ink-muted)", textTransform: "uppercase", paddingBottom: 10, borderBottom: "1px solid var(--hairline)" }}>Feature</div>
            <div style={{ font: "600 10px/1 var(--font-sans)", letterSpacing: "1px", color: "var(--ink-muted)", textTransform: "uppercase", paddingBottom: 10, borderBottom: "1px solid var(--hairline)", textAlign: "center" }}>Free</div>
            <div style={{ font: "600 10px/1 var(--font-sans)", letterSpacing: "1px", color: "var(--accent)", textTransform: "uppercase", paddingBottom: 10, borderBottom: "1px solid var(--accent)" }}>Pro</div>
            {features.map((f, i) => (
              <React.Fragment key={i}>
                <div style={{ padding: "14px 0", borderBottom: "1px solid var(--hairline)", font: "400 14px/1 var(--font-sans)", color: "var(--ink)" }}>{f.label}</div>
                <div style={{ padding: "14px 0", borderBottom: "1px solid var(--hairline)", textAlign: "center", color: "var(--ink-muted)", font: "500 13px/1 var(--font-sans)" }}>
                  {f.free === true ? "✓" : f.free === false ? "—" : f.free}
                </div>
                <div style={{ padding: "14px 0", borderBottom: "1px solid var(--hairline)", textAlign: "center", color: "var(--accent)", font: "700 13px/1 var(--font-sans)" }}>
                  {f.pro === true ? "✓" : f.pro === false ? "—" : f.pro}
                </div>
              </React.Fragment>
            ))}
          </div>

          <div style={{ textAlign: "center", marginBottom: 24 }}>
            <div style={{ font: "500 42px/1 var(--font-sans)", letterSpacing: "-0.84px" }}>3,99 €</div>
            <div style={{ font: "400 13px/1 var(--font-sans)", color: "var(--ink-muted)", marginTop: 6 }}>/ Monat · jederzeit kündbar</div>
          </div>

          {error && (
            <div style={{ background: "var(--accent-soft)", border: "1px solid var(--accent)", padding: "10px 16px", marginBottom: 16, font: "500 13px/1.4 var(--font-sans)", color: "var(--ink)" }}>
              {error}
            </div>
          )}

          <button className="btn btn-primary" onClick={handleCheckout} disabled={loading}
            style={{ width: "100%", justifyContent: "center", padding: "18px 0", fontSize: 14 }}>
            {loading ? "Weiterleitung …" : "Jetzt upgraden → Pro"}
          </button>

          <div style={{ textAlign: "center", marginTop: 14, font: "400 12px/1 var(--font-sans)", color: "var(--ink-muted)" }}>
            Sichere Zahlung über Paddle · Steuern und Zahlungsabwicklung durch Merchant of Record
          </div>
        </div>
      </div>
    </>
  );
}

// ----- Profil-Eingabe -----
function ProfileForm({ profile, onChange }) {
  const set = (k, v) => onChange({ ...profile, [k]: v });
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 28 }}>
      <div>
        <div className="eyebrow" style={{ marginBottom: 18 }}>01 — Fahrer-Profil</div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 24 }}>
          <SliderField label="Gewicht" min={50} max={130} step={1} unit="kg"
            value={profile.weight} onChange={(v) => set("weight", v)} />
          <SliderField label="Größe" min={150} max={205} step={1} unit="cm"
            value={profile.height} onChange={(v) => set("height", v)} />
        </div>
      </div>

      <hr className="divider" />

      <div>
        <div className="eyebrow" style={{ marginBottom: 14 }}>02 — Antrieb</div>
        <Segmented options={[
          { value: "analog", label: "Bio" },
          { value: "ebike", label: "E-Bike" }
        ]} value={profile.bike_type || "analog"} onChange={(v) => set("bike_type", v)} />
      </div>

      <div>
        <div className="eyebrow" style={{ marginBottom: 14 }}>03 — Skill</div>
        <Segmented options={SKILL_OPTIONS} value={profile.skill_level} onChange={(v) => set("skill_level", v)} />
      </div>

      <div>
        <div className="eyebrow" style={{ marginBottom: 14 }}>04 — Fahrstil</div>
        <Segmented options={STYLE_OPTIONS} value={profile.riding_style} onChange={(v) => set("riding_style", v)} />
      </div>

      <div>
        <div className="eyebrow" style={{ marginBottom: 14 }}>05 — Einsatzbereich</div>
        <Segmented accent options={TERRAIN_OPTIONS} value={profile.terrain} onChange={(v) => set("terrain", v)} />
      </div>

      <hr className="divider" />

      <div>
        <div className="eyebrow" style={{ marginBottom: 18 }}>06 — Budget</div>
        <SliderField label="Budget" min={1200} max={8000} step={100} unit="€"
          value={profile.budget} onChange={(v) => set("budget", v)} large />
      </div>
    </div>
  );
}

function SliderField({ label, min, max, step, unit, value, onChange, large }) {
  return (
    <div className="field">
      <div className="field-label">{label}</div>
      <div className="slider-row">
        <input type="range" min={min} max={max} step={step} value={value}
          onChange={(e) => onChange(Number(e.target.value))} />
        <div className="slider-readout" style={large ? { fontSize: 32 } : null}>
          {unit === "€" ? fmtNum(value) : value}
          <span className="field-suffix" style={{ marginLeft: 6, fontSize: 11 }}>{unit}</span>
        </div>
      </div>
    </div>
  );
}

function Segmented({ options, value, onChange, accent }) {
  return (
    <div className={"seg" + (accent ? " seg-accent" : "")}>
      {options.map(o => (
        <button key={o.value} className={value === o.value ? "is-on" : ""} onClick={() => onChange(o.value)}>
          {o.label}
        </button>
      ))}
    </div>
  );
}

// ----- Component card -----
function ComponentCard({ slot, item, onClick }) {
  if (!item) return null;
  const high = item.level === "high" || item.level === "mid_high";
  const visionConfidence = Math.max(0, Math.min(1, Number(item.vision_confidence || 0)));
  return (
    <div className="comp-card" onClick={onClick}>
      <div className="comp-card-icon"><Icon name={slot} size={28} /></div>
      <div className="comp-card-body">
        <div className="comp-card-cat">{SLOT_LABELS[slot]}</div>
        <div className="comp-card-name">{item.name}</div>
        <div style={{ display: "flex", alignItems: "center", gap: 6, marginTop: 4, flexWrap: "wrap" }}>
          {item.level && <span className={"comp-card-level-pill" + (high ? " is-high" : "")}>{item.level.replace("_", "-")}</span>}
          {item.locked && <span className="comp-card-level-pill is-high">Bestand</span>}
          {item.replacement_for_existing && <span className="comp-card-level-pill">Upgrade</span>}
          {visionConfidence > 0 && <span className="comp-card-level-pill">Vision {Math.round(visionConfidence * 100)}%</span>}
          {item.locked && item.confidence && <span className="comp-card-level-pill">Match {item.confidence}%</span>}
          <BrandBadge name={item.name} size="sm" />
          <MarketplaceButton item={item} compact />
        </div>
      </div>
      <div style={{ display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 4 }}>
        {(item.locked || item.replacement_for_existing) && (
          <div className="eyebrow" style={{ fontSize: 8, color: item.locked ? "var(--ink-muted)" : "var(--accent)" }}>
            {item.locked ? "Wert" : "Kosten"}
          </div>
        )}
        <div className="comp-card-price">{fmtPrice(item.price || 0)}</div>
        <div style={{ color: "var(--ink-muted)" }}><Icon name="chevron" size={14} /></div>
      </div>
    </div>
  );
}

// ----- Spec cell (Ferrari big-number) -----
function SpecCell({ label, value, unit, accent, mega }) {
  return (
    <div className={"spec" + (accent ? " spec-accent" : "") + (mega ? " spec-mega" : "")}>
      <div className="spec-label">{label}</div>
      <div>
        <span className="spec-value">{value}</span>
        {unit && <span className="spec-unit">{unit}</span>}
      </div>
    </div>
  );
}

// ----- Score panel -----
function ScorePanel({ scores }) {
  const items = [
    { key: "fit_score", label: "FIT", v: scores.fit_score, accent: true },
    { key: "performance_score", label: "PERFORMANCE", v: scores.performance_score },
    { key: "value_score", label: "VALUE", v: scores.value_score }
  ];
  return (
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 32 }}>
      {items.map(it => (
        <div key={it.key}>
          <div className="spec-label" style={{ marginBottom: 12 }}>{it.label}</div>
          <div style={{ display: "flex", alignItems: "baseline", gap: 4 }}>
            <span style={{ font: "500 56px/1 var(--font-sans)", letterSpacing: "-1.12px", fontVariantNumeric: "tabular-nums", color: it.accent ? "var(--accent)" : "var(--ink)" }}>
              {it.v.toFixed(1)}
            </span>
            <span className="spec-unit" style={{ color: "var(--ink-muted)" }}>/10</span>
          </div>
          <div className="score-bar">
            <div className={"score-bar-fill" + (it.accent ? " is-accent" : "")} style={{ width: `${it.v * 10}%` }} />
          </div>
        </div>
      ))}
    </div>
  );
}

// ----- Warnings -----
function Warnings({ warnings }) {
  if (!warnings || warnings.length === 0) return null;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      {warnings.map((w, i) => (
        <div key={i} style={{
          display: "flex", alignItems: "flex-start", gap: 10,
          padding: "12px 14px",
          background: w.kind === "safety" ? "var(--accent-soft)" : "rgba(255,255,255,0.04)",
          borderLeft: `2px solid ${w.kind === "safety" ? "var(--accent)" : "var(--ink-soft)"}`,
          color: "var(--ink)"
        }}>
          <Icon name={w.kind === "safety" ? "warn" : "info"} size={16} />
          <span style={{ font: "500 13px/1.4 var(--font-sans)" }}>{w.msg}</span>
        </div>
      ))}
    </div>
  );
}

// ----- Drawer für Komponenten-Tausch -----
function ComponentDrawer({ slot, currentItem, pool, frame, profile, onPick, onClose }) {
  if (!slot || !pool) return null;
  // Filter passende Komponenten (gleiche Kompat.-Regeln wie engine)
  let candidates = pool.slice();
  if (slot === "wheels") {
    candidates = candidates.filter(w => (!w.wheel_sizes || w.wheel_sizes.includes(frame.wheel_size)) && (!w.axle_front || w.axle_front === frame.axle_front));
  } else if (slot === "fork") {
    candidates = candidates.filter(f => (!f.wheel_sizes || f.wheel_sizes.includes(frame.wheel_size)) && (!f.axle || f.axle === frame.axle_front));
  } else if (slot === "tires") {
    candidates = candidates.filter(t => !t.terrain || t.terrain === profile.terrain);
  } else if (slot === "dropper") {
    candidates = candidates.filter(d => !d.seatpost_diameters || d.seatpost_diameters.includes(frame.seatpost_diameter));
  } else if (slot === "shock" && frame.shock_size_class) {
    candidates = candidates.filter(s => !s.size_class || s.size_class.includes(frame.shock_size_class));
  }
  candidates.sort((a, b) => (a.price || 0) - (b.price || 0));

  return (
    <>
      <div className="drawer-backdrop" onClick={onClose} />
      <div className="drawer scroll-area">
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "24px 32px", borderBottom: "1px solid var(--hairline)", flex: "0 0 auto" }}>
          <div>
            <div className="eyebrow eyebrow-accent">Komponente wählen</div>
            <h3 style={{ marginTop: 6 }}>{SLOT_LABELS[slot]}</h3>
          </div>
          <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="close" size={14} /></button>
        </div>
        <div style={{ padding: 24, display: "flex", flexDirection: "column", gap: 6 }}>
          {candidates.map(c => (
            <div key={c.id}
              className={"comp-card" + (currentItem && currentItem.id === c.id ? " is-active" : "")}
              onClick={() => onPick(c)}>
              <div className="comp-card-icon"><Icon name={slot} size={26} /></div>
              <div className="comp-card-body">
                <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 2 }}>
                  <div className="comp-card-cat">{c.level ? c.level.replace("_", "-") : ""}</div>
                  <BrandBadge name={c.name} size="lg" />
                </div>
                <div className="comp-card-name">{c.name}</div>
                <div style={{ display: "flex", gap: 12, marginTop: 6, flexWrap: "wrap" }}>
                  {c.power != null && <SpecMini label="Power" value={`${c.power}/10`} />}
                  {c.range != null && <SpecMini label="Range" value={`${c.range}/10`} />}
                  {c.stiffness != null && <SpecMini label="Steif." value={`${c.stiffness}/10`} />}
                  {c.performance != null && <SpecMini label="Perf." value={`${c.performance}/10`} />}
                  {c.travel_mm != null && <SpecMini label="Travel" value={`${c.travel_mm}mm`} />}
                  {c.weight_g != null && <SpecMini label="Gewicht" value={`${c.weight_g}g`} />}
                </div>
              </div>
              <div style={{ display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 10 }}>
                <div className="comp-card-price">{fmtPrice(c.price || 0)}</div>
                <MarketplaceButton item={c} />
              </div>
            </div>
          ))}
          {candidates.length === 0 && <div style={{ color: "var(--ink-muted)", padding: 24 }}>Keine kompatiblen Komponenten gefunden.</div>}
        </div>
      </div>
    </>
  );
}

function SpecMini({ label, value }) {
  return (
    <span style={{ font: "600 10px/1.2 var(--font-sans)", letterSpacing: "0.6px", color: "var(--ink-muted)", textTransform: "uppercase" }}>
      {label} <span style={{ color: "var(--ink)", fontWeight: 700, fontVariantNumeric: "tabular-nums" }}>{value}</span>
    </span>
  );
}

// ----- Saved Builds Drawer -----
function GarageDrawer({ saved, onClose, onLoad, onDelete, onCompare, user, onLogout, plan, onUpgrade }) {
  return (
    <>
      <div className="drawer-backdrop" onClick={onClose} />
      <div className="drawer scroll-area" style={{ display: "flex", flexDirection: "column" }}>
        {/* Header */}
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "24px 32px", borderBottom: "1px solid var(--hairline)", flex: "0 0 auto" }}>
          <div>
            <div className="eyebrow eyebrow-accent">Meine Builds</div>
            <h3 style={{ marginTop: 6 }}>Garage</h3>
          </div>
          <div style={{ display: "flex", gap: 8 }}>
            {saved.length >= 2 && onCompare && (
              <button className={plan === "pro" ? "btn btn-primary btn-sm" : "btn btn-outline btn-sm"} onClick={plan === "pro" ? onCompare : onUpgrade}>
                <Icon name="compare" size={14} /> {plan === "pro" ? "Vergleichen" : "Vergleich ist Pro"}
              </button>
            )}
            <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="close" size={14} /></button>
          </div>
        </div>

        {/* Build list */}
        <div style={{ padding: 24, display: "flex", flexDirection: "column", gap: 14, flex: 1 }}>
          {saved.length === 0 && (
            <div style={{ textAlign: "center", color: "var(--ink-muted)", padding: 48 }}>
              <Icon name="frame" size={48} />
              <div className="eyebrow" style={{ marginTop: 14 }}>Noch keine Builds gespeichert</div>
              <p style={{ marginTop: 8, color: "var(--ink-muted)" }}>Konfiguriere ein Bike und speichere deinen Build hier.</p>
            </div>
          )}
          {saved.map(s => {
            const existingBike = s.profile?.existing_bike;
            const savedMeta = s.profile?.saved_state || {};
            const breakdown = savedMeta.price_breakdown;
            const existingSummary = savedMeta.existing_summary;
            const primaryPrice = existingBike && breakdown ? breakdown.upgrade_cost : s.total;
            const retainedCount = existingSummary?.locked_slots?.length || 0;
            const replacedCount = existingSummary?.replaced_slots?.length || 0;
            return (
              <div key={s.id} style={{ background: "var(--canvas-card)", border: "1px solid var(--hairline)", padding: 0 }}>
                {s.thumbnail && <div style={{ height: 140, background: `url(${s.thumbnail}) center/cover`, borderBottom: "1px solid var(--hairline)" }} />}
                <div style={{ padding: 18 }}>
                  <div className="eyebrow eyebrow-accent">{s.profile.terrain.toUpperCase()} · {s.profile.riding_style}</div>
                  <div style={{ font: "500 18px/1.3 var(--font-sans)", marginTop: 4 }}>{s.title}</div>
                  {existingBike && (
                    <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 10 }}>
                      <span className="comp-card-level-pill is-high">Bestandsbike</span>
                      {retainedCount > 0 && <span className="comp-card-level-pill">Bestand {retainedCount}</span>}
                      {replacedCount > 0 && <span className="comp-card-level-pill">Upgrade {replacedCount}</span>}
                    </div>
                  )}
                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12, marginTop: 14 }}>
                    <SpecMini label={existingBike ? "Upgrade" : "Preis"} value={fmtPrice(primaryPrice)} />
                    <SpecMini label="Fit" value={`${s.scores.fit_score}/10`} />
                    <SpecMini label="Perf" value={`${s.scores.performance_score}/10`} />
                  </div>
                  {existingBike && breakdown && (
                    <div style={{ display: "flex", gap: 10, flexWrap: "wrap", marginTop: 10 }}>
                      <SpecMini label="Bestandswert" value={fmtPrice(breakdown.existing_value || 0)} />
                      <SpecMini label="Gesamtwert" value={fmtPrice(s.total)} />
                    </div>
                  )}
                  <div style={{ display: "flex", gap: 8, marginTop: 16 }}>
                    <button className="btn btn-primary btn-sm" onClick={() => onLoad(s)}>Laden</button>
                    <button className="btn btn-outline btn-sm" onClick={() => onDelete(s.id)}>Löschen</button>
                  </div>
                </div>
              </div>
            );
          })}
        </div>

        {/* User profile footer */}
        {user && (
          <div style={{ flex: "0 0 auto", borderTop: "1px solid var(--hairline)", padding: "20px 32px" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
              <div style={{
                width: 40, height: 40, background: "var(--accent)",
                display: "grid", placeItems: "center",
                font: "700 15px/1 var(--font-sans)", color: "var(--accent-ink)", flexShrink: 0
              }}>
                {user.name.charAt(0).toUpperCase()}
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ font: "600 14px/1 var(--font-sans)", color: "var(--ink)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {user.name}
                </div>
                <div style={{ font: "400 12px/1 var(--font-sans)", color: "var(--ink-muted)", marginTop: 4, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {user.email}
                </div>
                {plan === "pro" ? (
                  <span style={{ display: "inline-block", marginTop: 6, background: "var(--accent)", color: "var(--accent-ink)", font: "700 9px/1 var(--font-sans)", letterSpacing: "1px", textTransform: "uppercase", padding: "3px 8px" }}>PRO</span>
                ) : (
                  <button onClick={onUpgrade} style={{ display: "inline-block", marginTop: 6, background: "none", border: "none", padding: 0, cursor: "pointer", font: "600 11px/1 var(--font-sans)", color: "var(--accent)", letterSpacing: "0.4px" }}>
                    → Upgrade auf Pro
                  </button>
                )}
              </div>
              <button className="btn btn-ghost btn-sm" onClick={onLogout} title="Abmelden" style={{ flexShrink: 0 }}>
                <Icon name="close" size={14} /> Abmelden
              </button>
            </div>
          </div>
        )}
      </div>
    </>
  );
}

window.BikeUI = {
  TopNav, ProfileForm, ComponentCard, SpecCell, ScorePanel, Warnings,
  ComponentDrawer, GarageDrawer, UpgradeModal, ExistingBikeModal, BrandTicker,
  SpecMini, Segmented, SliderField
};
