// VELOUR Wardrobe — Step 3: live AI Stylist for occasions.
// Calls api/stylist.js with the user's live closet + an occasion, and gets back
// a styled look assembled from owned pieces, a calm brand-voice rationale, and any gap.
const { Card } = window.VelourDesignSystem_380ed4;

const OCCASIONS = [
  { label: "Day to day", icon: "sun", prompt: "An easy, polished day-to-day look for errands and working from a cafe." },
  { label: "A gathering", icon: "users-three", prompt: "A relaxed gathering with friends this weekend — put-together but comfortable." },
  { label: "Dinner date", icon: "wine", prompt: "A dinner date on Friday evening — a little dressed up, still myself." },
  { label: "Work presentation", icon: "presentation", prompt: "An important work presentation — confident and sharp without trying too hard." },
  { label: "Out of town", icon: "airplane-tilt", prompt: "A travel day flying out of town — comfortable but pulled-together." },
];

function clcpw(it) { return it.wears > 0 ? `${window.velourMoney(it.price / it.wears)}/wear` : "new, unworn"; }
// Days since last worn — date-based (honoring the day offset), with legacy fallback.
// The app's "today", offset-corrected — the same day key the rest of VELOUR uses.
function clToday() { const t = new Date(); const off = Number(window.VELOUR_DAY_OFFSET) || 0; if (off) t.setDate(t.getDate() + off); return t; }
function clDaysIdle(it) {
  if (it.lastWornDate) { return Math.max(0, Math.round((new Date(window.velourDateISO(clToday()) + "T00:00:00") - new Date(it.lastWornDate + "T00:00:00")) / 86400000)); }
  if (it.wears === 0) return 999;
  return it.lastWorn != null ? it.lastWorn : 999;
}

// Ask the real stylist. The prompt lives server-side in api/stylist.js — the client
// sends the occasion and the closet, never a prompt, so the endpoint can't be used as
// an open LLM proxy. Structured outputs guarantee the JSON shape, so there is nothing
// to strip or slice here any more.
async function askStylist(occasion, items) {
  return window.velourAiFetch("/api/stylist", {
    occasion,
    today: window.velourDateISO(clToday()),
    items: items.map((it) => ({
      id: it.id, name: it.name, category: it.category,
      price: it.price, wears: it.wears, lastWornDate: it.lastWornDate || null,
    })),
  });
}

// ---- local fallback stylist ------------------------------------------------
// Deterministically assembles a look from the user's real closet when the hosted
// stylist endpoint isn't reachable — e.g. local dev, or no API key set. Same result shape
// as askStylist; swapped for the real model in production.
// A complete look aims for top + bottom + shoes + an accessory (e.g. a bag) when
// the closet has them. cats = preferred order; alt = fillers if cats come up short.
function localPlan(o) {
  o = (o || "").toLowerCase();
  // Everyday/errands first, so casual phrasings like "working from a cafe" don't trip the work branch.
  if (/errand|cafe|coffee|day[ -]?to[ -]?day|every ?day|casual day/.test(o)) return { title: "An easy, polished day", cats: ["Tops", "Denim", "Shoes", "Accessories"], alt: ["Knits", "Outerwear", "Dresses"], need: ["Shoes", "Accessories"] };
  if (/dinner|date|dress|evening|cocktail|drinks/.test(o)) return { title: "Dinner, dressed with ease", cats: ["Dresses", "Shoes", "Accessories", "Outerwear"], alt: ["Tops", "Trousers & skirts", "Denim", "Knits"], need: ["Dresses", "Shoes", "Accessories"] };
  if (/work|present|office|meeting|interview|board/.test(o)) return { title: "Sharp, without trying", cats: ["Outerwear", "Tops", "Denim", "Shoes"], alt: ["Accessories", "Knits", "Dresses"], need: ["Outerwear", "Shoes", "Accessories"] };
  if (/gather|friend|party|weekend|brunch|casual/.test(o)) return { title: "Easy company", cats: ["Tops", "Denim", "Shoes", "Accessories"], alt: ["Dresses", "Knits", "Outerwear"], need: ["Shoes", "Accessories"] };
  if (/travel|town|flight|trip|airport|plane/.test(o)) return { title: "Made for the miles", cats: ["Tops", "Denim", "Shoes", "Outerwear"], alt: ["Accessories", "Knits"], need: ["Shoes", "Accessories"] };
  return { title: "An easy, polished day", cats: ["Tops", "Denim", "Shoes", "Accessories"], alt: ["Knits", "Outerwear", "Dresses"], need: ["Shoes", "Accessories"] };
}
function pickFromCat(items, cat) {
  const inCat = items.filter((it) => it.category === cat);
  if (!inCat.length) return null;
  // gently favor reviving an idle piece, else the most-worn (proven versatile) one
  const idle = inCat.filter((it) => it.wears === 0 || clDaysIdle(it) >= 90).sort((a, b) => clDaysIdle(b) - clDaysIdle(a))[0];
  return idle || inCat.slice().sort((a, b) => b.wears - a.wears)[0];
}
function styleLocally(occasion, items) {
  const plan = localPlan(occasion);
  const chosen = [], used = new Set();
  for (const cat of plan.cats.concat(plan.alt || [])) {
    if (chosen.length >= 4) break;
    const it = pickFromCat(items.filter((i) => !used.has(i.id)), cat);
    if (it) { chosen.push(it); used.add(it.id); }
  }
  if (chosen.length < 2) {
    items.filter((i) => !used.has(i.id)).sort((a, b) => b.wears - a.wears).forEach((it) => { if (chosen.length < 4) { chosen.push(it); used.add(it.id); } });
  }
  const revived = chosen.find((it) => it.wears === 0 || clDaysIdle(it) >= 90);
  const anchor = chosen.slice().sort((a, b) => b.wears - a.wears)[0];
  let rationale;
  if (revived) rationale = `Built around your ${revived.name.toLowerCase()} — ${revived.wears === 0 ? "still unworn" : "unworn " + clDaysIdle(revived) + " days"}, and right for this. A quiet reason to bring it back.`;
  else if (anchor && anchor.wears > 0) rationale = `Leaning on your ${anchor.name.toLowerCase()} — ${anchor.wears} wears at ${clcpw(anchor)}, proven and versatile.`;
  else rationale = "Pulled from the pieces that work hardest in your capsule.";
  // Name the first genuinely-missing piece the look would benefit from (priority order).
  const GAP_INFO = {
    Dresses: { piece: "a dress", why: "Your capsule has no dress to anchor this look." },
    Outerwear: { piece: "a layering piece", why: "Your capsule has no layer to finish this look." },
    Shoes: { piece: "a pair of shoes", why: "Your capsule has no shoes to complete the look." },
    Accessories: { piece: "a bag", why: "A bag would pull this together — your capsule doesn't have one yet." },
  };
  let gap = null;
  for (const cat of (plan.need || [])) {
    if (!items.some((it) => it.category === cat)) { gap = GAP_INFO[cat] || { piece: "a piece", why: "Your capsule has a gap to fill here." }; break; }
  }
  return { title: plan.title, itemIds: chosen.map((it) => it.id), rationale, gap };
}

function StylistThumb({ item }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 8, flex: 1, minWidth: 0 }}>
      <div style={{ width: "100%", aspectRatio: "3 / 4", borderRadius: 12, overflow: "hidden", background: "var(--amber-fill)", display: "flex", alignItems: "center", justifyContent: "center" }}>
        {item.photo ? <img src={item.photo} alt={item.name} style={{ width: "100%", height: "100%", objectFit: "cover" }} />
          : <i className={`ph ph-${item.icon || "coat-hanger"}`} style={{ fontSize: 30, color: "var(--amber-text)" }}></i>}
      </div>
      <div style={{ width: "100%", textAlign: "center" }}>
        <div style={{ fontSize: 12.5, color: "var(--text-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.name}</div>
        <div style={{ fontSize: 11, color: "var(--text-tertiary)", marginTop: 1 }}>{clcpw(item)}</div>
      </div>
    </div>
  );
}

function WardrobeStylist({ items, onWearMany, onNavigate }) {
  const [text, setText] = React.useState("");
  const [loading, setLoading] = React.useState(false);
  const [result, setResult] = React.useState(null);
  // Every piece in the stylist's look already worn today — same confirmed state as
  // the closet card and the outfit card. RESOLVED AGAINST THE LIVE CLOSET, not
  // against result.matched: those items were copied into state when the stylist
  // answered, so their lastWornDate predates the tap and this would never flip.
  const stylistWorn = !!(result && result.matched && result.matched.length > 0 &&
    result.matched.every((m) => { const live = items.find((it) => it.id === m.id); return live && wornToday(live); }));
  const [error, setError] = React.useState(null);
  const plan = window.useVelourPlan ? window.useVelourPlan() : { stylist: true };

  // The gate replaces the whole tool rather than letting a member compose a
  // request and refusing it at the end. Being told no after the effort is worse
  // than being told up front what this is.
  if (!plan.stylist) {
    return <window.UpgradePrompt feature="stylist" onNavigate={onNavigate} />;
  }

  const run = async (occasion) => {
    if (!occasion.trim() || loading) return;
    if (!items.length) { setResult(null); setError("Add a few pieces to your closet first — then I can style you from them."); return; }
    setLoading(true); setError(null); setResult(null);
    try {
      let r = null;
      // Try the real stylist; fall back to the deterministic local one on any failure
      // (endpoint missing in local dev, API key unset, model unavailable).
      try { r = await askStylist(occasion, items); } catch (e) { r = null; }
      let matched = r ? (r.itemIds || []).map((id) => items.find((it) => it.id === id)).filter(Boolean) : [];
      if (!matched.length) {
        await new Promise((res) => setTimeout(res, 450)); // brief beat so the styling feels considered
        r = styleLocally(occasion, items);
        matched = (r.itemIds || []).map((id) => items.find((it) => it.id === id)).filter(Boolean);
      }
      if (!matched.length) throw new Error("no-match");
      setResult({ ...r, matched, occasion });
    } catch (e) {
      setError("Add a few more pieces and I'll style you from them.");
    } finally { setLoading(false); }
  };

  const chip = (active) => ({ display: "inline-flex", alignItems: "center", gap: 8, padding: "9px 15px", borderRadius: 999, cursor: loading ? "default" : "pointer", fontFamily: "var(--font-sans)", fontSize: 13.5, fontWeight: 500, border: "var(--border-width) solid var(--border)", background: "var(--surface-card)", color: "var(--text-primary)", opacity: loading ? 0.6 : 1 });

  return (
    <div>
      <div style={{ margin: "8px 2px 16px" }}>
        <h2 style={{ fontFamily: "var(--font-serif)", fontWeight: 500, fontSize: 24, color: "var(--text-primary)", margin: 0, letterSpacing: "-0.01em" }}>Ask your stylist</h2>
        <p style={{ fontSize: 14, color: "var(--text-secondary)", margin: "6px 0 0" }}>Tell VELOUR the occasion. It styles you from your capsule first — and names a gap only if there truly is one.</p>
      </div>

      <Card padding={26}>
        {/* Input */}
        <div style={{ display: "flex", gap: 10, marginBottom: 14 }}>
          <div style={{ flex: 1, position: "relative" }}>
            <i className="ph ph-sparkle" style={{ position: "absolute", left: 16, top: "50%", transform: "translateY(-50%)", fontSize: 17, color: "var(--amber)" }}></i>
            <input value={text} onChange={(e) => setText(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") run(text); }} placeholder="e.g. dinner date Friday, dressy but it'll be cold" style={{ width: "100%", padding: "13px 16px 13px 44px", borderRadius: 12, border: "var(--border-width) solid var(--border)", background: "var(--surface-card)", fontFamily: "var(--font-sans)", fontSize: 14.5, color: "var(--text-primary)", outline: "none", boxSizing: "border-box" }} />
          </div>
          <button onClick={() => run(text)} disabled={loading || !text.trim()} style={{ display: "inline-flex", alignItems: "center", gap: 8, background: "var(--ink)", color: "var(--parchment)", border: "none", borderRadius: 12, padding: "0 22px", fontFamily: "var(--font-sans)", fontSize: 14.5, fontWeight: 500, cursor: loading || !text.trim() ? "default" : "pointer", opacity: loading || !text.trim() ? 0.5 : 1, whiteSpace: "nowrap" }}>Style me</button>
        </div>

        {/* Occasion chips */}
        <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
          {OCCASIONS.map((o) => (
            <button key={o.label} onClick={() => { setText(o.prompt); run(o.prompt); }} disabled={loading} style={chip()}>
              <i className={`ph ph-${o.icon}`} style={{ fontSize: 16, color: "var(--amber-text)" }}></i>{o.label}
            </button>
          ))}
        </div>

        {/* Loading */}
        {loading && (
          <div style={{ display: "flex", alignItems: "center", gap: 12, marginTop: 22, color: "var(--text-secondary)", fontSize: 14 }}>
            <span className="vr-spin" style={{ width: 18, height: 18, borderRadius: "50%", border: "2px solid var(--border)", borderTopColor: "var(--amber)", display: "inline-block" }}></span>
            Reading your capsule and styling the look…
          </div>
        )}

        {/* Error */}
        {error && !loading && (
          <div style={{ display: "flex", gap: 11, alignItems: "flex-start", background: "var(--surface-sunken)", borderRadius: 12, padding: "14px 16px", marginTop: 20, fontSize: 14, color: "var(--text-secondary)", lineHeight: 1.55 }}>
            <i className="ph ph-cloud-slash" style={{ fontSize: 18, color: "var(--text-tertiary)", marginTop: 1 }}></i>{error}
          </div>
        )}

        {/* Result */}
        {result && !loading && (
          <div style={{ marginTop: 24, paddingTop: 22, borderTop: "var(--border-width) solid var(--divider)" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 4 }}>
              <span style={{ fontSize: 11, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--amber-text)", fontWeight: 500 }}>Styled for you</span>
              <span style={{ fontSize: 11.5, color: "var(--text-tertiary)" }}>· {result.occasion.length > 40 ? result.occasion.slice(0, 40) + "…" : result.occasion}</span>
            </div>
            <div style={{ fontFamily: "var(--font-serif)", fontSize: 23, color: "var(--text-primary)", letterSpacing: "-0.01em", marginBottom: 18 }}>{result.title || "Your look"}</div>

            <div style={{ display: "flex", gap: 16, alignItems: "flex-start" }}>
              {result.matched.map((item, i) => (
                <React.Fragment key={item.id}>
                  <StylistThumb item={item} />
                  {i < result.matched.length - 1 && <div style={{ alignSelf: "center", color: "var(--text-tertiary)", fontSize: 18, paddingTop: 18 }}>+</div>}
                </React.Fragment>
              ))}
            </div>

            {result.rationale && (
              <div style={{ display: "flex", gap: 11, alignItems: "flex-start", marginTop: 20 }}>
                <i className="ph ph-quotes" style={{ fontSize: 18, color: "var(--amber)", marginTop: 2 }}></i>
                <div style={{ fontSize: 15, color: "var(--text-primary)", lineHeight: 1.6, fontStyle: "italic" }}>{result.rationale}</div>
              </div>
            )}

            {window.velourOmittedNote && window.velourOmittedNote(result.omitted) && (
              <div style={{ display: "flex", gap: 11, alignItems: "flex-start", marginTop: 18, fontSize: 13.5, color: "var(--text-tertiary)", lineHeight: 1.55 }}>
                <i className="ph ph-stack" style={{ fontSize: 16, marginTop: 1 }}></i>
                <div>{window.velourOmittedNote(result.omitted)}</div>
              </div>
            )}

            {result.gap && (
              <div style={{ display: "flex", gap: 11, alignItems: "flex-start", background: "var(--amber-fill)", borderRadius: 13, padding: "14px 16px", marginTop: 18 }}>
                <i className="ph ph-lightbulb" style={{ fontSize: 18, color: "var(--amber)", marginTop: 1 }}></i>
                <div style={{ fontSize: 14, color: "var(--amber-text)", lineHeight: 1.55 }}><span style={{ fontWeight: 600 }}>One gap — {result.gap.piece}.</span> {result.gap.why} When you set a budget, VELOUR can suggest the exact piece to fill it.</div>
              </div>
            )}

            <div style={{ display: "flex", gap: 10, marginTop: 22, flexWrap: "wrap" }}>
              <button onClick={() => onWearMany(result.matched.map((m) => m.id))} style={{ display: "inline-flex", alignItems: "center", gap: 8, background: stylistWorn ? "var(--amber-fill)" : "var(--ink)", color: stylistWorn ? "var(--amber-text)" : "var(--parchment)", border: "none", borderRadius: 999, padding: "11px 20px", fontFamily: "var(--font-sans)", fontSize: 14, fontWeight: 500, cursor: "pointer" }}><i className={`ph ph-${stylistWorn ? "check" : "plus"}`} style={{ fontSize: 15 }}></i>{stylistWorn ? "Worn today" : "Wear this today"}</button>
              <button onClick={() => run(result.occasion)} style={{ display: "inline-flex", alignItems: "center", gap: 8, background: "var(--surface-card)", color: "var(--text-primary)", border: "var(--border-width) solid var(--border)", borderRadius: 999, padding: "11px 20px", fontFamily: "var(--font-sans)", fontSize: 14, fontWeight: 500, cursor: "pointer" }}><i className="ph ph-arrows-clockwise" style={{ fontSize: 15 }}></i>Try another</button>
            </div>
          </div>
        )}
      </Card>
    </div>
  );
}

window.WardrobeStylist = WardrobeStylist;
