// InstancePanel — SSH terminal + port management overlay

const { SshTerminal } = window.SEIS_TERMINAL;
const { ChatPanel }  = window.SEIS_CHAT;

function PortsPanel({ instanceId }) {
  const [rules,    setRules]    = React.useState(null);
  const [loading,  setLoading]  = React.useState(true);
  const [port,     setPort]     = React.useState("");
  const [protocol, setProtocol] = React.useState("tcp");
  const [cidr,     setCidr]     = React.useState("0.0.0.0/0");
  const [desc,     setDesc]     = React.useState("");
  const [adding,   setAdding]   = React.useState(false);
  const [err,      setErr]      = React.useState("");

  const load = () => {
    setLoading(true);
    fetch(`/api/ec2/instance/${instanceId}/ports`, { credentials: "include" })
      .then(r => r.ok ? r.json() : Promise.reject(r.status))
      .then(d => { setRules(d); setLoading(false); })
      .catch(() => { setErr("Failed to load ports"); setLoading(false); });
  };

  React.useEffect(() => { load(); }, [instanceId]);

  const handleAdd = async () => {
    const p = parseInt(port);
    if (!p || p < 1 || p > 65535) { setErr("Invalid port"); return; }
    setAdding(true); setErr("");
    try {
      const r = await fetch(`/api/ec2/instance/${instanceId}/ports`, {
        method: "POST", credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ port: p, protocol, cidr, description: desc }),
      });
      if (!r.ok) { const b = await r.json().catch(() => ({})); setErr(b.detail || "Add failed"); }
      else { setPort(""); setDesc(""); load(); }
    } catch { setErr("Network error"); }
    finally { setAdding(false); }
  };

  const handleRemove = async (rule) => {
    try {
      const r = await fetch(`/api/ec2/instance/${instanceId}/ports`, {
        method: "DELETE", credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ port: rule.fromPort, protocol: rule.protocol, cidr: rule.cidr }),
      });
      if (!r.ok) { const b = await r.json().catch(() => ({})); setErr(b.detail || "Remove failed"); }
      else load();
    } catch { setErr("Network error"); }
  };

  const PRESETS = [
    { label: "SSH",   port: "22",   proto: "tcp" },
    { label: "HTTP",  port: "80",   proto: "tcp" },
    { label: "HTTPS", port: "443",  proto: "tcp" },
    { label: "RDP",   port: "3389", proto: "tcp" },
    { label: "8080",  port: "8080", proto: "tcp" },
    { label: "8888",  port: "8888", proto: "tcp" },
  ];

  return (
    <div>
      <div className="micro" style={{ marginBottom: 10, color: "var(--muted)" }}>SECURITY GROUP · INBOUND RULES</div>
      {loading ? (
        <div className="tiny" style={{ color: "var(--muted)" }}>LOADING...</div>
      ) : (
        <table className="idx" style={{ fontSize: 11, marginBottom: 12 }}>
          <thead>
            <tr>
              <th>PORT</th>
              <th>PROTO</th>
              <th>SOURCE</th>
              <th>DESC</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {(rules || []).length === 0 && (
              <tr><td colSpan={5} className="tiny" style={{ color: "var(--muted)", padding: "8px 0" }}>NO RULES</td></tr>
            )}
            {(rules || []).map((r, i) => (
              <tr key={i}>
                <td className="num">{r.fromPort === r.toPort ? r.fromPort : `${r.fromPort}–${r.toPort}`}</td>
                <td>{r.protocol.toUpperCase()}</td>
                <td>{r.cidr}</td>
                <td style={{ color: "var(--muted)" }}>{r.description || "—"}</td>
                <td>
                  <button className="micro" style={{ cursor: "pointer", color: "var(--danger)" }}
                    onClick={() => handleRemove(r)}>REMOVE</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      )}

      <div className="micro" style={{ marginBottom: 8, color: "var(--muted)" }}>ADD RULE</div>
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 8 }}>
        {PRESETS.map(p => (
          <button key={p.port} className="micro" style={{ cursor: "pointer", padding: "2px 8px", border: "1px solid var(--rule-soft)" }}
            onClick={() => { setPort(p.port); setProtocol(p.proto); }}>
            {p.label}
          </button>
        ))}
      </div>
      <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
        <input type="number" placeholder="PORT" value={port} onChange={e => setPort(e.target.value)}
          style={{ width: 80 }} min="1" max="65535" />
        <select value={protocol} onChange={e => setProtocol(e.target.value)} style={{ width: 70 }}>
          <option value="tcp">TCP</option>
          <option value="udp">UDP</option>
        </select>
        <input type="text" placeholder="CIDR" value={cidr} onChange={e => setCidr(e.target.value)}
          style={{ width: 130 }} />
        <input type="text" placeholder="DESC (optional)" value={desc} onChange={e => setDesc(e.target.value)}
          style={{ width: 160 }} />
        <button className="btn solid" style={{ padding: "6px 12px", fontSize: 10 }}
          disabled={adding || !port} onClick={handleAdd}>
          {adding ? "..." : "ADD"}
        </button>
      </div>
      {err && <div className="micro" style={{ color: "var(--danger)", marginTop: 6 }}>{err}</div>}
    </div>
  );
}

function CredentialsPanel({ instanceId, detail }) {
  const isWindows = detail?.instanceType && !detail.instanceType.startsWith("t3") && true; // always show for now
  const [creds,     setCreds]     = React.useState(null);
  const [loading,   setLoading]   = React.useState(false);
  const [revealed,  setRevealed]  = React.useState(false);
  const [err,       setErr]       = React.useState("");

  const load = async () => {
    setLoading(true); setErr("");
    try {
      const r = await fetch(`/api/ec2/instance/${instanceId}/password`, { credentials: "include" });
      const d = await r.json();
      if (!r.ok) { setErr(d.detail || "Failed"); }
      else { setCreds(d); }
    } catch { setErr("Network error"); }
    finally { setLoading(false); }
  };

  const copyText = (t) => navigator.clipboard.writeText(t).catch(() => {});

  return (
    <div style={{ padding: 20 }}>
      <div className="micro" style={{ marginBottom: 16, color: "var(--muted)" }}>INSTANCE CREDENTIALS</div>

      {detail?.publicIp && (
        <div style={{ marginBottom: 16 }}>
          <div className="micro" style={{ color: "var(--muted)", marginBottom: 6 }}>SSH / RDP HOST</div>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <code style={{ background: "var(--bg-2)", padding: "6px 10px", fontSize: 12 }}>{detail.publicIp}</code>
            <button className="micro" style={{ cursor: "pointer", color: "var(--accent)" }}
              onClick={() => copyText(detail.publicIp)}>COPY</button>
          </div>
        </div>
      )}

      <div style={{ marginBottom: 16 }}>
        <div className="micro" style={{ color: "var(--muted)", marginBottom: 6 }}>LINUX SSH</div>
        {detail?.publicIp ? (
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <code style={{ background: "var(--bg-2)", padding: "6px 10px", fontSize: 11 }}>
              ssh ubuntu@{detail.publicIp}
            </code>
            <button className="micro" style={{ cursor: "pointer", color: "var(--accent)" }}
              onClick={() => copyText(`ssh ubuntu@${detail.publicIp}`)}>COPY</button>
          </div>
        ) : <span className="tiny" style={{ color: "var(--muted)" }}>No public IP yet</span>}
      </div>

      <div>
        <div className="micro" style={{ color: "var(--muted)", marginBottom: 8 }}>WINDOWS ADMINISTRATOR PASSWORD</div>
        {!creds && !loading && (
          <div>
            <div className="tiny" style={{ color: "var(--muted)", marginBottom: 10 }}>
              Retrieved via AWS GetPasswordData + your RSA private key. May take 4–15 min after launch for Windows to generate.
            </div>
            <button className="btn" style={{ fontSize: 10 }} onClick={load}>GET PASSWORD</button>
          </div>
        )}
        {loading && <div className="tiny" style={{ color: "var(--muted)" }}>FETCHING...</div>}
        {err && <div className="micro" style={{ color: "var(--danger)", marginTop: 6 }}>{err}</div>}
        {creds && !creds.ready && (
          <div>
            <div className="tiny" style={{ color: "var(--warn)", marginBottom: 8 }}>NOT READY YET — Windows still initializing. Try again in a few minutes.</div>
            <button className="btn" style={{ fontSize: 10 }} onClick={load}>RETRY</button>
          </div>
        )}
        {creds?.ready && (
          <div>
            <table className="idx" style={{ fontSize: 12, marginBottom: 10 }}>
              <tbody>
                <tr>
                  <td style={{ color: "var(--muted)", width: 100 }}>USERNAME</td>
                  <td>
                    <code>{creds.username}</code>
                    <button className="micro" style={{ cursor: "pointer", color: "var(--accent)", marginLeft: 10 }}
                      onClick={() => copyText(creds.username)}>COPY</button>
                  </td>
                </tr>
                <tr>
                  <td style={{ color: "var(--muted)" }}>PASSWORD</td>
                  <td>
                    <code style={{ letterSpacing: revealed ? 0 : "0.2em" }}>
                      {revealed ? creds.password : "●".repeat(Math.min(creds.password.length, 20))}
                    </code>
                    <button className="micro" style={{ cursor: "pointer", color: "var(--muted)", marginLeft: 10 }}
                      onClick={() => setRevealed(r => !r)}>{revealed ? "HIDE" : "SHOW"}</button>
                    <button className="micro" style={{ cursor: "pointer", color: "var(--accent)", marginLeft: 8 }}
                      onClick={() => copyText(creds.password)}>COPY</button>
                  </td>
                </tr>
              </tbody>
            </table>
            {detail?.publicIp && (
              <div style={{ marginTop: 8 }}>
                <div className="micro" style={{ color: "var(--muted)", marginBottom: 6 }}>RDP COMMAND</div>
                <code style={{ background: "var(--bg-2)", padding: "6px 10px", fontSize: 11, display: "block" }}>
                  mstsc /v:{detail.publicIp}
                </code>
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

function InstancePanel({ instanceId, onClose, hasSshKey, user }) {
  const [detail, setDetail] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [tab, setTab] = React.useState("terminal");
  const [aiOpen, setAiOpen] = React.useState(false);
  const termCmdRef = React.useRef(null);

  React.useEffect(() => {
    if (!instanceId) return;
    fetch(`/api/ec2/instance/${instanceId}`, { credentials: "include" })
      .then(r => r.ok ? r.json() : null)
      .then(d => { setDetail(d); setLoading(false); })
      .catch(() => setLoading(false));
  }, [instanceId]);

  React.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]);

  const copyIp = (ip) => {
    navigator.clipboard.writeText(ip).catch(() => {});
  };

  return (
    <div className="modal-back" onClick={e => {
      if (e.target !== e.currentTarget) return;
      if (aiOpen && !window.confirm("Close instance panel? AI chat will be saved.")) return;
      onClose();
    }}>
      <div className="modal" style={{ width: "min(1400px, 98vw)", height: "96vh", display: "flex", flexDirection: "column" }}
           role="dialog" aria-modal="true" onClick={e => e.stopPropagation()}>

        {/* Header */}
        <div className="panel-head" style={{ flexShrink: 0 }}>
          <span className="idx">EC2-INST-001</span>
          <span className="title row gap-8">
            INSTANCE · {instanceId}
            {detail?.state && (
              <span style={{ color: detail.state === "running" ? "var(--ok)" : "var(--muted)", fontWeight: 400, fontSize: 9 }}>
                ● {detail.state.toUpperCase()}
              </span>
            )}
          </span>
          <span className="right row gap-12">
            <button onClick={() => setAiOpen(o => !o)} className="micro" style={{ cursor: "pointer", color: aiOpen ? "var(--accent)" : "var(--muted)" }} title="AI assistant">{aiOpen ? "— AI" : "+ AI"}</button>
            <button onClick={onClose} className="micro" style={{ cursor: "pointer" }}>CLOSE ✕</button>
          </span>
        </div>

        {/* Info strip */}
        {detail && (
          <div style={{ padding: "8px 16px", borderBottom: "1px solid var(--rule-soft)", display: "flex", gap: 24, flexShrink: 0, flexWrap: "wrap" }}>
            {detail.publicIp && (
              <span className="tiny" style={{ cursor: "pointer" }} onClick={() => copyIp(detail.publicIp)}
                title="Click to copy">
                PUBLIC <b>{detail.publicIp}</b> ↗
              </span>
            )}
            {detail.privateIp && (
              <span className="tiny" style={{ color: "var(--muted)" }}>PRIVATE {detail.privateIp}</span>
            )}
            <span className="tiny" style={{ color: "var(--muted)" }}>{detail.instanceType}</span>
            <span className="tiny" style={{ color: "var(--muted)" }}>{detail.az}</span>
            {detail.securityGroups?.[0] && (
              <span className="tiny" style={{ color: "var(--muted)" }}>SG: {detail.securityGroups[0].name}</span>
            )}
          </div>
        )}
        {loading && (
          <div style={{ padding: "8px 16px", borderBottom: "1px solid var(--rule-soft)", flexShrink: 0 }}>
            <div className="tiny" style={{ color: "var(--muted)" }}>LOADING...</div>
          </div>
        )}

        {/* Tab bar */}
        <div style={{ display: "flex", borderBottom: "1px solid var(--ink)", flexShrink: 0 }}>
          {[
            { key: "terminal",    label: "TERMINAL" },
            { key: "ports",       label: "PORTS" },
            { key: "credentials", label: "CREDENTIALS" },
          ].map(t => (
            <button key={t.key}
              onClick={() => setTab(t.key)}
              className="micro"
              style={{
                padding: "10px 20px",
                cursor: "pointer",
                borderRight: "1px solid var(--rule-soft)",
                background: tab === t.key ? "var(--bg-2)" : "transparent",
                fontWeight: tab === t.key ? 700 : 400,
                borderBottom: tab === t.key ? "2px solid var(--ink)" : "none",
              }}>
              {t.label}
            </button>
          ))}
        </div>

        {/* Content */}
        <div style={{ flex: 1, minHeight: 0, overflow: "hidden" }}>
          {tab === "terminal" && (
            <div style={{ height: "100%", display: "flex" }}>
              <div style={{ flex: aiOpen ? 1 : 1, minWidth: 0 }}>
                {!hasSshKey ? (
                  <div style={{ padding: 32 }}>
                    <div className="tiny" style={{ color: "var(--accent)", marginBottom: 12 }}>
                      ⚠ TERMINAL REQUIRES A GENERATED SSH KEY
                    </div>
                    <div className="micro" style={{ color: "var(--muted)" }}>
                      Generate a key in the SSH KEY section above. Pasted keys are not supported
                      (private key is not stored). Use your local terminal:{" "}
                      <code style={{ background: "var(--bg-2)", padding: "2px 6px" }}>
                        ssh ubuntu@{detail?.publicIp || "<public-ip>"}
                      </code>
                    </div>
                  </div>
                ) : (
                  <SshTerminal instanceId={instanceId} commandRef={termCmdRef} />
                )}
              </div>
              {aiOpen && (
                <div style={{ width: "min(400px, 45vw)", flexShrink: 0, height: "100%" }}>
                  <ChatPanel
                    open={true}
                    onToggle={() => setAiOpen(false)}
                    user={user}
                    inline
                    instanceId={instanceId}
                    onRunCommand={(cmd) => termCmdRef.current?.send(cmd)}
                    onYoloRun={(cmd) => termCmdRef.current?.runAndCapture(cmd) || Promise.resolve("")}
                  />
                </div>
              )}
            </div>
          )}
          {tab === "ports" && (
            <div style={{ padding: 16, overflowY: "auto", height: "100%" }}>
              <PortsPanel instanceId={instanceId} />
            </div>
          )}
          {tab === "credentials" && (
            <div style={{ overflowY: "auto", height: "100%" }}>
              <CredentialsPanel instanceId={instanceId} detail={detail} />
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

window.SEIS_INSTANCE_PANEL = { InstancePanel };
