/* deploy.jsx - Flow 3: deployment channels (embed, API, SDK, messaging) */

function CodeBlock({ children, lang }) {
  const [copied, setCopied] = React.useState(false);
  const copy = () => { navigator.clipboard?.writeText(children); setCopied(true); setTimeout(() => setCopied(false), 1400); };
  return (
    <div style={{ position: "relative", background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: "var(--r-md)", overflow: "hidden" }}>
      <div className="between" style={{ padding: "7px 12px", borderBottom: "1px solid var(--border)" }}>
        <span className="caption mono" style={{ fontSize: 11 }}>{lang}</span>
        <button className="btn btn-ghost btn-sm" onClick={copy} style={{ height: 24 }}>{I(copied ? "check" : "copy", { style: { width: 13, height: 13 } })} {copied ? "Copied" : "Copy"}</button>
      </div>
      <pre className="mono" style={{ margin: 0, padding: "13px 14px", fontSize: 12, lineHeight: 1.65, overflowX: "auto", color: "var(--ink)", whiteSpace: "pre" }}>{children}</pre>
    </div>
  );
}

const CHANNELS = [
  { id: "web", group: "Recommended", name: "Website widget", icon: "globe", desc: "Embeddable chat bubble", status: "ready" },
  { id: "api", group: "Recommended", name: "API endpoint", icon: "code", desc: "REST for your own UI", status: "ready" },
  { id: "sdk", group: "Recommended", name: "SDK", icon: "layers", desc: "JS / Python libraries", status: "ready" },
  { id: "whatsapp", group: "Messaging", name: "WhatsApp Business", icon: "whatsapp", desc: "via Cloud API", status: "soon" },
  { id: "telegram", group: "Messaging", name: "Telegram", icon: "send", desc: "Bot integration", status: "soon" },
  { id: "messenger", group: "Messaging", name: "Instagram & Messenger", icon: "message", desc: "Meta inbox", status: "soon" },
  { id: "wechat", group: "Messaging", name: "WeChat", icon: "chat", desc: "China-market setup", status: "regional" },
];

function StatusPill({ status }) {
  if (status === "ready") return <span className="badge badge-good">{I("check", { style: { width: 11, height: 11 } })} Ready</span>;
  if (status === "regional") return <span className="badge badge-warn">{I("globe", { style: { width: 11, height: 11 } })} Regional</span>;
  return <span className="badge badge-neutral">Coming soon</span>;
}

function DeployView({ ctx }) {

  const { user, signIn } = useFirebaseAuth();
  const [sel, setSel] = React.useState("web");
  const [accent, setAccent] = React.useState("#1A1A1C");
  const [pos, setPos] = React.useState("right");
  const [deployment, setDeployment] = React.useState(null);
  const [deployBusy, setDeployBusy] = React.useState(false);
  const [deployStatus, setDeployStatus] = React.useState(null);
  const [llmKey, setLlmKey] = React.useState(null);
  const [apiKey, setApiKey] = React.useState(null);
  const [apiKeyBusy, setApiKeyBusy] = React.useState(false);
  const [apiKeyStatus, setApiKeyStatus] = React.useState(null);
  const ch = CHANNELS.find(c => c.id === sel);
  const integrationSettings = window.ModelOSIntegrations?.load?.() || {};
  const activeAgent = ctx.activeAgent || integrationSettings.activeAgent;
  const botId = activeAgent?.modelId || "";
  const tenantId = user?.uid || "";
  const appOrigin = window.location.origin;
  const widgetSrc = `${appOrigin}/widget.js`;
  const apiBaseUrl = (integrationSettings.backendBaseUrl || appOrigin).replace(/\/$/, "");
  const localLlm = window.ModelOSIntegrations?.normalizeLlmSettings?.(integrationSettings) || {};
  const deployed = Boolean(deployment?.deployed || deployment?.status === "active");
  const deploymentId = deployment?.deploymentId || "";

  React.useEffect(() => {
    let cancelled = false;
    if (!user || !botId) {
      setDeployment(null);
      return;
    }
    user.getIdToken()
      .then(token => fetch(`${apiBaseUrl}/api/model-os/deployments/status?${new URLSearchParams({ tenantId: user.uid, modelId: botId, channel: "website_widget" }).toString()}`, {
        cache: "no-store",
        headers: { Authorization: `Bearer ${token}`, "Cache-Control": "no-cache" },
      }))
      .then(res => res.json())
      .then(data => {
        if (cancelled) return;
        if (data.success) setDeployment(data.deployment ? { ...data.deployment, deployed: data.deployed, deploymentId: data.deploymentId } : { deployed: false, deploymentId: data.deploymentId });
      })
      .catch(err => {
        if (!cancelled) setDeployStatus({ type: "error", text: err?.message || "Could not load deployment status" });
      });
    return () => { cancelled = true; };
  }, [apiBaseUrl, botId, user]);

  React.useEffect(() => {
    let cancelled = false;
    if (!user || !botId) {
      setLlmKey(null);
      return;
    }
    window.ModelOSIntegrations?.loadStoredLlmKey?.(botId, user)
      .then(data => { if (!cancelled) setLlmKey(data.key || null); })
      .catch(() => { if (!cancelled) setLlmKey(null); });
    return () => { cancelled = true; };
  }, [botId, user]);
  React.useEffect(() => {
    let cancelled = false;
    if (!user || !botId) {
      setApiKey(null);
      return;
    }

    user.getIdToken()
      .then(token => fetch(`${apiBaseUrl}/api/model-os/api-keys?${new URLSearchParams({ modelId: botId }).toString()}`, {
        cache: "no-store",
        headers: {
          Authorization: `Bearer ${token}`,
          "Cache-Control": "no-cache",
        },
      }))
      .then(async res => {
        const data = await res.json().catch(() => ({}));
        if (!res.ok || data.success === false) throw new Error(data.error || "Could not load API keys");
        return data;
      })
      .then(data => {
        if (!cancelled) setApiKey(data.keys?.[0] || null);
      })
      .catch(err => {
        if (!cancelled) setApiKeyStatus({ type: "error", text: err?.message || "Could not load API keys" });
      });

    return () => { cancelled = true; };
  }, [apiBaseUrl, botId, user]);

  const updateDeployment = async (action, options = {}) => {
    if (!user) {
      await signIn();
      return;
    }
    if (!botId) {
      setDeployStatus({ type: "error", text: "Upload a PDF first so Model OS can create a botId." });
      return;
    }
    setDeployBusy(true);
    if (!options.silent) setDeployStatus(null);
    try {
      if (action !== "disable") {
        const savedLlm = await window.ModelOSIntegrations.ensureStoredLlmKey({ modelId: botId, settings: integrationSettings, authUser: user });
        setLlmKey(savedLlm.key || null);
      }
      const token = await user.getIdToken();
      const res = await fetch(`${apiBaseUrl}/api/model-os/deployments`, {
        method: "POST",
        headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
        body: JSON.stringify({
          action,
          tenantId: user.uid,
          modelId: botId,
          channel: "website_widget",
          accent,
          position: pos,
          widgetSrc,
          backendUrl: apiBaseUrl,
        }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok || data.success === false) throw new Error(data.error || "Deployment request failed");
      const next = data.deployment ? { ...data.deployment, deployed: data.deployed, deploymentId: data.deploymentId } : { deployed: data.deployed, deploymentId: data.deploymentId };
      setDeployment(next);
      window.ModelOSIntegrations?.save?.({ websiteDeployment: next });
      if (!options.silent) setDeployStatus({ type: "success", text: data.deployed ? "Widget ready. Use the embed code below." : "Widget disabled. Existing embeds will stop answering." });
    } catch (err) {
      setDeployStatus({ type: "error", text: err?.message || "Deployment request failed" });
    } finally {
      setDeployBusy(false);
    }
  };

  const autoDeployStarted = React.useRef(false);
  React.useEffect(() => {
    if (!user || !botId || deployed || deployBusy || autoDeployStarted.current) return;
    autoDeployStarted.current = true;
    updateDeployment("activate", { silent: true });
  }, [user, botId, deployed, deployBusy]);

  const generateApiKey = async (rotate = false) => {
    if (!user) {
      setApiKeyStatus({ type: "info", text: "Sign in with Google, then generate the API key again." });
      await signIn();
      return;
    }
    if (!botId) {
      setApiKeyStatus({ type: "error", text: "Upload a PDF first so Model OS can create a botId." });
      return;
    }

    setApiKeyBusy(true);
    setApiKeyStatus(null);
    try {
      const token = await user.getIdToken();
      if (rotate && apiKey?.keyId) {
        const revokeRes = await fetch(`${apiBaseUrl}/api/model-os/api-keys/${encodeURIComponent(apiKey.keyId)}/revoke`, {
          method: "POST",
          headers: { Authorization: `Bearer ${token}` },
        });
        const revokeData = await revokeRes.json().catch(() => ({}));
        if (!revokeRes.ok || revokeData.success === false) throw new Error(revokeData.error || "Could not revoke the old API key");
      }

      const res = await fetch(`${apiBaseUrl}/api/model-os/api-keys`, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${token}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          modelId: botId,
          tenantId,
          name: `${activeAgent?.name || "Model OS bot"} API key`,
        }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok || data.success === false) throw new Error(data.error || "Could not generate API key");
      setApiKey({ ...data.apiKey, secret: data.secret });
      setApiKeyStatus({ type: "success", text: "API key generated. Copy it now; the full key is shown only once." });
    } catch (err) {
      setApiKeyStatus({ type: "error", text: err?.message || "Could not generate API key" });
    } finally {
      setApiKeyBusy(false);
    }
  };

  const copyApiKey = async () => {
    if (!apiKey?.secret) {
      setApiKeyStatus({ type: "info", text: "For security, saved keys are masked. Rotate the key to reveal a new copyable value." });
      return;
    }
    await navigator.clipboard?.writeText(apiKey.secret);
    setApiKeyStatus({ type: "success", text: "API key copied." });
  };

  const embed = `<script>
  (function(){
    var s = document.createElement('script');
    s.src = "${widgetSrc}";
    s.async = true;
    s.dataset.botId = "${botId || "UPLOAD_A_PDF_FIRST"}";
    s.dataset.tenantId = "${tenantId}";
    s.dataset.deploymentId = "${deploymentId || "CLICK_DEPLOY_FIRST"}";
    s.dataset.accent = "${accent}";
    s.dataset.position = "${pos}";
    s.dataset.backendUrl = "${apiBaseUrl}";
    document.head.appendChild(s);
  })();
<\/script>`;

  const curl = `curl ${apiBaseUrl}/api/model-os/v1/chat \\
  -H "Authorization: Bearer ${apiKey?.secret || "YOUR_MODEL_OS_API_KEY"}" \\
  -H "Content-Type: application/json" \\
  -d '{
    "modelId": "${botId || "UPLOAD_A_PDF_FIRST"}",
    "tenantId": "${tenantId}",
    "question": "What does the uploaded knowledge base say?",
    "llmProvider": "openai",
    "llmModel": "gpt-4o-mini",
    "llmApiKey": "YOUR_OPENAI_ANTHROPIC_GEMINI_OR_GLM_KEY",
    "topK": 5
  }'`;

  const sdk = `npm install @modelos/sdk

import { ModelOS } from "@modelos/sdk";

const mos = new ModelOS("mos_live_****7Q2x");
const res = await mos.chat({
  bot: "${botId || "UPLOAD_A_PDF_FIRST"}",
  tenantId: "${tenantId}",
  message: userInput,
  rag: true,
});`;

  return (
    <div className="page page-wide">
      <PageHead eyebrow="Step 3 of 3 - Ship"
        title="Deploy your chatbot"
        sub="Put your assistant in front of customers. Start with a website widget or API, then add messaging channels as you grow.">
        {deployed
          ? <span className="badge badge-good" style={{ height: 30 }}>{I("checkCircle", { style: { width: 14, height: 14 } })} Website widget ready</span>
          : null}
      </PageHead>

      <div style={{ display: "grid", gridTemplateColumns: "300px 1fr", gap: 20, alignItems: "start" }} className="dp-grid">
        {/* channel list */}
        <div className="stack fu fu-1" style={{ gap: 14 }}>
          {["Recommended", "Messaging"].map(group => (
            <div key={group} className="card" style={{ overflow: "hidden" }}>
              <div className="card-hd" style={{ padding: "11px 16px" }}><span className="eyebrow">{group}</span></div>
              <div className="stack" style={{ padding: 6 }}>
                {CHANNELS.filter(c => c.group === group).map(c => (
                  <div key={c.id} className="row" onClick={() => setSel(c.id)}
                       style={{ gap: 11, padding: "10px 11px", borderRadius: "var(--r-sm)", cursor: "pointer", background: sel === c.id ? "var(--primary-soft)" : "transparent", transition: "background .14s" }}>
                    <div style={{ width: 32, height: 32, borderRadius: "var(--r-sm)", background: "var(--surface-2)", border: "1px solid var(--border)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--ink-2)", flex: "none" }}>{I(c.icon, { style: { width: 16, height: 16 } })}</div>
                    <div className="grow" style={{ minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 600 }}>{c.name}</div>
                      <div className="caption">{c.desc}</div>
                    </div>
                    {c.status === "ready" && <span className="dot" style={{ background: "var(--good)" }} />}
                  </div>
                ))}
              </div>
            </div>
          ))}
        </div>

        {/* config */}
        <div className="stack fu fu-2" style={{ gap: 18 }}>
          <div className="between wrap" style={{ gap: 12 }}>
            <div className="row" style={{ gap: 12 }}>
              <div style={{ width: 42, height: 42, borderRadius: "var(--r-md)", background: "var(--primary)", color: "var(--primary-ink)", display: "flex", alignItems: "center", justifyContent: "center", flex: "none" }}>{I(ch.icon, { style: { width: 20, height: 20 } })}</div>
              <div>
                <div className="h2">{ch.name}</div>
                <div className="caption">{ch.desc}</div>
              </div>
            </div>
            <StatusPill status={ch.status} />
          </div>

          {sel === "web" && (
            <div style={{ display: "grid", gridTemplateColumns: "1fr 300px", gap: 18, alignItems: "start" }} className="web-grid">
              <div className="stack" style={{ gap: 16 }}>
                <div className="card card-pad stack" style={{ gap: 14 }}>
                  <span className="h3">Appearance</span>
                  <div>
                    <label className="field-label">Accent color</label>
                    <div className="row" style={{ gap: 8 }}>
                      {["#1A1A1C", "#2360C4", "#157A4F", "#9A6411", "#5B4BDA"].map(c => (
                        <button key={c} onClick={() => setAccent(c)} style={{ width: 30, height: 30, borderRadius: "var(--r-sm)", background: c, border: accent === c ? "2px solid var(--ink)" : "1px solid var(--border-2)", cursor: "pointer", outline: accent === c ? "2px solid var(--bg)" : "none", outlineOffset: -4 }} />
                      ))}
                    </div>
                  </div>
                  <div>
                    <label className="field-label">Bubble position</label>
                    <div className="tabs">
                      {["left", "right"].map(p => <button key={p} className="tab" data-on={pos === p ? "1" : "0"} onClick={() => setPos(p)} style={{ textTransform: "capitalize" }}>{p}</button>)}
                    </div>
                  </div>
                </div>
                <div className="stack" style={{ gap: 8 }}>
                  <span className="label">Paste before <span className="mono">&lt;/body&gt;</span></span>
                  {!botId && (
                    <div className="badge badge-warn" style={{ alignSelf: "flex-start" }}>
                      {I("info", { style: { width: 13, height: 13 } })}
                      Upload a PDF first so Model OS can create a real botId.
                    </div>
                  )}
                  <CodeBlock lang="html - widget embed">{embed}</CodeBlock>
                </div>
              </div>

              {/* live preview */}
              <div className="card" style={{ overflow: "hidden", position: "sticky", top: 20 }}>
                <div className="caption" style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)" }}>Preview</div>
                <div style={{ position: "relative", height: 280, background: "var(--surface-2)", backgroundImage: "radial-gradient(var(--border-2) 1px, transparent 0)", backgroundSize: "16px 16px" }}>
                  <div style={{ position: "absolute", bottom: 14, [pos]: 14, width: 188, borderRadius: 14, overflow: "hidden", boxShadow: "var(--sh-lg)", border: "1px solid var(--border)", background: "var(--surface)" }}>
                    <div style={{ background: accent, color: "#fff", padding: "10px 12px", fontSize: 12, fontWeight: 700 }}>Assistant</div>
                    <div className="stack" style={{ gap: 6, padding: 10 }}>
                      <div style={{ alignSelf: "flex-start", background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 10, padding: "6px 9px", fontSize: 11 }}>Hi! How can I help?</div>
                      <div style={{ alignSelf: "flex-end", background: accent, color: "#fff", borderRadius: 10, padding: "6px 9px", fontSize: 11 }}>What's the range?</div>
                    </div>
                  </div>
                  <div style={{ position: "absolute", bottom: 14, [pos]: 14, transform: "translateY(0)" }} />
                  <div style={{ position: "absolute", bottom: 14, [pos === "right" ? "right" : "left"]: 14, width: 44, height: 44, borderRadius: "50%", background: accent, display: "flex", alignItems: "center", justifyContent: "center", color: "#fff", boxShadow: "var(--sh-md)", display: "none" }}>{I("chat", { style: { width: 20, height: 20 } })}</div>
                </div>
              </div>
            </div>
          )}

          {sel === "api" && (
            <div className="stack" style={{ gap: 16 }}>
              <div className="card card-pad stack" style={{ gap: 12 }}>
                <span className="h3">Model OS API key</span>
                <div className="row" style={{ gap: 8 }}>
                  <input className="input mono" readOnly value={apiKey?.secret || apiKey?.masked || "No API key generated"} style={{ fontSize: 12.5 }} />
                  {apiKey
                    ? <button className="btn btn-secondary" onClick={copyApiKey} disabled={apiKeyBusy}>{I("copy")} Copy</button>
                    : <button className="btn btn-primary" onClick={() => generateApiKey(false)} disabled={apiKeyBusy || !botId}>{I("code")} Generate</button>}
                  {apiKey && <button className="btn btn-ghost" onClick={() => generateApiKey(true)} disabled={apiKeyBusy}>{I("refresh")} Rotate</button>}
                </div>
                <div className="caption">For server-to-server API calls into Model OS. This is different from the LLM provider key used by the widget.</div>
                {apiKeyStatus && <div className="caption" style={{ color: apiKeyStatus.type === "error" ? "var(--danger)" : "var(--ink-2)" }}>{apiKeyStatus.text}</div>}
              </div>
              <div className="stack" style={{ gap: 8 }}>
                <span className="label">Send a message</span>
                <CodeBlock lang="bash - POST /v1/chat">{curl}</CodeBlock>
              </div>
            </div>
          )}

          {sel === "sdk" && (
            <div className="stack" style={{ gap: 16 }}>
              <div className="row wrap" style={{ gap: 10 }}>
                {["JavaScript / TS", "Python", "Go", "Ruby"].map((l, i) => <button key={l} className="chip" data-on={i === 0 ? "1" : "0"}>{l}</button>)}
              </div>
              <CodeBlock lang="javascript - @modelos/sdk">{sdk}</CodeBlock>
              <div className="row" style={{ gap: 8, color: "var(--ink-2)", fontSize: 13 }}>{I("book", { style: { width: 16, height: 16 } })} Full reference at <a className="mono" style={{ color: "var(--info)" }}>docs.modelos.ai</a></div>
            </div>
          )}

          {(ch.status === "soon" || ch.status === "regional") && (
            <div className="card card-pad">
              {ch.status === "regional" ? (
                <div className="stack" style={{ gap: 14 }}>
                  <div className="row" style={{ gap: 10 }}>
                    <span style={{ color: "var(--warn)" }}>{I("info", { style: { width: 20, height: 20 } })}</span>
                    <span className="h3">WeChat requires regional setup</span>
                  </div>
                  <p className="lead" style={{ fontSize: 14 }}>Deploying to WeChat for the China / Chinese-speaking market involves additional steps that depend on your account type.</p>
                  <div className="stack" style={{ gap: 8 }}>
                    {["Official Account verification", "Mini Program registration & review", "ICP filing for a mainland-China domain", "Approved message templates"].map(x => (
                      <div key={x} className="row" style={{ gap: 9, fontSize: 13.5 }}>{I("checkCircle", { style: { width: 16, height: 16, color: "var(--ink-3)" } })} {x}</div>
                    ))}
                  </div>
                  <div className="row" style={{ gap: 10, marginTop: 4 }}>
                    <button className="btn btn-primary">{I("book")} Read the WeChat guide</button>
                    <button className="btn btn-secondary">Talk to our team</button>
                  </div>
                </div>
              ) : (
                <div className="stack" style={{ gap: 12, alignItems: "flex-start" }}>
                  <span className="badge badge-neutral">On the roadmap</span>
                  <span className="h3">{ch.name} is coming soon</span>
                  <p className="lead" style={{ fontSize: 14 }}>We're rolling out messaging channels after website & API. Get notified when {ch.name} is ready.</p>
                  <button className="btn btn-secondary">{I("bolt")} Notify me</button>
                </div>
              )}
            </div>
          )}

          {sel === "web" && ch.status === "ready" && (
            <div className="card card-pad between wrap" style={{ gap: 14, background: deployed ? "var(--good-bg)" : "var(--surface)", borderColor: deployed ? "var(--good-border)" : "var(--border)" }}>
              <div className="row" style={{ gap: 12 }}>
                <span style={{ color: deployed ? "var(--good)" : "var(--ink-2)" }}>{I(deployed ? "checkCircle" : "rocket", { style: { width: 22, height: 22 } })}</span>
                <div>
                  <div className="h3">{deployed ? "Website widget is ready" : "Activate website widget"}</div>
                  <div className="caption">{llmKey?.configured ? `Uses saved ${llmKey.provider} key for this bot.` : localLlm.apiKey ? "Your provider key will be encrypted for this bot before activation." : "Save an OpenAI, Claude, Gemini, or GLM key before this widget can answer."}</div>
                </div>
              </div>
              <button className={cx("btn btn-lg", deployed ? "btn-secondary" : "btn-primary")} disabled={deployBusy || !botId} onClick={() => updateDeployment(deployed ? "disable" : "activate")}>
                {deployBusy ? "Working..." : deployed ? "Disable" : <>{I("rocket")} Activate</>}
              </button>
            </div>
          )}

          {ch.status === "ready" && deployStatus && deployStatus.type === "error" && (
            <div className="card card-pad">
              <div className="row" style={{ gap: 10 }}>
                <span style={{ color: "var(--bad)" }}>{I("alert", { style: { width: 18, height: 18 } })}</span>
                <div>
                  <div className="h3">Widget setup needs attention</div>
                  <div className="caption danger">{deployStatus.text}</div>
                </div>
              </div>
            </div>
          )}
        </div>
      </div>
      <style>{`@media(max-width:1000px){.dp-grid{grid-template-columns:1fr !important}.web-grid{grid-template-columns:1fr !important}}`}</style>
    </div>
  );
}
window.DeployView = DeployView;
