// Right-side overlay sheet — used to host either Contact details or the AI Agent panel.
// Backdrop dims the rest of the app; sheet slides in from the right.

// Inline right column — sits next to the thread view (not an overlay).
// Used by the AI Agent panel: the thread view squeezes to share horizontal space.
const RightSheet = ({ children, onClose, state = "in", duration = 180 }) => {
  const closing = state === "out";
  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape" && onClose) onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onClose]);

  return (
    <>
      <div
        role="complementary"
        style={{
          // Width is animated so the thread view reclaims the space smoothly
          // instead of snapping when the sheet unmounts.
          flex: "0 0 auto",
          borderLeft: "1px solid #E4E7EC",
          background: "#FFFFFF",
          display: "flex", flexDirection: "column",
          overflow: "hidden",
          pointerEvents: closing ? "none" : "auto",
          animation: `${closing ? "rsSlideOut" : "rsSlideIn"} ${duration}ms cubic-bezier(.2,.7,.2,1) forwards`
        }}>
        {/* Fixed-width inner keeps the content from reflowing as the shell animates. */}
        <div style={{ width: 380, minWidth: 380, flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
          {children}
        </div>
      </div>
      <style>{`
        @keyframes rsSlideIn {
          from { opacity: 0; width: 0 }
          to { opacity: 1; width: 380px }
        }
        @keyframes rsSlideOut {
          from { opacity: 1; width: 380px }
          to { opacity: 0; width: 0 }
        }
        @keyframes agentPulse {
          0%, 100% { box-shadow: 0 0 0 0 rgba(127,86,217,0.45) }
          50% { box-shadow: 0 0 0 6px rgba(127,86,217,0) }
        }
        @keyframes agentDot {
          0%, 80%, 100% { transform: translateY(0); opacity: .35 }
          40% { transform: translateY(-3px); opacity: 1 }
        }
        @keyframes agentSlideUp { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: translateY(0) } }
      `}</style>
    </>
  );
};

// Keeps a RightSheet mounted through its exit animation, so closing it slides
// out instead of vanishing. Children are frozen at their last open value —
// the source data is usually gone by the time the exit plays.
const RightSheetMount = ({ show, onClose, duration = 180, children }) => {
  const [render, setRender] = useState(show);
  const lastChildren = useRef(children);
  if (show) lastChildren.current = children;

  useEffect(() => {
    if (show) { setRender(true); return undefined; }
    const t = setTimeout(() => setRender(false), duration);
    return () => clearTimeout(t);
  }, [show, duration]);

  if (!render) return null;
  return (
    <RightSheet onClose={onClose} state={show ? "in" : "out"} duration={duration}>
      {lastChildren.current}
    </RightSheet>);

};

// ---------------------------------------------------------------------------
// AI Agent panel — appears in the same right slot as Contact details when the
// user clicks "View brief". Embodies an agent persona ("Justy") that has been
// working the conversation: auto-tagging, drafting replies, flagging sentiment
// shifts, and preparing a hand-over briefing.
// ---------------------------------------------------------------------------

const AGENT = {
  name: "Justy",
  role: "AI copilot",
  blurb: "Working alongside you on this thread"
};

const buildAgentActivity = (thread) => {
  const ins = window.buildInsights ? window.buildInsights(thread) : { empty: true };
  if (ins.empty) {
    return { empty: true, ins };
  }
  const name = thread.name?.split(" ")[0] || "Contact";
  const tagSet = thread.tags || [];

  // Athlete-to-Athlete tag/sentiment/replies, keyed by thread.id with sensible
  // tag-driven fallbacks for everything else.
  const TAG_PACKS = {
    t_mia: [
      { label: "High-rebook intent", tone: "good", reason: `Mia explicitly asked to keep working with Zara after a 5★ intro.` },
      { label: "Conversion-ready", tone: "good", reason: `Replied within minutes of the post-call feedback prompt.` },
      { label: "Track & Field", tone: "info", reason: `Mentee sport tag for matching downstream.` }
    ],
    t_marcus: [
      { label: "Service recovery", tone: "warn", reason: `Voicemail flagged a broken meet link mid-call.` },
      { label: "Parent · escalation", tone: "warn", reason: `Inbound voicemail tone was frustrated.` },
      { label: "Resolved on callback", tone: "good", reason: `Priya recovered the call inside 2 minutes.` }
    ],
    t_landon: [
      { label: "Re-engaged mentor", tone: "good", reason: `Replied "Yes! Please book it." after 3 quiet weeks.` },
      { label: "Football · QB", tone: "info", reason: `Mentor sport + position tag.` }
    ],
    t_tyler: [
      { label: "Onboarding complete", tone: "good", reason: `Walkthrough call completed cleanly.` },
      { label: "First-match pending", tone: "info", reason: `Ready for an age-appropriate match this week.` }
    ],
    t_jenna: [
      { label: "Recovery success", tone: "good", reason: `Personal callback restored trust after a missed assignment.` },
      { label: "Advocate-in-the-making", tone: "info", reason: `Last reply was warm and grateful.` }
    ]
  };

  const tags = TAG_PACKS[thread.id] || (
    tagSet.includes("Onboarding") ? [
      { label: "Onboarding", tone: "info", reason: `${name} is still in the onboarding flow.` },
      { label: "Match-ready", tone: "good", reason: `Availability submitted; ready for a first match.` }
    ] : tagSet.includes("Reschedule") ? [
      { label: "Reschedule", tone: "info", reason: `Intro call moved to a new slot.` },
      { label: "Confirmed", tone: "good", reason: `Both sides have the new link.` }
    ] : tagSet.includes("Recurring") ? [
      { label: "Recurring intent", tone: "good", reason: `Open to a recurring booking after the last session.` },
      { label: "Payouts", tone: "info", reason: `Asked about payout cadence.` }
    ] : tagSet.includes("Paused") ? [
      { label: "Seasonal pause", tone: "info", reason: `Stepped back for the active competitive season.` },
      { label: "Re-engage later", tone: "info", reason: `Relationship preserved warmly for re-activation.` }
    ] : [
      { label: "Active match", tone: "info", reason: `Conversation is mid-flow.` },
      { label: "Awaiting reply", tone: "info", reason: `Waiting on the next concrete commitment.` }
    ]
  );

  const SENTIMENT_PACKS = {
    t_mia: { from: "Curious", to: "Excited", delta: +0.36, note: "Tone jumped after the 5★ intro call with Zara." },
    t_marcus: { from: "Neutral", to: "Frustrated → Calm", delta: -0.10, note: "Frustration on voicemail, recovered after the callback." },
    t_landon: { from: "Quiet", to: "Engaged", delta: +0.32, note: "Re-engagement SMS landed; reply within 12 minutes." },
    t_jenna: { from: "Frustrated", to: "Grateful", delta: +0.48, note: "Personal callback turned the conversation around." },
    t_tyler: { from: "Curious", to: "Positive", delta: +0.20, note: "Tyler is excited about taking on his first mentees." }
  };
  const sentimentShift = SENTIMENT_PACKS[thread.id] || { from: "Neutral", to: "Positive", delta: +0.12, note: "Steady tone across recent messages." };

  const REPLY_PACKS = {
    t_mia: [
      { tone: "Warm", text: `So glad to hear, Mia! Sending you the recurring booking link with Zara now — lock in your cadence whenever's good.` },
      { tone: "Concise", text: `Awesome — recurring link with Zara incoming. Weekly or every other week work better?` },
      { tone: "Encouraging", text: `Love this energy. Zara had great things to say too. Booking link on its way.` }
    ],
    t_marcus: [
      { tone: "Apologetic", text: `Hi Marcus, so sorry again about the link confusion. Hannah's call should be running now — I'll check in tomorrow morning to make sure it landed well.` },
      { tone: "Direct", text: `Marcus, the new link is live and the call is in progress. I've also flagged the stale-link issue internally so it doesn't repeat.` },
      { tone: "Reassuring", text: `Totally understand the frustration. Hannah's intro is back on track — I'll personally check in with you tomorrow.` }
    ],
    t_landon: [
      { tone: "Direct", text: `Awesome Landon — booking now! Calendar invite + meet link in the next 5 min.` },
      { tone: "Friendly", text: `Excited to get you back in the rotation! Sending the booking confirmation now.` }
    ],
    t_jenna: [
      { tone: "Warm", text: `Of course, Jenna — happy we got it sorted. I'll check in after Eli's call with Cole.` },
      { tone: "Concise", text: `Thanks Jenna. I'll be in touch right after the intro call to make sure it went well.` }
    ]
  };
  const replies = REPLY_PACKS[thread.id] || [
    { tone: "Helpful", text: `Hey ${name}, thanks for the update — confirming on my end and I'll follow up shortly.` },
    { tone: "Concise", text: `Got it ${name} — getting the next step lined up now.` }
  ];

  const HANDOVER_PACKS = {
    t_mia: {
      summary: `Mia rated her intro with Zara 5★ and asked to keep working with her. Send the recurring booking link today — post-call conversion windows are short.`,
      open: ["Recurring booking link not yet sent", "Confirm cadence (weekly vs biweekly)"]
    },
    t_marcus: {
      summary: `Marcus left an angry voicemail about a broken meet link before Hannah's intro. Priya called back inside 2 min and resolved it (stale link from a prior reschedule). Follow up with a written apology tomorrow.`,
      open: ["Written apology + post-call check-in", "Engineering ticket for stale meet links"]
    },
    t_landon: {
      summary: `Landon went quiet for ~3 weeks; the re-engagement SMS landed and he replied "Yes! Please book it." Send the booking confirmation while he's hot.`,
      open: ["Booking confirmation + calendar invite", "Refresh next-2-week availability"]
    },
    t_jenna: {
      summary: `Jenna's mentor assignment was missed for 5 days. Priya recovered with a personal call and locked Cole Banner on the same call. Last reply was warm — schedule a post-intro check-in.`,
      open: ["Post-intro check-in after 5/3 call", "Add to advocate list pending positive intro"]
    }
  };
  const handoverPack = HANDOVER_PACKS[thread.id];
  const handover = {
    summary: handoverPack ? handoverPack.summary :
      `${name} is mid-flow on this match. Review the last 2-3 messages, confirm the next concrete commitment, and reply within 24h to keep momentum.`,
    facts: [
      { k: "Last touch", v: thread.time || "Recently" },
      { k: "Channel", v: thread.channel === "call" ? "Voice + SMS" : "SMS" },
      { k: "Line", v: thread.line || "—" },
      { k: "Owner", v: thread.assignee?.name || "Unassigned" }
    ],
    open: handoverPack ? handoverPack.open : ["Confirm next concrete step", "Reply within 24h"]
  };

  return {
    empty: false,
    ins,
    tags,
    sentimentShift,
    replies,
    handover,
    activity: [
      { t: "12s ago", icon: "tag",      label: `Auto-tagged thread`,      detail: tags.map(x => x.label).join(" · ") },
      { t: "1m ago",  icon: "sentiment", label: `Sentiment shift detected`, detail: `${sentimentShift.from} → ${sentimentShift.to}` },
      { t: "2m ago",  icon: "reply",    label: `Drafted ${replies.length} reply variants`, detail: "Ready to review" }
    ]
  };
};

const AIAgentPanel = ({ thread, onClose, onSwitchToContact, initialSection = "brief" }) => {
  const a = useMemo(() => buildAgentActivity(thread), [thread.id]);
  const [section, setSection] = useState(initialSection); // brief | tags | replies | sentiment | handover
  // When the parent opens the panel with a different initial tab (e.g. handoff), honor it
  useEffect(() => { setSection(initialSection); }, [initialSection, thread.id]);
  const [acceptedTags, setAcceptedTags] = useState([]);
  const [dismissedTags, setDismissedTags] = useState([]);
  const [pickedReply, setPickedReply] = useState(null);
  const [thinking, setThinking] = useState(true);

  // Briefly show a "thinking" pulse when the panel opens — gives the agent a sense of life
  useEffect(() => {
    setThinking(true);
    const t = setTimeout(() => setThinking(false), 1100);
    return () => clearTimeout(t);
  }, [thread.id]);

  if (a.empty) {
    return <AgentEmptyState thread={thread} onClose={onClose} onSwitchToContact={onSwitchToContact} />;
  }

  const sections = [
    { id: "brief",     label: "Brief",       icon: I.sparkle },
    { id: "tags",      label: "Auto-tags",   icon: I.tag },
    { id: "replies",   label: "Suggested replies", icon: I.chat },
    { id: "sentiment", label: "Sentiment",   icon: I.alert }
  ];

  return (
    <div style={{ width: "100%", height: "100%", display: "flex", flexDirection: "column", background: "#FFFFFF" }}>
      {/* Agent header — minimal: back arrow + title + last-updated + close */}
      <div style={{
        padding: "12px 16px",
        background: "#FFFFFF",
        borderBottom: "1px solid #E4E7EC",
        display: "flex", alignItems: "center", gap: 8, flexShrink: 0
      }}>
        {onSwitchToContact && (
          <button onClick={onSwitchToContact} title="Back to contact details"
            style={agentIconBtn}
            onMouseEnter={(e) => e.currentTarget.style.background = "#F2F4F7"}
            onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
            <I.chevLeft size={16} stroke="#475467" />
          </button>
        )}
        <div style={{ fontSize: 15, fontWeight: 600, color: "#101828" }}>AI Insights</div>
        <div style={{ flex: 1 }} />
        <div style={{ fontSize: 12, color: "#667085", display: "inline-flex", alignItems: "center", gap: 5 }}>
          {thinking ? (
            <>
              <ThinkingDots />
              <span>Reading the thread…</span>
            </>
          ) : (
            <>Updated {a.activity[0].t}</>
          )}
        </div>
        <button onClick={onClose} title="Close" style={agentIconBtn}
          onMouseEnter={(e) => e.currentTarget.style.background = "#F2F4F7"}
          onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
          <I.x size={15} stroke="#475467" />
        </button>
      </div>

      {/* Section nav */}
      <div style={{
        display: "flex", gap: 2, padding: "8px 12px", borderBottom: "1px solid #E4E7EC",
        background: "#FFFFFF", flexShrink: 0, overflowX: "auto"
      }}>
        {sections.map(s => {
          const active = s.id === section;
          const SIcon = s.icon;
          return (
            <button key={s.id} onClick={() => setSection(s.id)}
              style={{
                display: "inline-flex", alignItems: "center", gap: 5, padding: "5px 10px",
                borderRadius: 500, border: "1px solid",
                borderColor: active ? "#B692F6" : "transparent",
                background: active ? "#F4EBFF" : "transparent",
                color: active ? "#5925DC" : "#667085",
                fontSize: 12, fontWeight: active ? 600 : 500, cursor: "pointer",
                whiteSpace: "nowrap", flexShrink: 0, fontFamily: "inherit"
              }}
              onMouseEnter={(e) => { if (!active) e.currentTarget.style.background = "#F9FAFB"; }}
              onMouseLeave={(e) => { if (!active) e.currentTarget.style.background = "transparent"; }}>
              <SIcon size={12} stroke={active ? "#5925DC" : "#667085"} />
              {s.label}
            </button>
          );
        })}
      </div>

      {/* Body */}
      <div style={{ flex: 1, overflowY: "auto", background: "#FAFBFC" }}>
        {section === "brief" && <BriefSection a={a} thread={thread} onJump={setSection} />}
        {section === "tags" && (
          <TagsSection a={a} accepted={acceptedTags} dismissed={dismissedTags}
            onAccept={(label) => setAcceptedTags(s => s.includes(label) ? s : [...s, label])}
            onDismiss={(label) => setDismissedTags(s => s.includes(label) ? s : [...s, label])}
          />
        )}
        {section === "replies" && (
          <RepliesSection a={a} picked={pickedReply} onPick={setPickedReply} />
        )}
        {section === "sentiment" && <SentimentSection a={a} />}
      </div>

      {/* Footer */}
      <div style={{
        padding: "10px 14px", borderTop: "1px solid #E4E7EC", background: "#FFFFFF",
        display: "flex", justifyContent: "space-between", alignItems: "center", gap: 8, flexShrink: 0
      }}>
        <button style={{
          display: "inline-flex", alignItems: "center", gap: 5,
          padding: "6px 10px", borderRadius: 4, border: "1px solid #E4E7EC",
          background: "#FFFFFF", color: "#344054", fontSize: 12, fontWeight: 500,
          cursor: "pointer", fontFamily: "inherit"
        }}
          onClick={() => window.dispatchEvent(new CustomEvent("convo:toast", { detail: { msg: "Justy is regenerating…" } }))}>
          <I.refresh size={12} stroke="#667085" /> Regenerate
        </button>
        <div style={{ fontSize: 11, color: "#98A2B3", display: "inline-flex", alignItems: "center", gap: 5 }}>
          <I.info size={11} stroke="#98A2B3" />
          Verify before acting
        </div>
      </div>
    </div>
  );
};

const agentIconBtn = {
  width: 28, height: 28, borderRadius: 6, border: "1px solid transparent",
  background: "transparent", cursor: "pointer", padding: 0,
  display: "inline-flex", alignItems: "center", justifyContent: "center"
};

const ThinkingDots = () => (
  <span style={{ display: "inline-flex", alignItems: "center", gap: 2 }}>
    {[0,1,2].map(i => (
      <span key={i} style={{
        width: 4, height: 4, borderRadius: 500, background: "#7F56D9",
        animation: `agentDot 1.2s ${i * 0.15}s ease-in-out infinite`
      }} />
    ))}
  </span>
);

// ----- Brief section: headline + activity timeline + jump-to chips ---------
const BriefSection = ({ a, thread, onJump }) => {
  return (
    <div style={{ padding: 16, display: "flex", flexDirection: "column", gap: 14, animation: "agentSlideUp .2s ease-out" }}>
      <div style={{
        background: "#FFFFFF", border: "1px solid #E9D7FE", borderRadius: 10,
        padding: "12px 14px",
        boxShadow: "0 1px 2px rgba(16,24,40,0.04)"
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 6 }}>
          <I.sparkle size={11} stroke="#7F56D9" />
          <span style={{ fontSize: 10, fontWeight: 700, color: "#5925DC", textTransform: "uppercase", letterSpacing: ".06em" }}>
            What I see
          </span>
        </div>
        <div style={{ fontSize: 13, color: "#101828", lineHeight: 1.55 }}>{a.ins.headline}</div>
        <div style={{ display: "flex", gap: 6, marginTop: 10, flexWrap: "wrap" }}>
          <Chip label="Sentiment" value={a.ins.sentiment} />
          <Chip label="Stage" value={a.ins.stage} />
        </div>
      </div>

      <div>
        <SectionLabel>What I'm doing</SectionLabel>
        <div style={{ display: "flex", flexDirection: "column", gap: 0, marginTop: 8 }}>
          {a.activity.map((act, i) => (
            <ActivityRow key={i} act={act} last={i === a.activity.length - 1} onJump={onJump} />
          ))}
        </div>
      </div>

      <div>
        <SectionLabel>Jump to</SectionLabel>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginTop: 8 }}>
          <JumpCard icon={I.tag}    label="Auto-tags"    count={a.tags.length}    accent="#3538CD" bg="#EEF4FF" onClick={() => onJump("tags")} />
          <JumpCard icon={I.chat}   label="Suggested replies" count={a.replies.length} accent="#5925DC" bg="#F4EBFF" onClick={() => onJump("replies")} />
          <JumpCard icon={I.alert}  label="Sentiment"    count={a.sentimentShift.delta > 0 ? `+${(a.sentimentShift.delta * 100).toFixed(0)}%` : `${(a.sentimentShift.delta * 100).toFixed(0)}%`} accent={a.sentimentShift.delta > 0 ? "#027A48" : "#B42318"} bg={a.sentimentShift.delta > 0 ? "#ECFDF3" : "#FEF3F2"} onClick={() => onJump("sentiment")} />
        </div>
      </div>
    </div>
  );
};

const ActivityRow = ({ act, last, onJump }) => {
  const iconMap = {
    tag: I.tag, sentiment: I.alert, reply: I.chat, summary: I.forward
  };
  const sectionMap = { tag: "tags", sentiment: "sentiment", reply: "replies", summary: "handover" };
  const IconC = iconMap[act.icon] || I.sparkle;
  return (
    <button onClick={() => onJump(sectionMap[act.icon] || "brief")}
      style={{
        display: "flex", gap: 10, padding: "8px 4px", textAlign: "left",
        background: "transparent", border: "none", cursor: "pointer", fontFamily: "inherit",
        borderRadius: 6, alignItems: "flex-start", position: "relative"
      }}
      onMouseEnter={(e) => e.currentTarget.style.background = "#F2F4F7"}
      onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
      <div style={{ position: "relative", width: 24, flexShrink: 0, paddingTop: 1 }}>
        <span style={{
          width: 24, height: 24, borderRadius: 500, background: "#F4EBFF",
          border: "1px solid #E9D7FE", display: "inline-flex",
          alignItems: "center", justifyContent: "center"
        }}>
          <IconC size={11} stroke="#7F56D9" />
        </span>
        {!last && <span style={{
          position: "absolute", left: 11, top: 26, bottom: -8, width: 1.5, background: "#E9D7FE"
        }} />}
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: "flex", alignItems: "baseline", gap: 6 }}>
          <span style={{ fontSize: 12, fontWeight: 600, color: "#101828" }}>{act.label}</span>
          <span style={{ fontSize: 10, color: "#98A2B3", fontWeight: 500 }}>{act.t}</span>
        </div>
        <div style={{ fontSize: 11, color: "#667085", marginTop: 1, lineHeight: 1.4 }}>{act.detail}</div>
      </div>
      <I.chevRight size={12} stroke="#98A2B3" style={{ marginTop: 5, flexShrink: 0 }} />
    </button>
  );
};

const JumpCard = ({ icon: IconC, label, count, accent, bg, onClick }) => (
  <button onClick={onClick}
    style={{
      textAlign: "left", cursor: "pointer", fontFamily: "inherit",
      background: "#FFFFFF", border: "1px solid #E4E7EC", borderRadius: 8,
      padding: "10px 12px", display: "flex", alignItems: "center", gap: 10,
      transition: "border-color .15s, box-shadow .15s"
    }}
    onMouseEnter={(e) => {
      e.currentTarget.style.borderColor = "#B692F6";
      e.currentTarget.style.boxShadow = "0 1px 2px rgba(16,24,40,0.04), 0 4px 12px rgba(127,86,217,0.08)";
    }}
    onMouseLeave={(e) => {
      e.currentTarget.style.borderColor = "#E4E7EC";
      e.currentTarget.style.boxShadow = "none";
    }}>
    <span style={{
      width: 28, height: 28, borderRadius: 6, background: bg,
      display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0
    }}>
      <IconC size={13} stroke={accent} />
    </span>
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{ fontSize: 11, color: "#667085", fontWeight: 500 }}>{label}</div>
      <div style={{ fontSize: 14, fontWeight: 600, color: accent, marginTop: 1 }}>{count}</div>
    </div>
  </button>
);

const Chip = ({ label, value }) => (
  <span style={{
    fontSize: 10, fontWeight: 500, color: "#5925DC",
    background: "#FFFFFF", border: "1px solid #E9D7FE",
    padding: "2px 8px", borderRadius: 500, display: "inline-flex", alignItems: "center", gap: 4
  }}>
    <span style={{ color: "#98A2B3", fontWeight: 500 }}>{label}:</span>
    <span style={{ fontWeight: 600 }}>{value}</span>
  </span>
);

const SectionLabel = ({ children }) => (
  <div style={{
    fontSize: 10, fontWeight: 700, color: "#98A2B3",
    textTransform: "uppercase", letterSpacing: ".06em"
  }}>{children}</div>
);

// ----- Auto-tags ------------------------------------------------------------
const TONE_COLORS = {
  good: { bg: "#ECFDF3", fg: "#027A48", border: "#A6F4C5" },
  warn: { bg: "#FEF3F2", fg: "#B42318", border: "#FECDCA" },
  info: { bg: "#EEF4FF", fg: "#3538CD", border: "#C7D7FE" }
};

const TagsSection = ({ a, accepted, dismissed, onAccept, onDismiss }) => {
  const visible = a.tags.filter(t => !dismissed.includes(t.label));
  return (
    <div style={{ padding: 16, display: "flex", flexDirection: "column", gap: 12, animation: "agentSlideUp .2s ease-out" }}>
      <AgentNote>
        I scanned this thread and pulled out tags that match your team's taxonomy. Accept the ones that fit — they'll apply to the contact.
      </AgentNote>
      {visible.length === 0 && (
        <div style={{
          textAlign: "center", padding: "32px 16px",
          background: "#FFFFFF", border: "1px dashed #E4E7EC", borderRadius: 8,
          fontSize: 12, color: "#667085"
        }}>
          All tag suggestions handled.
        </div>
      )}
      {visible.map((t, i) => {
        const isAccepted = accepted.includes(t.label);
        const c = TONE_COLORS[t.tone] || TONE_COLORS.info;
        return (
          <div key={i} style={{
            background: "#FFFFFF", border: "1px solid #E4E7EC", borderRadius: 8,
            padding: "10px 12px", display: "flex", alignItems: "flex-start", gap: 10
          }}>
            <span style={{
              fontSize: 11, fontWeight: 600, color: c.fg, background: c.bg, border: `1px solid ${c.border}`,
              padding: "3px 9px", borderRadius: 500, flexShrink: 0, whiteSpace: "nowrap"
            }}>{t.label}</span>
            <div style={{ flex: 1, fontSize: 12, color: "#667085", lineHeight: 1.45 }}>{t.reason}</div>
            <div style={{ display: "flex", gap: 4, flexShrink: 0 }}>
              {isAccepted ? (
                <span style={{
                  fontSize: 11, fontWeight: 600, color: "#027A48",
                  display: "inline-flex", alignItems: "center", gap: 3,
                  padding: "4px 8px"
                }}>
                  <I.check size={11} stroke="#027A48" /> Applied
                </span>
              ) : (
                <>
                  <button onClick={() => onAccept(t.label)} title="Apply tag"
                    style={miniBtn("primary")}>
                    <I.check size={11} stroke="#FFFFFF" />
                  </button>
                  <button onClick={() => onDismiss(t.label)} title="Dismiss"
                    style={miniBtn("ghost")}>
                    <I.x size={11} stroke="#667085" />
                  </button>
                </>
              )}
            </div>
          </div>
        );
      })}
      {accepted.length > 0 && (
        <div style={{ fontSize: 11, color: "#027A48", display: "inline-flex", alignItems: "center", gap: 5 }}>
          <I.check size={11} stroke="#027A48" />
          {accepted.length} tag{accepted.length === 1 ? "" : "s"} applied to this contact
        </div>
      )}
    </div>
  );
};

const miniBtn = (variant) => ({
  width: 26, height: 26, borderRadius: 4, border: "1px solid",
  borderColor: variant === "primary" ? "#7F56D9" : "#E4E7EC",
  background: variant === "primary" ? "#7F56D9" : "#FFFFFF",
  cursor: "pointer", padding: 0,
  display: "inline-flex", alignItems: "center", justifyContent: "center"
});

// ----- Suggested replies ----------------------------------------------------
const RepliesSection = ({ a, picked, onPick }) => {
  return (
    <div style={{ padding: 16, display: "flex", flexDirection: "column", gap: 12, animation: "agentSlideUp .2s ease-out" }}>
      <AgentNote>
        Three drafts in different tones, each grounded in what {a.ins.sentiment.toLowerCase().includes("positive") ? "they've shared so far" : "the thread is asking for"}. Insert one to seed the composer — you can edit before sending.
      </AgentNote>
      {a.replies.map((r, i) => {
        const isPicked = picked === i;
        return (
          <div key={i} style={{
            background: "#FFFFFF",
            border: `1px solid ${isPicked ? "#B692F6" : "#E4E7EC"}`,
            borderRadius: 8, padding: "12px 14px",
            boxShadow: isPicked ? "0 1px 2px rgba(16,24,40,0.04), 0 4px 12px rgba(127,86,217,0.10)" : "none",
            transition: "border-color .15s, box-shadow .15s"
          }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 6 }}>
              <span style={{
                fontSize: 10, fontWeight: 700, color: "#5925DC",
                background: "#F4EBFF", padding: "2px 8px", borderRadius: 500,
                textTransform: "uppercase", letterSpacing: ".04em"
              }}>{r.tone}</span>
              <span style={{ fontSize: 10, color: "#98A2B3" }}>{r.text.length} chars</span>
            </div>
            <div style={{ fontSize: 13, color: "#101828", lineHeight: 1.5, marginBottom: 10 }}>{r.text}</div>
            <div style={{ display: "flex", gap: 6 }}>
              <button onClick={() => {
                onPick(i);
                window.dispatchEvent(new CustomEvent("convo:toast", { detail: { msg: "Draft inserted into composer" } }));
              }} style={{
                flex: 1, padding: "7px 10px", borderRadius: 4, border: "none",
                background: "#7F56D9", color: "#FFFFFF", fontSize: 12, fontWeight: 600,
                cursor: "pointer", fontFamily: "inherit",
                display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 5
              }}>
                <I.send size={11} stroke="#FFFFFF" /> Insert
              </button>
              <button onClick={() => {
                navigator.clipboard?.writeText(r.text);
                window.dispatchEvent(new CustomEvent("convo:toast", { detail: { msg: "Copied to clipboard" } }));
              }} style={{
                padding: "7px 10px", borderRadius: 4, border: "1px solid #E4E7EC",
                background: "#FFFFFF", color: "#344054", fontSize: 12, fontWeight: 500,
                cursor: "pointer", fontFamily: "inherit"
              }}>
                Copy
              </button>
            </div>
          </div>
        );
      })}
    </div>
  );
};

// ----- Sentiment ------------------------------------------------------------
const SentimentSection = ({ a }) => {
  const s = a.sentimentShift;
  const positive = s.delta >= 0;
  const accent = positive ? "#027A48" : "#B42318";
  const bg = positive ? "#ECFDF3" : "#FEF3F2";
  const border = positive ? "#A6F4C5" : "#FECDCA";
  // Mock 8-point trend ending at the current sentiment
  const trend = positive
    ? [0.45, 0.48, 0.52, 0.55, 0.58, 0.62, 0.68, 0.72]
    : [0.62, 0.58, 0.54, 0.48, 0.42, 0.34, 0.28, 0.20];
  const max = Math.max(...trend);
  const min = Math.min(...trend);

  return (
    <div style={{ padding: 16, display: "flex", flexDirection: "column", gap: 12, animation: "agentSlideUp .2s ease-out" }}>
      <AgentNote>
        I noticed a sentiment shift in this thread. Here's what changed and what I'd do next.
      </AgentNote>
      <div style={{
        background: "#FFFFFF", border: `1px solid ${border}`, borderRadius: 10, padding: "14px 16px"
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 12 }}>
          <span style={{
            width: 36, height: 36, borderRadius: 8, background: bg, border: `1px solid ${border}`,
            display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0
          }}>
            <I.alert size={16} stroke={accent} />
          </span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12, color: "#667085" }}>{s.from} → {s.to}</div>
            <div style={{ fontSize: 18, fontWeight: 700, color: accent, lineHeight: 1.1, marginTop: 2 }}>
              {positive ? "+" : ""}{(s.delta * 100).toFixed(0)}% {positive ? "warmer" : "cooler"}
            </div>
          </div>
        </div>

        {/* Sparkline */}
        <div style={{
          height: 56, position: "relative", marginBottom: 12,
          background: "#FAFBFC", borderRadius: 6, padding: 8
        }}>
          <svg viewBox="0 0 100 40" preserveAspectRatio="none" style={{ width: "100%", height: "100%" }}>
            <defs>
              <linearGradient id="sentFill" x1="0" x2="0" y1="0" y2="1">
                <stop offset="0%" stopColor={accent} stopOpacity="0.18" />
                <stop offset="100%" stopColor={accent} stopOpacity="0" />
              </linearGradient>
            </defs>
            {(() => {
              const range = max - min || 1;
              const points = trend.map((v, i) => [
                (i / (trend.length - 1)) * 100,
                40 - ((v - min) / range) * 36 - 2
              ]);
              const path = points.map((p, i) => (i === 0 ? "M" : "L") + p[0] + "," + p[1]).join(" ");
              const fill = path + ` L 100,40 L 0,40 Z`;
              return (
                <>
                  <path d={fill} fill="url(#sentFill)" />
                  <path d={path} fill="none" stroke={accent} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                  {points.map(([x, y], i) => (
                    <circle key={i} cx={x} cy={y} r={i === points.length - 1 ? 2.5 : 1.2} fill={accent} />
                  ))}
                </>
              );
            })()}
          </svg>
        </div>

        <div style={{ fontSize: 12, color: "#344054", lineHeight: 1.5 }}>{s.note}</div>
      </div>

      <div>
        <SectionLabel>Recommended next moves</SectionLabel>
        <div style={{ display: "flex", flexDirection: "column", gap: 6, marginTop: 8 }}>
          {(positive
            ? ["Send the comparison one-pager while momentum is high", "Propose Thursday afternoon for a sync"]
            : ["Loop in CSM before responding", "Acknowledge the friction in your reply", "Offer a 1:1 review call"]
          ).map((m, i) => (
            <div key={i} style={{
              background: "#FFFFFF", border: "1px solid #E4E7EC", borderRadius: 6,
              padding: "8px 12px", fontSize: 12, color: "#344054",
              display: "flex", alignItems: "center", gap: 8
            }}>
              <span style={{
                width: 18, height: 18, borderRadius: 500, background: "#F4EBFF",
                color: "#7F56D9", display: "inline-flex", alignItems: "center", justifyContent: "center",
                fontSize: 10, fontWeight: 700, flexShrink: 0
              }}>{i + 1}</span>
              {m}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

// ----- Hand-over ------------------------------------------------------------
const HandoverSection = ({ a, thread }) => {
  const [copied, setCopied] = useState(false);
  const summary = `${thread.name} — ${a.handover.summary}\n\nKey facts:\n${a.handover.facts.map(f => `• ${f.k}: ${f.v}`).join("\n")}\n\nOpen items:\n${a.handover.open.map(o => `• ${o}`).join("\n")}`;

  const onCopy = () => {
    navigator.clipboard?.writeText(summary);
    setCopied(true);
    window.dispatchEvent(new CustomEvent("convo:toast", { detail: { msg: "Brief copied — paste into Slack or email" } }));
    setTimeout(() => setCopied(false), 1800);
  };

  return (
    <div style={{ padding: 16, display: "flex", flexDirection: "column", gap: 12, animation: "agentSlideUp .2s ease-out" }}>
      <AgentNote>
        If you're handing this off — to a teammate, a manager, or just future-you — here's the brief I'd lead with.
      </AgentNote>

      <div style={{
        background: "#FFFFFF", border: "1px solid #E4E7EC", borderRadius: 10, padding: "14px 16px",
        display: "flex", flexDirection: "column", gap: 12
      }}>
        <div>
          <SectionLabel>Summary</SectionLabel>
          <div style={{ fontSize: 13, color: "#101828", lineHeight: 1.55, marginTop: 6 }}>
            {a.handover.summary}
          </div>
        </div>

        <div style={{ height: 1, background: "#F2F4F7" }} />

        <div>
          <SectionLabel>Key facts</SectionLabel>
          <div style={{ display: "grid", gridTemplateColumns: "auto 1fr", columnGap: 14, rowGap: 6, marginTop: 6 }}>
            {a.handover.facts.map((f, i) => (
              <React.Fragment key={i}>
                <span style={{ fontSize: 11, color: "#98A2B3" }}>{f.k}</span>
                <span style={{ fontSize: 12, color: "#101828", fontWeight: 500 }}>{f.v}</span>
              </React.Fragment>
            ))}
          </div>
        </div>

        <div style={{ height: 1, background: "#F2F4F7" }} />

        <div>
          <SectionLabel>Open items</SectionLabel>
          <div style={{ display: "flex", flexDirection: "column", gap: 6, marginTop: 6 }}>
            {a.handover.open.map((o, i) => (
              <div key={i} style={{
                fontSize: 12, color: "#344054",
                display: "flex", alignItems: "flex-start", gap: 8, lineHeight: 1.4
              }}>
                <span style={{
                  width: 14, height: 14, borderRadius: 3, border: "1.5px solid #D0D5DD",
                  flexShrink: 0, marginTop: 1
                }} />
                {o}
              </div>
            ))}
          </div>
        </div>
      </div>

      <div style={{ display: "flex", gap: 8 }}>
        <button onClick={onCopy} style={{
          flex: 1, padding: "9px 12px", borderRadius: 6, border: "none",
          background: "#7F56D9", color: "#FFFFFF", fontSize: 12, fontWeight: 600,
          cursor: "pointer", fontFamily: "inherit",
          display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6
        }}>
          {copied ? <><I.check size={12} stroke="#FFFFFF" /> Copied</> : <><I.forward size={12} stroke="#FFFFFF" /> Copy brief</>}
        </button>
        <button onClick={() => window.dispatchEvent(new CustomEvent("convo:toast", { detail: { msg: "Posted to #sales-handoff" } }))}
          style={{
          padding: "9px 12px", borderRadius: 6, border: "1px solid #E4E7EC",
          background: "#FFFFFF", color: "#344054", fontSize: 12, fontWeight: 500,
          cursor: "pointer", fontFamily: "inherit",
          display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6
        }}>
          Post to Slack
        </button>
      </div>
    </div>
  );
};

const AgentNote = ({ children }) => (
  <div style={{
    display: "flex", alignItems: "flex-start", gap: 10,
    background: "#FFFFFF", border: "1px solid #E9D7FE", borderRadius: 8,
    padding: "10px 12px"
  }}>
    <span style={{
      width: 22, height: 22, borderRadius: 500, flexShrink: 0,
      background: "linear-gradient(135deg, #7F56D9 0%, #4A1FB8 100%)",
      color: "#FFFFFF", display: "inline-flex", alignItems: "center", justifyContent: "center",
      fontSize: 9, fontWeight: 700
    }}>J</span>
    <div style={{ fontSize: 12, color: "#5925DC", lineHeight: 1.5, fontStyle: "italic" }}>
      {children}
    </div>
  </div>
);

const AgentEmptyState = ({ thread, onClose, onSwitchToContact }) => (
  <div style={{ width: "100%", height: "100%", display: "flex", flexDirection: "column", background: "#FFFFFF" }}>
    <div style={{
      padding: "14px 16px", borderBottom: "1px solid #E4E7EC",
      display: "flex", alignItems: "center", gap: 10, flexShrink: 0
    }}>
      <div style={{
        width: 32, height: 32, borderRadius: 8,
        background: "#F2F4F7", display: "inline-flex", alignItems: "center", justifyContent: "center"
      }}>
        <I.sparkle size={14} stroke="#98A2B3" />
      </div>
      <div style={{ fontSize: 13, fontWeight: 600, color: "#101828", flex: 1 }}>{AGENT.name}</div>
      <button onClick={onClose} style={agentIconBtn}>
        <I.x size={15} stroke="#667085" />
      </button>
    </div>
    <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: 24, background: "#FAFBFC" }}>
      <div style={{ maxWidth: 280, textAlign: "center" }}>
        <div style={{
          width: 48, height: 48, borderRadius: 12, background: "#F2F4F7",
          display: "inline-flex", alignItems: "center", justifyContent: "center", marginBottom: 12
        }}>
          <I.sparkle size={20} stroke="#98A2B3" />
        </div>
        <div style={{ fontSize: 14, fontWeight: 600, color: "#344054", marginBottom: 6 }}>Not enough to work with yet</div>
        <div style={{ fontSize: 12, color: "#667085", lineHeight: 1.5 }}>
          I'll start tagging, drafting, and watching tone the moment this thread has a couple of real exchanges.
        </div>
        {onSwitchToContact && (
          <button onClick={onSwitchToContact} style={{
            marginTop: 14, padding: "7px 12px", borderRadius: 4, border: "1px solid #E4E7EC",
            background: "#FFFFFF", color: "#344054", fontSize: 12, fontWeight: 500,
            cursor: "pointer", fontFamily: "inherit"
          }}>
            View contact details
          </button>
        )}
      </div>
    </div>
  </div>
);

window.RightSheet = RightSheet;
window.RightSheetMount = RightSheetMount;
window.AIAgentPanel = AIAgentPanel;
window.BriefSection = BriefSection;
window.buildAgentActivity = buildAgentActivity;

// Overlay sheet — used by Contact details (image-2 behavior).
// Slides over the thread with a dim backdrop; does not push layout.
const OverlaySheet = ({ children, onClose }) => {
  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape" && onClose) onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onClose]);
  return (
    <>
      <div onClick={onClose} style={{
        position: "absolute", inset: 0, zIndex: 40,
        background: "rgba(16,24,40,0.32)",
        animation: "rsFade .18s ease-out"
      }} />
      <div role="dialog" aria-modal="true" style={{
        position: "absolute", top: 0, right: 0, bottom: 0, zIndex: 41,
        width: 420, maxWidth: "92vw", background: "#FFFFFF",
        boxShadow: "-12px 0 32px rgba(16,24,40,.18), -2px 0 6px rgba(16,24,40,.06)",
        display: "flex", flexDirection: "column",
        animation: "osSlide .22s cubic-bezier(.2,.7,.2,1)"
      }}>{children}</div>
      <style>{`
        @keyframes rsFade { from { opacity: 0 } to { opacity: 1 } }
        @keyframes osSlide { from { transform: translateX(24px); opacity: 0 } to { transform: translateX(0); opacity: 1 } }
      `}</style>
    </>
  );
};
window.OverlaySheet = OverlaySheet;
