/** The address: a compact horizontal chip on the header row (street/number over nickname).
 *  Tapped, the chip appears to grow: the card is clipped to the chip's exact box at its
 *  top-right corner and un-clips down and to the left, same dark material, so nothing new
 *  arrives on screen — the chip just got bigger. It stops short of the right edge.
 *
 *  Inside: globe + city/state + "Meus endereços" on the left, the saved addresses as
 *  horizontal rows stacked on the right (tap to switch), route map along the bottom. */
function AddressRail({ addresses, open, onOpen, onClose, onPick, onSave, onDelete, restaurant }) {
  const current = addresses[0];
  const W = 318, CHIP_W = 146, CHIP_H = 40, TIME_H = 34, STAGE_H = 206, BAR_H = 46;
  const width = W;
  const [route, setRoute] = React.useState(null);
  const [manage, setManage] = React.useState(false);
  const [turned, setTurned] = React.useState(false);
  const [editing, setEditing] = React.useState(null); // address line, or "new"
  const [draft, setDraft] = React.useState({ label: "", line: "", city: "", cep: "" });
  const [locating, setLocating] = React.useState(null); // null | "busy" | "done" | "off"
  const [unrolled, setUnrolled] = React.useState(false); // editor stretch animation
  const [grown, setGrown] = React.useState(false); // chip → card un-clip

  React.useEffect(() => {
    if (!open) { setGrown(false); return; }
    const r = requestAnimationFrame(() => setGrown(true));
    return () => cancelAnimationFrame(r);
  }, [open]);

  const collapse = () => { setGrown(false); setTimeout(onClose, 240); };

  // one continuous move: the globe turns, zooms past its own edge, and the map takes over
  const [spin, setSpin] = React.useState(false);
  const [mapOn, setMapOn] = React.useState(false);
  React.useEffect(() => {
    if (!open) { setSpin(false); setMapOn(false); return; }
    const a = setTimeout(() => setSpin(true), 140);
    const b = setTimeout(() => setMapOn(true), 560);
    return () => { clearTimeout(a); clearTimeout(b); };
  }, [open]);

  React.useEffect(() => {
    if (!editing) { setUnrolled(false); return; }
    const r = requestAnimationFrame(() => setUnrolled(true));
    return () => cancelAnimationFrame(r);
  }, [editing]);

  React.useEffect(() => { if (!open) { setManage(false); setEditing(null); setLocating(null); } }, [open]);
  React.useEffect(() => { setLocating(null); }, [editing]);

  // one frame in the rotated pose, then ease to upright — reads as the card turning.
  // Leaving runs the same beats backwards so the globe and map return, not snap.
  const [leaving, setLeaving] = React.useState(false);
  React.useEffect(() => {
    if (!manage) { setTurned(false); return; }
    const r = requestAnimationFrame(() => setTurned(true));
    return () => cancelAnimationFrame(r);
  }, [manage]);

  const exitManage = () => { setEditing(null); setTurned(false); setManage(false); };

  const prep = restaurant ? (restaurant.prepMin || 15) : null;
  const ride = route ? route.min : null;
  const total = prep != null && ride != null ? prep + ride : null;

  /** Splits a stored one-line address back into its parts for editing.
   *  "Rua Aurora, 148 — apto 42" → street "Rua Aurora", number "148", comp "apto 42" */
  const explode = (a) => {
    if (a.street != null) return { street: a.street, number: a.number || "", comp: a.comp || "", district: a.district || "" };
    const [head, ...tail] = String(a.line || "").split(" — ");
    const parts = head.split(", ");
    const number = parts.length > 1 && /\d/.test(parts[parts.length - 1]) ? parts.pop() : "";
    return { street: parts.join(", "), number, comp: tail.join(" — "), district: a.district || "" };
  };

  /** One canonical line from the parts — what the vertical bars and the map label read. */
  const compose = (d) => {
    const base = [d.street.trim(), d.number.trim()].filter(Boolean).join(", ");
    return d.comp.trim() ? base + " — " + d.comp.trim() : base;
  };

  const startEdit = (a) => {
    setEditing(a.line);
    setDraft({ label: a.label, city: a.city || "", cep: a.cep || "", ...explode(a) });
  };
  const startNew = () => {
    setEditing("new");
    setDraft({ label: "", city: current.city || "", cep: "", street: "", number: "", district: "", comp: "" });
  };
  const commit = () => {
    if (!draft.street.trim()) return;
    const line = compose(draft);
    const base = editing === "new" ? { lat: current.lat + 0.012, lon: current.lon + 0.014 } : {};
    onSave({
      ...base,
      label: draft.label.trim() || "Novo",
      line,
      short: [draft.street.trim().replace(/^(rua|av\.?|avenida|travessa|alameda)\s+/i, ""), draft.number.trim()].filter(Boolean).join(", ").slice(0, 18),
      street: draft.street.trim(), number: draft.number.trim(),
      district: draft.district.trim(), comp: draft.comp.trim(),
      city: draft.city.trim() || current.city, cep: draft.cep.trim()
    }, editing === "new" ? null : editing);
    setEditing(null);
  };

  // real geolocation, filling CEP + city from the coordinates (reverse geocode)
  const locate = () => {
    if (!navigator.geolocation) { setLocating("off"); return; }
    setLocating("busy");
    navigator.geolocation.getCurrentPosition(async (pos) => {
      const { latitude, longitude } = pos.coords;
      try {
        const r = await fetch("https://nominatim.openstreetmap.org/reverse?format=json&zoom=18&lat=" + latitude + "&lon=" + longitude);
        const j = await r.json();
        const a = j.address || {};
        setDraft(d => ({
          ...d,
          cep: a.postcode || d.cep,
          city: [a.city || a.town || a.village || a.municipality, a.state_code || a.state].filter(Boolean).join(", ") || d.city,
          street: a.road || d.street,
          number: a.house_number || d.number,
          district: a.suburb || a.neighbourhood || a.city_district || d.district
        }));
        setLocating("done");
      } catch (e) { setLocating("off"); }
    }, () => setLocating("off"), { timeout: 8000 });
  };

  /** Inputs keep the row's own voice: the display face for the address, mono for the
   *  label/CEP — no boxes, just an underline that darkens on focus. */
  const field = (ph, key, opts) => {
    const o = opts || {};
    return (
      <input value={draft[key]} placeholder={ph}
        onChange={e => setDraft(d => ({ ...d, [key]: e.target.value }))}
        style={{
          width: "100%", boxSizing: "border-box", height: o.tall ? 26 : 22, padding: "0 0 3px",
          border: "none", borderBottom: "1px solid var(--ink-600)", borderRadius: 0, outline: "none",
          background: "transparent", color: "var(--white)",
          fontFamily: o.display ? "var(--font-display)" : "var(--font-mono)",
          fontWeight: o.display ? 900 : 700,
          fontStretch: o.display ? "125%" : "normal",
          fontSize: o.display ? 14 : 10,
          letterSpacing: o.display ? "-0.01em" : "0.14em",
          textTransform: "uppercase"
        }} />
    );
  };

  const label = (t) => (
    <div style={{ fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 8, letterSpacing: "0.16em", textTransform: "uppercase", color: "var(--ink-400)", marginBottom: 4 }}>{t}</div>
  );

  /** city → CEP (with the locate affordance) → street → nickname → delete.
   *  Unrolls in place so the row appears to stretch open rather than be replaced. */
  const editor = (isNew, aLine) => (
    <div style={{
      display: "grid", gridTemplateRows: unrolled ? "1fr" : "0fr",
      transition: "grid-template-rows 340ms var(--ease-out)"
    }}>
      <div style={{ overflow: "hidden", minHeight: 0 }}>
      <div style={{
        display: "flex", flexDirection: "column", gap: 11, padding: "10px 10px 13px",
        background: "var(--ink-900)", borderLeft: "2px solid var(--white)",
        opacity: unrolled ? 1 : 0, transition: "opacity 220ms var(--ease-out) 90ms"
      }}>
        <div>{label("Cidade")}{field("São Paulo, SP", "city", { display: true, tall: true })}</div>
        <div>
          {label("CEP")}
          <div style={{ display: "flex", alignItems: "flex-end", gap: 8 }}>
            {field("00000-000", "cep")}
            <button type="button" onClick={locate} aria-label="Usar minha localização" title="Usar minha localização"
              style={{
                flex: "0 0 auto", width: 24, height: 24, cursor: "pointer", padding: 0,
                background: "transparent", color: locating === "busy" ? "var(--ink-500)" : "var(--white)",
                border: "none", display: "flex", alignItems: "center", justifyContent: "center"
              }}>
              <Icon d={P.pin} size={15} stroke={2.25} />
            </button>
          </div>
          {locating === "off" && (
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 8, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--ink-400)", marginTop: 4 }}>localização indisponível</div>
          )}
        </div>
        <div>{label("Endereço")}
          <div style={{ display: "flex", alignItems: "flex-end", gap: 10 }}>
            <div style={{ flex: 1, minWidth: 0 }}>{field("Rua", "street", { display: true, tall: true })}</div>
            <div style={{ flex: "0 0 62px" }}>{field("Nº", "number", { display: true, tall: true })}</div>
          </div>
        </div>
        <div style={{ display: "flex", alignItems: "flex-end", gap: 10 }}>
          <div style={{ flex: 1, minWidth: 0 }}>{label("Bairro")}{field("Vila Madalena", "district")}</div>
          <div style={{ flex: "0 0 96px" }}>{label("Comp")}{field("Apto 42", "comp")}</div>
        </div>
        <div>{label("Apelido")}{field("Casa, trabalho…", "label")}</div>
        <div style={{ display: "flex", gap: 6, marginTop: 3 }}>
          <button type="button" onClick={commit} style={{
            flex: 1, height: 32, background: "var(--white)", color: "var(--black)", border: "none",
            borderRadius: "var(--radius-xs)", cursor: "pointer",
            fontFamily: "var(--font-display)", fontWeight: 900, fontStretch: "125%", textTransform: "uppercase", fontSize: 10
          }}>{isNew ? "Adicionar" : "Salvar"}</button>
          <button type="button" onClick={() => setEditing(null)} style={{
            flex: "0 0 auto", height: 32, padding: "0 10px", background: "transparent", color: "var(--ink-400)",
            border: "1px solid var(--ink-600)", borderRadius: "var(--radius-xs)", cursor: "pointer",
            fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 9, letterSpacing: "0.12em", textTransform: "uppercase"
          }}>Cancelar</button>
          {!isNew && addresses.length > 1 && (
            <button type="button" onClick={() => { onDelete(aLine); setEditing(null); }} aria-label="Apagar endereço" title="Apagar endereço"
              style={{
                flex: "0 0 auto", width: 32, height: 32, background: "transparent", color: "var(--ink-400)",
                border: "1px dashed var(--ink-600)", borderRadius: "var(--radius-xs)", cursor: "pointer",
                display: "flex", alignItems: "center", justifyContent: "center"
              }}>
              <Icon d={P.x} size={13} stroke={2.25} />
            </button>
          )}
        </div>
      </div>
      </div>
    </div>
  );

  const iconBtn = (label, glyph, onClick, small) => (
    <button type="button" aria-label={label} onClick={(e) => { e.stopPropagation(); onClick(); }}
      style={{
        flex: "0 0 auto", width: small ? 20 : 26, height: small ? 20 : 26, padding: 0, cursor: "pointer",
        background: "transparent", border: "none", borderRadius: "var(--radius-xs)",
        color: "var(--ink-400)",
        fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: small ? 10 : 13, lineHeight: 1
      }}>{glyph}</button>
  );

  const shortStreet = (a) => String(a.street || a.line || "").replace(/^(rua|av\.?|avenida|travessa|alameda|praça)\s+/i, "");

  /** Collapsed: a chip on the header row, street/number over the nickname. */
  if (!open) {
    return (
      <>
        <button type="button" onClick={onOpen}
          onPointerDown={e => e.stopPropagation()}
          style={{
            position: "absolute", top: 48, right: 16, zIndex: 320,
            height: 40, maxWidth: 146, padding: "0 11px", cursor: "pointer",
            background: "var(--ink-800)", border: "1px solid var(--ink-600)", borderRadius: "var(--radius-md)",
            display: "flex", flexDirection: "column", alignItems: "flex-end", justifyContent: "center", gap: 2,
            overflow: "hidden"
          }}>
          <span style={{
            fontFamily: "var(--font-display)", fontWeight: 900, fontStretch: "125%", textTransform: "uppercase",
            fontSize: 12, lineHeight: 1, letterSpacing: "-0.01em", color: "var(--ink-200)",
            maxWidth: "100%", whiteSpace: "nowrap"
          }}>{shortStreet(current)}</span>
          <span style={{
            fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 8.5, letterSpacing: "0.16em",
            textTransform: "uppercase", color: "var(--ink-400)", lineHeight: 1, whiteSpace: "nowrap"
          }}>{current.number} {current.label}{total != null ? " · " + total + "MIN" : ""}</span>
        </button>
        {/* stays mounted at zero height: keeps tiles warm and the ETA computed for the chip */}
        <div style={{ position: "absolute", top: 48, right: 16, width: W, zIndex: 1, pointerEvents: "none" }}>
          <MapPanel open={false} width={W} height={STAGE_H}
            dest={current} pins={null}
            origin={restaurant ? { lat: restaurant.lat, lon: restaurant.lon, name: restaurant.name } : null}
            onRoute={setRoute} />
        </div>
      </>
    );
  }

  const listH = Math.min(3, addresses.length) * 46 + 26;
  const total_h = listH + (restaurant ? TIME_H : 0) + STAGE_H + BAR_H;
  const shut = "inset(0px 0px " + (total_h - CHIP_H) + "px " + (W - CHIP_W) + "px round var(--radius-md))";
  const clip = grown ? "inset(0px round var(--radius-md))" : shut;

  const row = (a, i) => {
    const active = a.line === current.line;
    return (
      <button key={a.line} type="button" onClick={() => onPick(a)} style={{
        display: "flex", alignItems: "center", gap: 9, width: "100%", textAlign: "left",
        padding: "9px 12px", cursor: "pointer", background: "transparent", border: "none",
        borderTop: i === 0 ? "none" : "1px solid var(--ink-700)",
        opacity: grown ? 1 : 0, transform: grown ? "translateX(0)" : "translateX(14px)",
        transition: "opacity 240ms var(--ease-out) " + (90 + i * 45) + "ms, transform 340ms var(--ease-out) " + (90 + i * 45) + "ms"
      }}>
        <span style={{
          flex: "0 0 auto", width: 6, height: 6, borderRadius: 999,
          background: active ? "var(--white)" : "transparent",
          border: active ? "none" : "1px solid var(--ink-600)"
        }} />
        <span style={{
          flex: "0 0 auto", fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 8, letterSpacing: "0.16em",
          textTransform: "uppercase", color: active ? "var(--ink-300)" : "var(--ink-500)", width: 46
        }}>{a.label}</span>
        <span style={{
          flex: 1, minWidth: 0, fontFamily: "var(--font-display)", fontWeight: 900, fontStretch: "125%",
          textTransform: "uppercase", fontSize: 12.5, letterSpacing: "-0.01em",
          color: active ? "var(--white)" : "var(--ink-400)",
          whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis"
        }}>{a.line}</span>
      </button>
    );
  };

  return (
    <div onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}
      style={{ position: "absolute", top: 48, right: 16, width: W, zIndex: 320 }}>
      <div style={{
        width: "100%", boxSizing: "border-box", overflow: "hidden",
        background: "var(--ink-800)", border: "1px solid var(--ink-600)", borderRadius: "var(--radius-md)",
        position: "relative",
        clipPath: clip, WebkitClipPath: clip,
        transition: "clip-path 380ms cubic-bezier(0.22, 1, 0.28, 1)"
      }}>
        {!manage && (<>
        {/* endereços salvos, largura toda */}
        <div style={{ position: "relative" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 6, padding: "9px 12px 2px" }}>
            <span style={{
              flex: 1, fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 8, letterSpacing: "0.18em",
              textTransform: "uppercase", color: "var(--ink-500)"
            }}>Entregar em</span>
            <button type="button" onClick={collapse} aria-label="Fechar" style={{
              flex: "0 0 auto", width: 18, height: 18, padding: 0, cursor: "pointer", background: "transparent",
              border: "none", color: "var(--ink-400)", fontFamily: "var(--font-mono)", fontSize: 12, lineHeight: 1
            }}>×</button>
          </div>
          <div style={{ maxHeight: 138, overflowY: "auto", scrollbarWidth: "none" }}>
            {addresses.map(row)}
          </div>
        </div>

        {/* tempo de entrega */}
        <div style={{
          width: "100%", height: restaurant ? TIME_H : 0, boxSizing: "border-box",
          borderTop: restaurant ? "1px solid var(--ink-700)" : "none",
          display: "flex", alignItems: "center", gap: 8, padding: restaurant ? "0 12px" : 0, overflow: "hidden",
          opacity: grown && !manage ? 1 : 0, transition: "opacity 220ms var(--ease-out) 140ms"
        }}>
          {restaurant ? (
            <>
              <span style={{
                fontFamily: "var(--font-display)", fontWeight: 900, fontStretch: "125%", fontSize: 15,
                color: "var(--white)", lineHeight: 1
              }}>{total != null ? total : "…"}</span>
              <span style={{
                fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 9, letterSpacing: "0.12em",
                textTransform: "uppercase", color: "var(--ink-400)", whiteSpace: "nowrap"
              }}>min · preparo {prep} + entrega {ride != null ? ride : "…"}</span>
            </>
          ) : null}
        </div>

        {/* palco: o globo vira o mapa */}
        <div style={{
          position: "relative", width: "100%", height: manage && !leaving ? 0 : STAGE_H,
          borderTop: "1px solid var(--ink-700)", overflow: "hidden",
          transition: "height 320ms var(--ease-out)"
        }}>
          <div style={{
            position: "absolute", inset: 0,
            opacity: mapOn && !(manage && !leaving) ? 1 : 0,
            transition: "opacity 300ms linear"
          }}>
            <MapPanel open={mapOn && !(manage && !leaving)} width={W} height={STAGE_H}
              dest={{ ...current, city: null }} pins={null}
              origin={restaurant ? { lat: restaurant.lat, lon: restaurant.lon, name: restaurant.name } : null}
              onRoute={setRoute} />
          </div>
          <div aria-hidden={mapOn} style={{
            position: "absolute", left: 0, right: 0, top: 8, display: "flex", justifyContent: "center",
            transform: spin ? "scale(2.9)" : "scale(1)",
            transformOrigin: "50% 62%",
            opacity: mapOn ? 0 : 1,
            filter: mapOn ? "blur(7px)" : "blur(0px)",
            transition: "transform 900ms cubic-bezier(0.3, 0, 0.2, 1), opacity 380ms linear, filter 380ms linear",
            pointerEvents: "none"
          }}>
            <Globe lat={current.lat} lon={current.lon} size={168} color="#fff" turns={spin ? 2 : 0} />
          </div>
        </div>

        {/* barra: cidade à esquerda, meus endereços à direita */}
        <div style={{
          display: "flex", alignItems: "center", gap: 8, height: BAR_H, boxSizing: "border-box",
          padding: "0 10px 0 12px", borderTop: "1px solid var(--ink-700)",
          opacity: grown && !manage ? 1 : 0, pointerEvents: grown && !manage ? "auto" : "none",
          transition: "opacity 240ms var(--ease-out) 120ms"
        }}>
          <span style={{
            flex: 1, minWidth: 0, fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 9,
            letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-300)",
            whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis"
          }}>{current.city}</span>
          <button type="button" onClick={() => setManage(true)} style={{
            flex: "0 0 auto", background: "var(--white)", color: "var(--black)", border: "none",
            borderRadius: "var(--radius-sm)", padding: "8px 11px", cursor: "pointer",
            fontFamily: "var(--font-display)", fontWeight: 900, fontStretch: "125%", textTransform: "uppercase", fontSize: 9.5
          }}>Meus endereços</button>
        </div>
        </>)}

        {/* gerenciar: mesma lista, agora editável — o card encolhe até ela */}
        {manage && (
          <div style={{
            position: "relative", background: "var(--ink-800)", zIndex: 3,
            display: "flex", flexDirection: "column", maxHeight: total_h,
            opacity: turned ? 1 : 0, transition: "opacity 200ms var(--ease-out)"
          }}>
            <div style={{ display: "flex", alignItems: "center", gap: 6, padding: "9px 10px 8px", borderBottom: "1px solid var(--ink-700)" }}>
              <span style={{
                flex: 1, fontFamily: "var(--font-display)", fontWeight: 900, fontStretch: "125%",
                textTransform: "uppercase", fontSize: 12.5, color: "var(--white)"
              }}>Meus endereços</span>
              {iconBtn("Adicionar", "+", startNew)}
              {iconBtn("Voltar", "×", exitManage)}
            </div>
            <div style={{ flex: 1, minHeight: 0, overflowY: "auto", scrollbarWidth: "none" }}>
              {addresses.map((a, i) => {
                const active = a.line === current.line;
                const isEditing = editing === a.line;
                return (
                  <div key={a.line} style={{
                    borderBottom: "1px solid var(--ink-700)",
                    transform: turned ? "translateX(0)" : "translateX(22px)",
                    opacity: turned ? 1 : 0,
                    transition: "transform 320ms var(--ease-out) " + (30 + i * 50) + "ms, opacity 220ms var(--ease-out) " + (30 + i * 50) + "ms"
                  }}>
                    {isEditing ? editor(false, a.line) : (
                      <div onClick={() => onPick(a)} style={{ display: "flex", alignItems: "center", gap: 5, padding: "8px 6px 8px 10px", cursor: "pointer" }}>
                        <span style={{
                          flex: "0 0 auto", width: 6, height: 6, borderRadius: 999,
                          background: active ? "var(--white)" : "transparent", border: active ? "none" : "1px solid var(--ink-600)"
                        }} />
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 8.5, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-500)" }}>{a.label}</div>
                          <div style={{
                            fontFamily: "var(--font-display)", fontWeight: 900, fontStretch: "125%", textTransform: "uppercase",
                            fontSize: 12, color: active ? "var(--white)" : "var(--ink-300)",
                            whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis"
                          }}>{a.line}</div>
                        </div>
                        {iconBtn("Editar " + a.label, "···", () => startEdit(a), true)}
                      </div>
                    )}
                  </div>
                );
              })}
              {editing === "new" && (<div style={{ borderBottom: "1px solid var(--ink-700)" }}>{editor(true)}</div>)}
              {editing !== "new" && (
                <button type="button" onClick={startNew} style={{
                  width: "100%", textAlign: "left", padding: "10px", background: "transparent", border: "none", cursor: "pointer",
                  fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 9, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-400)"
                }}>+ adicionar endereço</button>
              )}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}
Object.assign(window, { AddressRail });
