import { FormEvent, useEffect, useState } from "react";
import { apiFetch, setSession, type NodeCard } from "../api";

type Tab = "account" | "add" | "list";

export default function SettingsPage() {
  const [tab, setTab] = useState<Tab>("account");
  const [nodes, setNodes] = useState<NodeCard[]>([]);
  const [name, setName] = useState("");
  const [baseUrl, setBaseUrl] = useState("https://");
  const [err, setErr] = useState("");
  const [ok, setOk] = useState("");
  const [lastToken, setLastToken] = useState<{ id: number; token: string } | null>(
    null,
  );

  const [newUsername, setNewUsername] = useState("");
  const [currentPassword, setCurrentPassword] = useState("");
  const [newPassword, setNewPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [credBusy, setCredBusy] = useState(false);
  const [showHint, setShowHint] = useState(false);
  const [lanBypass, setLanBypass] = useState(false);
  const [lanBusy, setLanBusy] = useState(false);

  async function load() {
    const r = await apiFetch<{ nodes: NodeCard[] }>("/api/nodes/");
    setNodes(r.nodes || []);
  }

  async function loadMe() {
    const m = await apiFetch<{
      show_default_hint?: boolean;
      lan_bypass_enabled?: boolean;
    }>("/api/auth/me");
    setShowHint(!!m.show_default_hint);
    setLanBypass(!!m.lan_bypass_enabled);
  }

  useEffect(() => {
    Promise.all([load(), loadMe()]).catch((ex) =>
      setErr(ex instanceof Error ? ex.message : String(ex)),
    );
  }, []);

  async function onAdd(e: FormEvent) {
    e.preventDefault();
    setErr("");
    setOk("");
    try {
      await apiFetch("/api/nodes/", {
        method: "POST",
        body: JSON.stringify({ name: name.trim(), base_url: baseUrl.trim() }),
      });
      setName("");
      setOk("已添加策略机");
      await load();
      setTab("list");
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : String(ex));
    }
  }

  async function onSaveCreds(e: FormEvent) {
    e.preventDefault();
    setErr("");
    setOk("");
    if (newPassword !== confirmPassword) {
      setErr("两次新密码不一致");
      return;
    }
    setCredBusy(true);
    try {
      const r = await apiFetch<{
        token: string;
        username: string;
        show_default_hint?: boolean;
      }>("/api/auth/change-credentials", {
        method: "POST",
        body: JSON.stringify({
          current_password: currentPassword,
          new_username: newUsername.trim(),
          new_password: newPassword,
        }),
      });
      setSession(r.token, r.username);
      setCurrentPassword("");
      setNewPassword("");
      setConfirmPassword("");
      setNewUsername("");
      setShowHint(!!r.show_default_hint);
      setOk("中控账号已更新");
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : String(ex));
    } finally {
      setCredBusy(false);
    }
  }

  async function onToggleLan(next: boolean) {
    setErr("");
    setOk("");
    setLanBusy(true);
    try {
      const r = await apiFetch<{ lan_bypass_enabled: boolean }>(
        "/api/auth/lan-bypass",
        {
          method: "PUT",
          body: JSON.stringify({ enabled: next }),
        },
      );
      setLanBypass(!!r.lan_bypass_enabled);
      setOk(
        next
          ? "已开启局域网免登录（仅私网 IP 生效）"
          : "已关闭局域网免登录",
      );
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : String(ex));
    } finally {
      setLanBusy(false);
    }
  }

  async function genToken(id: number) {
    setErr("");
    setOk("");
    try {
      const r = await apiFetch<{ token: string; msg: string }>(
        `/api/nodes/${id}/generate-token`,
        { method: "POST" },
      );
      setLastToken({ id, token: r.token });
      setOk(r.msg || "已生成 Token");
      await load();
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : String(ex));
    }
  }

  async function remove(id: number) {
    if (!window.confirm("确认删除该策略机？")) return;
    setErr("");
    try {
      await apiFetch(`/api/nodes/${id}`, { method: "DELETE" });
      setOk("已删除");
      await load();
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : String(ex));
    }
  }

  async function copyToken(text: string) {
    setErr("");
    setOk("");
    try {
      if (navigator.clipboard?.writeText) {
        await navigator.clipboard.writeText(text);
        setOk("已复制到剪贴板");
        return;
      }
    } catch {
      /* fall through to legacy copy */
    }
    try {
      const ta = document.createElement("textarea");
      ta.value = text;
      ta.setAttribute("readonly", "");
      ta.style.position = "fixed";
      ta.style.left = "-9999px";
      document.body.appendChild(ta);
      ta.select();
      ta.setSelectionRange(0, text.length);
      const okCopy = document.execCommand("copy");
      document.body.removeChild(ta);
      if (okCopy) {
        setOk("已复制到剪贴板");
        return;
      }
    } catch {
      /* ignore */
    }
    setErr("复制失败，请手动选中 Token 复制");
  }

  return (
    <div>
      <h2>系统设置</h2>
      <p className="meta">
        中控不访问交易所。生成 Token 后登录策略机，在「登录账户」中保存同一 Token。
      </p>

      <div className="settings-tabs" role="tablist">
        <button
          type="button"
          className={tab === "account" ? "tab active" : "tab"}
          onClick={() => setTab("account")}
        >
          中控登录账户
        </button>
        <button
          type="button"
          className={tab === "add" ? "tab active" : "tab"}
          onClick={() => setTab("add")}
        >
          添加策略机
        </button>
        <button
          type="button"
          className={tab === "list" ? "tab active" : "tab"}
          onClick={() => setTab("list")}
        >
          策略机列表
        </button>
      </div>

      {err ? <div className="err">{err}</div> : null}
      {ok ? <div className="ok">{ok}</div> : null}

      {tab === "account" ? (
        <form className="add-form" onSubmit={onSaveCreds} autoComplete="off">
          <h3>中控登录账号</h3>
          {showHint ? (
            <p className="meta">当前仍为默认账号，建议修改用户名与密码。</p>
          ) : (
            <p className="meta">修改后旧会话将失效，需重新登录（局域网免登除外）。</p>
          )}
          <label className="switch-row">
            <span>
              本地局域网免登录
              <span className="meta switch-hint">
                开启后，从 192.168/10/172.16 等私网访问可自动进入，无需密码
              </span>
            </span>
            <button
              type="button"
              className={`switch ${lanBypass ? "on" : ""}`}
              disabled={lanBusy}
              aria-pressed={lanBypass}
              onClick={() => void onToggleLan(!lanBypass)}
            >
              <span className="switch-knob" />
            </button>
          </label>
          <label>
            新用户名
            <input
              value={newUsername}
              onChange={(e) => setNewUsername(e.target.value)}
              autoComplete="off"
              name="control-new-user"
              placeholder="输入新用户名"
              required
            />
          </label>
          <label>
            当前密码
            <input
              type="password"
              value={currentPassword}
              onChange={(e) => setCurrentPassword(e.target.value)}
              autoComplete="new-password"
              name="control-cur-pass"
              required
            />
          </label>
          <label>
            新密码
            <input
              type="password"
              value={newPassword}
              onChange={(e) => setNewPassword(e.target.value)}
              autoComplete="new-password"
              name="control-new-pass"
              minLength={6}
              required
            />
          </label>
          <label>
            确认新密码
            <input
              type="password"
              value={confirmPassword}
              onChange={(e) => setConfirmPassword(e.target.value)}
              autoComplete="new-password"
              name="control-confirm-pass"
              minLength={6}
              required
            />
          </label>
          <button className="btn" type="submit" disabled={credBusy}>
            {credBusy ? "保存中…" : "保存账号"}
          </button>
        </form>
      ) : null}

      {tab === "add" ? (
        <form className="add-form" onSubmit={onAdd}>
          <h3>添加策略机</h3>
          <label>
            名称
            <input
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="例如 云机-A"
              required
            />
          </label>
          <label>
            公网 Base URL
            <input
              value={baseUrl}
              onChange={(e) => setBaseUrl(e.target.value)}
              placeholder="https://dc.hyf2.cc"
              required
            />
          </label>
          <button className="btn" type="submit">
            添加
          </button>
        </form>
      ) : null}

      {tab === "list" ? (
        <div>
          {lastToken ? (
            <div className="token-box">
              <div>节点 #{lastToken.id} 新 Token（只显示一次，请复制）：</div>
              <code className="mono">{lastToken.token}</code>
              <button
                type="button"
                className="btn ghost"
                onClick={() => void copyToken(lastToken.token)}
              >
                复制
              </button>
            </div>
          ) : null}
          <div className="table-wrap">
            <table>
              <thead>
                <tr>
                  <th>ID</th>
                  <th>名称</th>
                  <th>URL</th>
                  <th>Token</th>
                  <th>操作</th>
                </tr>
              </thead>
              <tbody>
                {nodes.map((n) => (
                  <tr key={n.id}>
                    <td>{n.id}</td>
                    <td>{n.name}</td>
                    <td className="mono">{n.base_url}</td>
                    <td>{n.token_configured ? "已生成" : "无"}</td>
                    <td className="row-actions">
                      <button
                        type="button"
                        className="btn"
                        onClick={() => void genToken(n.id)}
                      >
                        生成 Token
                      </button>
                      <button
                        type="button"
                        className="btn ghost"
                        onClick={() => void remove(n.id)}
                      >
                        删除
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          {!nodes.length ? <p className="meta">暂无策略机，请到「添加策略机」。</p> : null}
        </div>
      ) : null}
    </div>
  );
}
