const { useState, useEffect, useRef } = React;

const TRAITS = [
  "Affectionate", "Opinionated", "Thoughtful/Curious", "Bold/Adventurous",
  "Compassionate/Empathetic", "Confident", "Deep Conversations/Intellectual",
  "Dramatic", "Expressive", "Flirty", "Innocent/Sweet", "Modest", "Outgoing",
  "Philosophical", "Playful/Teasing", "Quiet/Reserved", "Romantic", "Sarcastic",
  "Shy", "Stubborn",
];

const BODY_TYPES = [
  { id: "slim", label: "Slim" },
  { id: "average", label: "Average" },
  { id: "athletic", label: "Athletic" },
  { id: "curvy", label: "Curvy" },
];

const DEFAULT_APPEARANCE = {
  country: "mixed",
  skin_tone: "medium",
  hair_color: "brown",
  hair_style: "medium",
  eye_color: "brown",
  outfit: "casual",
  framing: "face",
  age_appearance: "mid_20s",
  vibe: "natural",
};

const api = {
  token: () => localStorage.getItem("token"),
  headers: () => ({
    "Content-Type": "application/json",
    Authorization: `Bearer ${api.token()}`,
  }),
  async get(path) {
    const r = await fetch(path, { headers: api.headers() });
    const d = await r.json();
    if (!r.ok) throw new Error(d.detail || "Request failed");
    return d;
  },
  async post(path, body) {
    const r = await fetch(path, {
      method: "POST",
      headers: api.headers(),
      body: JSON.stringify(body),
    });
    const d = await r.json();
    if (!r.ok) throw new Error(typeof d.detail === "string" ? d.detail : "Request failed");
    return d;
  },
  async patch(path, body) {
    const r = await fetch(path, {
      method: "PATCH",
      headers: api.headers(),
      body: JSON.stringify(body),
    });
    const d = await r.json();
    if (!r.ok) throw new Error(d.detail || "Request failed");
    return d;
  },
};

function avatarUrl(seed, lookGender) {
  const style = lookGender === "male" ? "adventurer" : "lorelei";
  return `https://api.dicebear.com/7.x/${style}/svg?seed=${encodeURIComponent(seed)}&backgroundColor=1a1a2e,2d1b4e`;
}

function portraitUrl(companion, cacheBust) {
  if (companion?.portrait_path && companion?.id && api.token()) {
    const base = `/api/companions/${companion.id}/portrait?token=${encodeURIComponent(api.token())}`;
    return cacheBust ? `${base}&v=${cacheBust}` : base;
  }
  const portraits = {
    female: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=600&fit=crop",
    male: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&h=600&fit=crop",
    nonbinary: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=400&h=600&fit=crop",
  };
  return portraits[companion?.look_gender] || portraits.female;
}

const PORTRAIT_FALLBACKS = {
  female: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=1200&h=1600&fit=crop",
  male: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=1200&h=1600&fit=crop",
  nonbinary: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=1200&h=1600&fit=crop",
};

function PortraitLightbox({ src, alt, onClose }) {
  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    document.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      document.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [onClose]);

  return (
    <div className="portrait-lightbox" onClick={onClose} role="dialog" aria-modal="true" aria-label="Full portrait">
      <button type="button" className="portrait-lightbox-close" onClick={onClose} aria-label="Close">×</button>
      <img src={src} alt={alt} onClick={(e) => e.stopPropagation()} />
    </div>
  );
}

function MagnifyIcon() {
  return (
    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" aria-hidden="true">
      <circle cx="11" cy="11" r="7" />
      <path d="M20 20l-3-3" strokeLinecap="round" />
    </svg>
  );
}

function CompanionPortraitFrame({ companion, portraitVersion, alt, className, onOpenFull }) {
  const src = portraitUrl(companion, portraitVersion);
  return (
    <div className={`photo-frame ${className || ""}`}>
      <img
        src={src}
        alt={alt}
        className="photo-frame-img"
        onClick={onOpenFull}
        onError={(e) => {
          e.target.onerror = null;
          e.target.src = PORTRAIT_FALLBACKS[companion?.look_gender] || PORTRAIT_FALLBACKS.female;
        }}
      />
      <button
        type="button"
        className="portrait-zoom-btn"
        onClick={onOpenFull}
        aria-label="View full image"
        title="View full image"
      >
        <MagnifyIcon />
      </button>
    </div>
  );
}

function Silhouette({ gender, bodyType }) {
  const widths = { slim: 28, average: 36, athletic: 40, curvy: 44 };
  const w = widths[bodyType] || 36;
  const isMale = gender === "male";
  const isNB = gender === "nonbinary";
  return (
    <svg viewBox="0 0 60 100" fill="currentColor" style={{ color: "#a78bfa" }}>
      <circle cx="30" cy="14" r="10" />
      {isMale ? (
        <>
          <rect x={30 - w / 2} y="26" width={w} height="38" rx="6" />
          <rect x={30 - w / 2 - 6} y="28" width="10" height="32" rx="4" />
          <rect x={30 + w / 2 - 4} y="28" width="10" height="32" rx="4" />
        </>
      ) : isNB ? (
        <>
          <path d={`M${30 - w / 2},26 L${30 + w / 2},26 L${30 + w / 2 - 4},64 L${30 - w / 2 + 4},64 Z`} />
          <rect x={30 - w / 2 - 5} y="28" width="9" height="30" rx="4" />
          <rect x={30 + w / 2 - 4} y="28" width="9" height="30" rx="4" />
        </>
      ) : (
        <>
          <path d={`M${30 - w / 2},26 Q${30},22 ${30 + w / 2},26 L${30 + w / 2 - 2},64 L${30 - w / 2 + 2},64 Z`} />
          <rect x={30 - w / 2 - 5} y="28" width="9" height="30" rx="4" />
          <rect x={30 + w / 2 - 4} y="28" width="9" height="30" rx="4" />
        </>
      )}
      <rect x="22" y="64" width="8" height="28" rx="3" />
      <rect x="30" y="64" width="8" height="28" rx="3" />
    </svg>
  );
}

function AuthScreen({ config, onAuth, mode, setMode }) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  async function submit(e) {
    e.preventDefault();
    setError("");
    setLoading(true);
    try {
      const path = mode === "login" ? "/api/auth/login" : "/api/auth/register";
      const data = await api.post(path, { email, password });
      localStorage.setItem("token", data.token);
      onAuth();
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <div className="screen">
      <div className="screen-inner">
        <div className="logo">{config.site_name}</div>
        <div className="tagline">{config.site_tagline}</div>
        {error && <div className="error">{error}</div>}
        <form onSubmit={submit}>
          <div className="field">
            <label>Email</label>
            <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required />
          </div>
          <div className="field">
            <label>Password</label>
            <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} minLength={6} required />
          </div>
          <button className="btn btn-primary" disabled={loading}>
            {loading ? "Please wait…" : mode === "login" ? "Log In" : "Create Account"}
          </button>
        </form>
        <div className="auth-switch">
          {mode === "login" ? (
            <>New here? <button onClick={() => setMode("register")}>Create an account</button></>
          ) : (
            <>Already have an account? <button onClick={() => setMode("login")}>Log in</button></>
          )}
        </div>
      </div>
    </div>
  );
}

function ProfileScreen({ onNext, onBack }) {
  const [displayName, setDisplayName] = useState("");
  const [gender, setGender] = useState("");
  const [age, setAge] = useState("");
  const [policy, setPolicy] = useState(false);
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  async function submit(e) {
    e.preventDefault();
    if (!policy) { setError("You must accept the terms to continue."); return; }
    setLoading(true);
    setError("");
    try {
      await api.patch("/api/me/profile", {
        display_name: displayName,
        gender,
        age: parseInt(age, 10),
        policy_accepted: true,
      });
      onNext({ displayName, gender, age: parseInt(age, 10) });
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <div className="screen">
      <div className="screen-inner">
        <div className="step-header">
          <button className="back-btn" onClick={onBack}>←</button>
          Tell us about you
        </div>
        {error && <div className="error">{error}</div>}
        <form onSubmit={submit}>
          <div className="field">
            <label>Your name</label>
            <input value={displayName} onChange={(e) => setDisplayName(e.target.value)} required placeholder="What should we call you?" />
          </div>
          <div className="field">
            <label>Gender</label>
            <div className="pill-row">
              {["male", "female", "nonbinary"].map((g) => (
                <div key={g} className={`pill ${gender === g ? "active" : ""}`} onClick={() => setGender(g)}>
                  {g.charAt(0).toUpperCase() + g.slice(1)}
                </div>
              ))}
            </div>
          </div>
          <div className="field">
            <label>Age</label>
            <input type="number" min="18" max="120" value={age} onChange={(e) => setAge(e.target.value)} required placeholder="18+" />
          </div>
          <div className="field">
            <label className="checkbox-row">
              <input type="checkbox" checked={policy} onChange={(e) => setPolicy(e.target.checked)} />
              <span>I am 18+ and agree to the Terms of Service and Privacy Policy. I understand this is an AI companion for entertainment.</span>
            </label>
          </div>
          <button className="btn btn-primary" disabled={loading || !gender}>Continue</button>
        </form>
      </div>
    </div>
  );
}

function PillSelect({ label, options, value, onChange }) {
  return (
    <div className="field">
      <label>{label}</label>
      <div className="pill-row pill-row-wrap">
        {options.map((o) => (
          <div
            key={o.id}
            className={`pill ${value === o.id ? "active" : ""}`}
            onClick={() => onChange(o.id)}
          >
            {o.label}
          </div>
        ))}
      </div>
    </div>
  );
}

function AppearancePicker({ appearance, setAppearance, options, compact }) {
  if (!options) return <div className="trait-hint">Loading look options…</div>;
  const set = (key) => (id) => setAppearance((a) => ({ ...a, [key]: id }));

  return (
    <div className={`appearance-picker ${compact ? "compact" : ""}`}>
      <div className="field">
        <label>Country / heritage (for their look)</label>
        <select value={appearance.country} onChange={(e) => set("country")(e.target.value)}>
          {options.countries.map((c) => (
            <option key={c.id} value={c.id}>{c.label}</option>
          ))}
        </select>
      </div>
      <PillSelect label="Skin tone" options={options.skin_tones} value={appearance.skin_tone} onChange={set("skin_tone")} />
      <PillSelect label="Hair color" options={options.hair_colors} value={appearance.hair_color} onChange={set("hair_color")} />
      <PillSelect label="Hair style" options={options.hair_styles} value={appearance.hair_style} onChange={set("hair_style")} />
      <PillSelect label="Eye color" options={options.eye_colors} value={appearance.eye_color} onChange={set("eye_color")} />
      <PillSelect label="Outfit style" options={options.outfits} value={appearance.outfit} onChange={set("outfit")} />
      <PillSelect label="Photo framing" options={options.framings} value={appearance.framing} onChange={set("framing")} />
      <PillSelect label="Age appearance" options={options.age_appearance} value={appearance.age_appearance} onChange={set("age_appearance")} />
      <PillSelect label="Overall vibe" options={options.vibes} value={appearance.vibe} onChange={set("vibe")} />
    </div>
  );
}

function LookScreen({ onNext, onBack }) {
  const [lookGender, setLookGender] = useState("female");
  const [bodyType, setBodyType] = useState("average");
  const [appearance, setAppearance] = useState({ ...DEFAULT_APPEARANCE });
  const [options, setOptions] = useState(null);

  useEffect(() => {
    api.get("/api/appearance/options").then(setOptions).catch(() => {});
  }, []);

  return (
    <div className="screen">
      <div className="screen-inner screen-wide look-screen-scroll">
        <div className="step-header">
          <button className="back-btn" onClick={onBack}>←</button>
          Choose Your Companion's Look
        </div>
        <p className="trait-hint" style={{ marginBottom: 16 }}>
          These choices shape their AI-generated portrait — country, colors, outfit, and how much of their body you see.
        </p>
        <div className="field">
          <label>Gender presentation</label>
          <div className="pill-row">
            {["female", "male", "nonbinary"].map((g) => (
              <div key={g} className={`pill ${lookGender === g ? "active" : ""}`} onClick={() => setLookGender(g)}>
                {g.charAt(0).toUpperCase() + g.slice(1)}
              </div>
            ))}
          </div>
        </div>
        <label>Body type</label>
        <div className="body-grid">
          {BODY_TYPES.map((b) => (
            <div
              key={b.id}
              className={`body-card ${bodyType === b.id ? "active" : ""}`}
              onClick={() => setBodyType(b.id)}
            >
              <Silhouette gender={lookGender} bodyType={b.id} />
              <span>{b.label}</span>
            </div>
          ))}
        </div>
        <h3 className="appearance-section-title">Face, style &amp; photo</h3>
        <AppearancePicker appearance={appearance} setAppearance={setAppearance} options={options} />
        <div style={{ marginTop: 24 }}>
          <button
            className="btn btn-primary"
            onClick={() => onNext({ lookGender, bodyType, appearance })}
          >
            Continue
          </button>
        </div>
      </div>
    </div>
  );
}

function PortraitStudioModal({ companion, options, quota, onClose, onUpdated }) {
  const [appearance, setAppearance] = useState(
    companion?.appearance ? { ...DEFAULT_APPEARANCE, ...companion.appearance } : { ...DEFAULT_APPEARANCE }
  );
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  const remaining = quota?.remaining ?? 0;

  async function regenerate() {
    if (!quota?.can_regenerate) {
      setError(quota?.upgrade_message || "Daily limit reached.");
      return;
    }
    setLoading(true);
    setError("");
    try {
      const data = await api.post(`/api/companions/${companion.id}/regenerate-portrait`, { appearance });
      onUpdated(data.companion, data.portrait_quota);
      onClose();
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <div className="portrait-modal-overlay" onClick={onClose}>
      <div className="portrait-modal" onClick={(e) => e.stopPropagation()}>
        <button type="button" className="modal-close-btn" onClick={onClose}>×</button>
        <h2>New portrait for {companion.name}</h2>
        <p className="trait-hint">
          {remaining > 0
            ? `${remaining} of ${quota?.limit || 3} free generations left today.`
            : quota?.upgrade_message}
        </p>
        {error && <div className="error">{error}</div>}
        <AppearancePicker appearance={appearance} setAppearance={setAppearance} options={options} compact />
        <button
          type="button"
          className="btn btn-primary"
          disabled={loading || !quota?.can_regenerate}
          onClick={regenerate}
        >
          {loading ? "Generating… (about a minute)" : "Generate new portrait"}
        </button>
        {!quota?.can_regenerate && (
          <button type="button" className="btn btn-upgrade" style={{ marginTop: 10 }}>
            Upgrade for unlimited portraits
          </button>
        )}
      </div>
    </div>
  );
}

function SetupScreen({ config, wizard, onNext, onBack }) {
  const [name, setName] = useState("");
  const [relationship, setRelationship] = useState("friendship");
  const [traits, setTraits] = useState([]);
  const [customTrait, setCustomTrait] = useState("");
  const [showBackstory, setShowBackstory] = useState(false);
  const [backstory, setBackstory] = useState("");
  const [error, setError] = useState("");
  const maxBackstory = 1000;

  function toggleTrait(t) {
    setTraits((prev) =>
      prev.includes(t) ? prev.filter((x) => x !== t) : prev.length < 7 ? [...prev, t] : prev
    );
  }

  async function generateName() {
    try {
      const data = await api.post("/api/companions/generate-name", {
        look_gender: wizard.lookGender,
      });
      setName(data.name);
    } catch {
      setName(["Luna", "Alex", "River"][Math.floor(Math.random() * 3)]);
    }
  }

  function submit() {
    if (!name.trim()) { setError("Give your companion a name."); return; }
    if (relationship !== "custom" && traits.length < 3) { setError("Pick at least 3 traits."); return; }
    setError("");
    onNext({ name: name.trim(), relationship, traits, backstory: backstory.trim() });
  }

  useEffect(() => {
    if (relationship === "custom") setShowBackstory(true);
  }, [relationship]);

  return (
    <div className="screen">
      <div className="screen-inner">
        <div className="step-header">
          <button className="back-btn" onClick={onBack}>←</button>
          Get Ready to Meet {name.trim() ? name : "Your Companion"}!
        </div>
        {error && <div className="error">{error}</div>}

        <div className="field">
          <div className="input-row">
            <input value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" />
            <button type="button" className="icon-btn" onClick={generateName} title="Generate name">🎲</button>
          </div>
        </div>

        <div className="field">
          <label>
            What type of relationship are you looking for?
            <span className="info-icon">i</span>
          </label>
          <div className="rel-tabs">
            {[
              { id: "friendship", label: "Friendship" },
              { id: "romantic", label: "Romantic" },
              { id: "mentor", label: "Mentor" },
              { id: "custom", label: "Custom" },
            ].map((r) => (
              <button
                key={r.id}
                className={`rel-tab ${relationship === r.id ? "active" : ""}`}
                onClick={() => setRelationship(r.id)}
              >
                {r.label}
              </button>
            ))}
          </div>
        </div>

        {relationship !== "custom" && (
          <>
            <div className="field">
              <label>Which key traits do you value most?</label>
              <div className="trait-hint">Please choose between 3 and 7 key traits.</div>
              <div className="trait-grid">
                {TRAITS.map((t) => (
                  <div
                    key={t}
                    className={`trait-chip ${traits.includes(t) ? "selected" : ""}`}
                    onClick={() => toggleTrait(t)}
                  >
                    {traits.includes(t) && <span className="check">✓</span>}
                    {t}
                  </div>
                ))}
              </div>
              <div className="custom-trait-row">
                <input
                  value={customTrait}
                  onChange={(e) => setCustomTrait(e.target.value)}
                  placeholder="Add your own…"
                  onKeyDown={(e) => {
                    if (e.key === "Enter" && customTrait.trim() && traits.length < 7) {
                      toggleTrait(customTrait.trim());
                      setCustomTrait("");
                    }
                  }}
                />
                <button
                  type="button"
                  className="add-trait-btn"
                  onClick={() => {
                    if (customTrait.trim() && traits.length < 7) {
                      toggleTrait(customTrait.trim());
                      setCustomTrait("");
                    }
                  }}
                >+</button>
              </div>
            </div>
            {!showBackstory && (
              <button type="button" className="link-btn" onClick={() => setShowBackstory(true)}>
                Create a backstory (optional)
              </button>
            )}
          </>
        )}

        {(showBackstory || relationship === "custom") && (
          <div className="field" style={{ marginTop: 16 }}>
            <label>
              {relationship === "custom"
                ? "What is your companion's backstory?"
                : "Backstory (optional)"}
            </label>
            {relationship === "custom" && (
              <div className="trait-hint">
                Enter details about background, personality, interests. Write in third person.
              </div>
            )}
            <textarea
              value={backstory}
              onChange={(e) => setBackstory(e.target.value.slice(0, maxBackstory))}
              placeholder={`${name || "They"} is a caring person who loves deep conversations…`}
            />
            <div className="char-count">{maxBackstory - backstory.length} / {maxBackstory} characters left</div>
          </div>
        )}

        <div style={{ marginTop: 24 }}>
          <button className="btn btn-primary" onClick={submit}>Start Chatting</button>
        </div>
      </div>
    </div>
  );
}

function CreatingScreen({ config, wizard, onDone }) {
  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const data = await api.post("/api/companions", {
          name: wizard.name,
          look_gender: wizard.lookGender,
          body_type: wizard.bodyType,
          relationship: wizard.relationship,
          traits: wizard.traits,
          backstory: wizard.backstory || "",
          appearance: wizard.appearance || DEFAULT_APPEARANCE,
        });
        onDone(data.companion, data.greeting);
      } catch (err) {
        alert(err.message);
      }
    })();
    return () => { cancelled = true; };
  }, []);

  return (
    <div className="screen creating-screen">
      <div className="spinner-ring" />
      <h2>Creating {wizard.name} for you…</h2>
      <p style={{ color: "#71717a" }}>
        Please wait while we make {wizard.name}&apos;s photo and bring them to life. This usually takes about a minute.
      </p>
    </div>
  );
}

function applyDarkMode(mode) {
  const root = document.documentElement;
  root.classList.remove("dark-forced", "light-forced");
  if (mode === "on") root.classList.add("dark-forced");
  else if (mode === "off") root.classList.add("light-forced");
}

function formatBirthdateDisplay(birthdate) {
  if (!birthdate) return null;
  const d = new Date(birthdate + "T12:00:00");
  if (Number.isNaN(d.getTime())) return birthdate;
  return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
}

function BottomNav({ active, onNav }) {
  const items = [
    { id: "home", label: "Home", icon: "🏠" },
    { id: "new", label: "New", icon: "✨" },
    { id: "chat", label: "Chat", icon: "💬" },
    { id: "profile", label: "Profile", icon: "👤" },
  ];
  return (
    <nav className="bottom-nav">
      {items.map((item) => (
        <button
          type="button"
          key={item.id}
          className={`nav-item ${active === item.id ? "active" : ""}`}
          onClick={() => onNav(item.id)}
        >
          <span>{item.icon}</span>
          {item.label}
        </button>
      ))}
    </nav>
  );
}

function SettingsSidebar({ config, active, onNav, onLogout }) {
  const items = [
    { id: "profile", label: "Profile Settings", icon: "👤" },
    { id: "account", label: "Account Settings", icon: "⚙️", disabled: true },
    { id: "help", label: "Help", icon: "❓", disabled: true },
  ];
  return (
    <aside className="app-sidebar">
      <div className="sidebar-top">
        <div className="sidebar-logo">{config.site_name}</div>
      </div>
      <div className="upgrade-card">
        <h3>Upgrade!</h3>
        <ul>
          <li>Unlimited messages</li>
          <li>More companions</li>
          <li>Faster replies &amp; selfies</li>
        </ul>
        <button type="button" className="btn-subscribe">Subscribe</button>
      </div>
      <nav className="app-menu">
        {items.map((item) => (
          <button
            key={item.id}
            type="button"
            className={`menu-item ${active === item.id ? "active" : ""} ${item.disabled ? "disabled" : ""}`}
            onClick={() => !item.disabled && onNav(item.id)}
            disabled={item.disabled}
          >
            <span>{item.icon}</span>
            {item.label}
          </button>
        ))}
        <button type="button" className="menu-item logout" onClick={onLogout}>
          <span>⎋</span>
          Logout
        </button>
      </nav>
    </aside>
  );
}

function ProfileSettingsPanel({ user, onSaved }) {
  const [displayName, setDisplayName] = useState(user?.display_name || "");
  const [birthdate, setBirthdate] = useState(user?.birthdate || "");
  const [gender, setGender] = useState(user?.gender || "male");
  const [stylized, setStylized] = useState(!!user?.stylized_formatting);
  const [darkMode, setDarkMode] = useState(user?.dark_mode || "device");
  const [error, setError] = useState("");
  const [success, setSuccess] = useState(false);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    setDisplayName(user?.display_name || "");
    setBirthdate(user?.birthdate || "");
    setGender(user?.gender || "male");
    setStylized(!!user?.stylized_formatting);
    setDarkMode(user?.dark_mode || "device");
  }, [user]);

  async function submit(e) {
    e.preventDefault();
    setError("");
    setSuccess(false);
    setLoading(true);
    try {
      const data = await api.patch("/api/me/settings", {
        display_name: displayName,
        birthdate: birthdate || null,
        gender,
        stylized_formatting: stylized,
        dark_mode: darkMode,
      });
      onSaved(data.user);
      applyDarkMode(data.user.dark_mode || "device");
      setSuccess(true);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <div className="settings-panel">
      <h1>Profile Settings</h1>
      {error && <div className="error">{error}</div>}
      {success && <div className="error" style={{ background: "rgba(34,197,94,.12)", color: "#86efac" }}>Settings saved.</div>}
      <form className="settings-form" onSubmit={submit}>
        <div className="field">
          <label>Name</label>
          <input value={displayName} onChange={(e) => setDisplayName(e.target.value)} required />
        </div>
        <div className="field">
          <label>Birthdate</label>
          <input
            type="date"
            value={birthdate}
            onChange={(e) => setBirthdate(e.target.value)}
          />
          {birthdate && (
            <div className="birthdate-display" style={{ marginTop: 8 }}>
              {formatBirthdateDisplay(birthdate)}
            </div>
          )}
        </div>
        <div className="field">
          <label>Gender</label>
          <select value={gender} onChange={(e) => setGender(e.target.value)}>
            <option value="male">Male</option>
            <option value="female">Female</option>
            <option value="nonbinary">Nonbinary</option>
          </select>
        </div>
        <div className="field">
          <label className="checkbox-row">
            <input type="checkbox" checked={stylized} onChange={(e) => setStylized(e.target.checked)} />
            <span>
              Use Stylized Action Asterisks Formatting
              <span className="info-icon" title="Actions appear like *smiles* around dialogue">i</span>
            </span>
          </label>
        </div>
        <div className="field">
          <label>Dark Mode Settings</label>
          <div className="radio-group">
            {[
              { value: "device", label: "Device Default" },
              { value: "off", label: "Off" },
              { value: "on", label: "On" },
            ].map((opt) => (
              <label key={opt.value} className="radio-row">
                <input
                  type="radio"
                  name="dark_mode"
                  value={opt.value}
                  checked={darkMode === opt.value}
                  onChange={() => setDarkMode(opt.value)}
                />
                {opt.label}
              </label>
            ))}
          </div>
        </div>
        <button type="submit" className="btn btn-update" disabled={loading}>
          {loading ? "Saving…" : "Update"}
        </button>
      </form>
    </div>
  );
}

function HomePanel({ config, companion, onNav }) {
  return (
    <div className="settings-panel">
      <h1>Home</h1>
      <p style={{ color: "var(--muted)", marginBottom: 20 }}>
        Welcome back{companion ? ` — ${companion.name} is ready to chat` : ""}.
      </p>
      <button className="btn btn-primary" onClick={() => onNav("chat")}>Go to Chat</button>
    </div>
  );
}

function MainApp({ config, user, setUser, companion, setCompanion, portraitQuota, setPortraitQuota, initialMessages, greeting, onLogout, onNewCompanion }) {
  const [view, setView] = useState("chat");
  const [appearanceOptions, setAppearanceOptions] = useState(null);

  useEffect(() => {
    api.get("/api/appearance/options").then(setAppearanceOptions).catch(() => {});
  }, []);

  useEffect(() => {
    applyDarkMode(user?.dark_mode || "device");
  }, [user?.dark_mode]);

  return (
    <div className="main-app-shell">
      <div className="main-app-body">
        {view === "profile" && (
          <>
            <SettingsSidebar
              config={config}
              active="profile"
              onNav={(id) => (id === "profile" ? setView("profile") : null)}
              onLogout={onLogout}
            />
            <main className="app-main">
              <ProfileSettingsPanel user={user} onSaved={setUser} />
            </main>
          </>
        )}
        {view === "home" && (
          <main className="app-main" style={{ width: "100%" }}>
            <HomePanel config={config} companion={companion} onNav={setView} />
          </main>
        )}
        {view === "new" && (
          <main className="app-main" style={{ width: "100%" }}>
            <div className="settings-panel">
              <h1>New Companion</h1>
              <p style={{ color: "var(--muted)", marginBottom: 20 }}>Create another AI companion with a new look and personality.</p>
              <button className="btn btn-primary" onClick={onNewCompanion}>Start Setup</button>
            </div>
          </main>
        )}
        {view === "chat" && (
          <ChatScreen
            config={config}
            companion={companion}
            setCompanion={setCompanion}
            appearanceOptions={appearanceOptions}
            portraitQuota={portraitQuota}
            setPortraitQuota={setPortraitQuota}
            initialMessages={initialMessages}
            greeting={greeting}
            onOpenProfile={() => setView("profile")}
          />
        )}
      </div>
      <BottomNav active={view} onNav={setView} />
    </div>
  );
}

function ChatScreen({ config, companion, setCompanion, appearanceOptions, portraitQuota, setPortraitQuota, initialMessages, greeting, onOpenProfile }) {
  const [portraitVersion, setPortraitVersion] = useState(Date.now());
  const [showPortraitStudio, setShowPortraitStudio] = useState(false);
  const [showPortraitLightbox, setShowPortraitLightbox] = useState(false);
  const portraitSrc = portraitUrl(companion, portraitVersion);
  const openFullPortrait = () => setShowPortraitLightbox(true);
  const [messages, setMessages] = useState(
    initialMessages.length
      ? initialMessages.map((m) => ({ role: m.role === "assistant" ? "ai" : "user", text: m.content }))
      : [{ role: "ai", text: greeting }]
  );
  const [input, setInput] = useState("");
  const [typing, setTyping] = useState(false);
  const [rateLimited, setRateLimited] = useState(false);
  const endRef = useRef(null);

  useEffect(() => {
    endRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [messages, typing]);

  async function send() {
    const text = input.trim();
    if (!text || typing) return;
    setMessages((m) => [...m, { role: "user", text }]);
    setInput("");
    setTyping(true);
    try {
      const data = await api.post("/api/chat", { companion_id: companion.id, message: text });
      setMessages((m) => [...m, { role: "ai", text: data.reply }]);
      if (data.rate_limited) setRateLimited(true);
    } catch (err) {
      setMessages((m) => [...m, { role: "ai", text: "AI is busy right now — try again in a minute." }]);
      setRateLimited(true);
    } finally {
      setTyping(false);
    }
  }

  const today = new Date().toLocaleDateString("en-US", {
    weekday: "short", month: "short", day: "2-digit", year: "numeric",
  });

  return (
    <div className="chat-app">
      <aside className="sidebar">
        <div className="sidebar-top">
          <div className="sidebar-logo">{config.site_name}</div>
        </div>
        <div className="companion-header">
          <div className="companion-name">{companion.name} 💡</div>
          <button type="button" className="profile-link-btn" onClick={onOpenProfile} title="Profile Settings">
            👤 Profile
          </button>
        </div>
        <div className="companion-photo">
          <div className="photo-wrap">
            <CompanionPortraitFrame
              companion={companion}
              portraitVersion={portraitVersion}
              alt={companion.name}
              onOpenFull={openFullPortrait}
            />
          </div>
          <button
            type="button"
            className="portrait-regen-btn"
            onClick={() => setShowPortraitStudio(true)}
            title="Generate a new portrait"
          >
            📷 New look
            {portraitQuota != null && (
              <span className="portrait-quota-badge">{portraitQuota.remaining}/{portraitQuota.limit}</span>
            )}
          </button>
        </div>
      </aside>
      {showPortraitLightbox && (
        <PortraitLightbox
          src={portraitSrc}
          alt={`${companion.name} — full portrait`}
          onClose={() => setShowPortraitLightbox(false)}
        />
      )}
      {showPortraitStudio && (
        <PortraitStudioModal
          companion={companion}
          options={appearanceOptions}
          quota={portraitQuota}
          onClose={() => setShowPortraitStudio(false)}
          onUpdated={(c, q) => {
            setCompanion(c);
            setPortraitQuota(q);
            setPortraitVersion(Date.now());
          }}
        />
      )}

      <main className="chat-main">
        {rateLimited && (
          <div className="rate-banner">
            Free AI limit hit — using demo replies. Add credits at openrouter.ai or wait ~1 hour.
          </div>
        )}
        <div className="promo-bar">
          <span>Upgrade for unlimited chat, faster messages &amp; more daily selfies</span>
          <button>New? Tour App Basics</button>
        </div>
        <div className="chat-mobile-portrait">
          <div className="chat-mobile-photo">
            <CompanionPortraitFrame
              companion={companion}
              portraitVersion={portraitVersion}
              alt={companion.name}
              className="photo-frame-mobile"
              onOpenFull={openFullPortrait}
            />
          </div>
          <div className="chat-mobile-actions">
            <strong>{companion.name}</strong>
            <button
              type="button"
              className="portrait-regen-btn portrait-regen-btn-mobile"
              onClick={() => setShowPortraitStudio(true)}
            >
              📷 New look
              {portraitQuota != null && (
                <span className="portrait-quota-badge">{portraitQuota.remaining}/{portraitQuota.limit}</span>
              )}
            </button>
          </div>
        </div>
        <div className="chat-header-mobile">
          <strong>{companion.name}</strong>
          <div className="chat-header-mobile-btns">
            <button
              type="button"
              className="portrait-regen-btn portrait-regen-btn-inline"
              onClick={() => setShowPortraitStudio(true)}
            >
              📷 New look
            </button>
            <button type="button" className="profile-link-btn" onClick={onOpenProfile}>👤 Profile</button>
          </div>
        </div>
        <div className="messages">
          <div className="date-divider">{today}</div>
          {messages.map((m, i) => (
            <div key={i} className={`msg-row ${m.role}`}>
              <div className="msg-bubble">{m.text}</div>
              {m.role === "ai" && (
                <div className="msg-meta">
                  <div className="msg-feedback">
                    <button title="Good">👍</button>
                    <button title="Bad">👎</button>
                  </div>
                  <span>{new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}</span>
                </div>
              )}
            </div>
          ))}
          {typing && (
            <div className="msg-row ai">
              <div className="msg-bubble">
                <div className="typing"><span /><span /><span /></div>
              </div>
            </div>
          )}
          <div ref={endRef} />
        </div>
        <div className="composer">
          <button className="circle-btn secondary">+</button>
          <button className="circle-btn secondary">🎤</button>
          <input
            value={input}
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && send()}
            placeholder={`Message ${companion.name}…`}
          />
          <button className="send-btn" onClick={send}>➤</button>
          <button className="circle-btn">📷</button>
        </div>
      </main>
    </div>
  );
}

function App() {
  const [config, setConfig] = useState({ site_name: "…", site_tagline: "" });
  const [step, setStep] = useState("loading");
  const [authMode, setAuthMode] = useState("login");
  const [user, setUser] = useState(null);
  const [companion, setCompanion] = useState(null);
  const [greeting, setGreeting] = useState("");
  const [messages, setMessages] = useState([]);
  const [wizard, setWizard] = useState({});
  const [portraitQuota, setPortraitQuota] = useState(null);

  useEffect(() => {
    fetch("/api/config")
      .then((r) => r.json())
      .then((c) => {
        setConfig(c);
        document.title = c.site_name;
      });
  }, []);

  async function loadSession() {
    if (!api.token()) {
      setStep("auth");
      return;
    }
    try {
      const data = await api.get("/api/me");
      setUser(data.user);
      applyDarkMode(data.user?.dark_mode || "device");
      if (data.companion) {
        setCompanion(data.companion);
        setPortraitQuota(data.portrait_quota || null);
        const full = await api.get(`/api/companions/${data.companion.id}`);
        setMessages(full.messages || []);
        setStep("chat");
      } else if (!data.user.policy_accepted) {
        setStep("profile");
      } else {
        setStep("look");
      }
    } catch {
      localStorage.removeItem("token");
      setStep("auth");
    }
  }

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

  if (step === "loading") {
    return <div className="screen"><div className="spinner-ring" /></div>;
  }

  if (step === "auth") {
    return (
      <AuthScreen
        config={config}
        mode={authMode}
        setMode={setAuthMode}
        onAuth={loadSession}
      />
    );
  }

  if (step === "profile") {
    return (
      <ProfileScreen
        onBack={() => { localStorage.removeItem("token"); setStep("auth"); }}
        onNext={(p) => { setWizard((w) => ({ ...w, ...p })); setStep("look"); }}
      />
    );
  }

  if (step === "look") {
    return (
      <LookScreen
        onBack={() => setStep("profile")}
        onNext={(d) => { setWizard((w) => ({ ...w, ...d })); setStep("setup"); }}
      />
    );
  }

  if (step === "setup") {
    return (
      <SetupScreen
        config={config}
        wizard={wizard}
        onBack={() => setStep("look")}
        onNext={(d) => { setWizard((w) => ({ ...w, ...d })); setStep("creating"); }}
      />
    );
  }

  if (step === "creating") {
    return (
      <CreatingScreen
        config={config}
        wizard={wizard}
        onDone={async (c, g) => {
          setCompanion(c);
          setGreeting(g);
          try {
            const me = await api.get("/api/me");
            setPortraitQuota(me.portrait_quota || null);
          } catch { /* ignore */ }
          setStep("chat");
        }}
      />
    );
  }

  if (step === "chat" && companion) {
    return (
      <MainApp
        config={config}
        user={user}
        setUser={setUser}
        companion={companion}
        setCompanion={setCompanion}
        portraitQuota={portraitQuota}
        setPortraitQuota={setPortraitQuota}
        initialMessages={messages}
        greeting={greeting}
        onLogout={() => {
          localStorage.removeItem("token");
          setUser(null);
          setCompanion(null);
          setStep("auth");
        }}
        onNewCompanion={() => setStep("look")}
      />
    );
  }

  return null;
}

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