import { useEffect, useMemo, useState } from "react";
import { check } from "@tauri-apps/plugin-updater";
import { relaunch } from "@tauri-apps/plugin-process";
import { Icon } from "./icons";
import * as api from "./runtime";
import type { KnowledgeDocument, SourceKind, SystemSnapshot } from "./types";

type View =
  | "channel"
  | "knowledge"
  | "market"
  | "history"
  | "portal"
  | "settings";
const nav: [View, string, string][] = [
  ["channel", "我的频道", "channel"],
  ["knowledge", "光湖知识库", "book"],
  ["market", "模块商城", "cube"],
  ["history", "系统演化史", "history"],
  ["portal", "企业门户", "building"],
  ["settings", "设置", "settings"],
];
const labels: Record<SourceKind, string> = {
  USER_MESSAGE: "用户语言",
  PERSONA_RESPONSE: "人格回应",
  SYSTEM_CONTEXT: "系统环境",
  PROTOCOL_EVENT: "协议运行",
  AGENT_ACTION: "Agent 执行",
  TOOL_RESULT: "工具结果",
  SYSTEM_RECEIPT: "系统回执",
};

export default function App() {
  const [data, setData] = useState<SystemSnapshot | null>(null),
    [view, setView] = useState<View>("channel"),
    [error, setError] = useState(""),
    [busy, setBusy] = useState(false);
  const refresh = () =>
    api
      .snapshot()
      .then(setData)
      .catch((e) => setError(String(e)));
  useEffect(() => {
    refresh();
  }, []);
  if (!data)
    return (
      <div className="boot">
        <div className="lake-mark" />
        正在进入 HoloLake…
      </div>
    );
  if (!data.channel) return <Onboarding onDone={refresh} error={error} />;
  return (
    <div className="app-shell">
      <div className="titlebar">
        <div className="traffic">
          <i />
          <i />
          <i />
        </div>
        <span>HoloLake</span>
        <span className="version">
          v{data.appVersion.replace("-browser", "")}
        </span>
      </div>
      <aside className="rail">
        <div className="brand-orbit">
          <span />
        </div>
        <nav>
          {nav.map(([id, label, icon]) => (
            <button
              key={id}
              className={view === id ? "active" : ""}
              aria-label={label}
              onClick={() => setView(id)}
            >
              <Icon name={icon} />
              <span>{label}</span>
            </button>
          ))}
        </nav>
        <div className="channel-mini">
          <div className="mini-lake" />
          <div>
            <strong>{data.channel.name}</strong>
            <small>{data.channel.channelId}</small>
          </div>
        </div>
      </aside>
      <main>
        {view === "channel" && (
          <Channel
            data={data}
            refresh={refresh}
            openKnowledge={() => setView("knowledge")}
          />
        )}{" "}
        {view === "knowledge" && <Knowledge data={data} refresh={refresh} />}{" "}
        {view === "market" && <Market />}{" "}
        {view === "history" && <History data={data} />}{" "}
        {view === "portal" && <Portal />}{" "}
        {view === "settings" && (
          <Settings
            data={data}
            refresh={refresh}
            busy={busy}
            setBusy={setBusy}
            setError={setError}
          />
        )}
      </main>
      {error && (
        <div className="toast" role="alert">
          <span>{error}</span>
          <button onClick={() => setError("")}>关闭</button>
        </div>
      )}
    </div>
  );
}

function Onboarding({ onDone, error }: { onDone: () => void; error: string }) {
  const [name, setName] = useState("");
  const go = async () => {
    if (!name.trim()) return;
    await api.createChannel(name.trim());
    onDone();
  };
  return (
    <div className="onboard">
      <div className="stars" />
      <section>
        <div className="origin-light" />
        <h1>为你的频道起一个名字</h1>
        <p>
          这是属于你的私人初始化频道。系统将为它登记唯一编号，并在本机建立私人
          Git。
        </p>
        <label>
          频道名称
          <input
            value={name}
            onChange={(e) => setName(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && go()}
            placeholder="例如：我的光湖"
            autoFocus
          />
        </label>
        <button onClick={go} disabled={!name.trim()}>
          建立我的频道
        </button>
        {error && <small>{error}</small>}
      </section>
      <footer>GH-AIOS · 光湖语言系统 · 通用人工智能操作平台</footer>
    </div>
  );
}

function Channel({
  data,
  refresh,
  openKnowledge,
}: {
  data: SystemSnapshot;
  refresh: () => void;
  openKnowledge: () => void;
}) {
  const [text, setText] = useState("");
  const send = async () => {
    if (!text.trim()) return;
    await api.submitMessage(text.trim());
    setText("");
    refresh();
  };
  return (
    <div className="page channel-page">
      <header>
        <div>
          <h1>{data.channel?.name}</h1>
          <p>个人初始化频道</p>
        </div>
        <button className="soft" onClick={openKnowledge}>
          打开光湖知识库
        </button>
      </header>
      <div className="channel-grid">
        <div className="channel-primary">
          <section className="conversation">
            <div className="welcome">
              <div className="lake-mark" />
              <h2>频道已经准备好</h2>
              <p>
                这里保存你与人格体的语言。系统动作会被分流到下方执行记录，不再混入对话。
              </p>
            </div>
            {data.timeline
              .filter(
                (e) =>
                  e.sourceKind === "USER_MESSAGE" ||
                  e.sourceKind === "PERSONA_RESPONSE",
              )
              .slice(0, 8)
              .reverse()
              .map((e) => (
                <article
                  className={
                    e.sourceKind === "USER_MESSAGE" ? "human" : "persona"
                  }
                  key={e.eventId}
                >
                  <span>{labels[e.sourceKind]}</span>
                  <p>{e.content}</p>
                </article>
              ))}
          </section>
          <ReceiptStream data={data} />
          <div className="composer">
            <textarea
              value={text}
              onChange={(e) => setText(e.target.value)}
              placeholder={`和${data.channel?.name}说点什么…`}
              onKeyDown={(e) => {
                if (e.key === "Enter" && !e.shiftKey) {
                  e.preventDefault();
                  send();
                }
              }}
            />
            <button onClick={send} aria-label="发送">
              ↗
            </button>
            <small>Enter 发送 · Shift + Enter 换行</small>
          </div>
        </div>
        <aside className="channel-context" aria-label="频道运行状态">
          <article>
            <h2>当前频道</h2>
            <strong>{data.channel?.name}</strong>
            <p>{data.channel?.channelId}</p>
          </article>
          <article>
            <h2>私人 Git</h2>
            <strong>本机已建立</strong>
            <p className="path">{data.channel?.privateGitPath}</p>
          </article>
          <article>
            <h2>公共更新</h2>
            <strong>
                {data.publicDistributionState === "SIGNED_UPDATE_FEED_READY_NO_RELEASE"
                  ? "更新入口在线 · 暂无发行"
                  : data.publicDistributionState}
            </strong>
            <p>只接收签名发行，不自动执行普通 Git 拉取。</p>
          </article>
        </aside>
      </div>
    </div>
  );
}

function ReceiptStream({ data }: { data: SystemSnapshot }) {
  const rows = data.timeline
    .filter(
      (e) =>
        e.sourceKind !== "USER_MESSAGE" && e.sourceKind !== "PERSONA_RESPONSE",
    )
    .slice(0, 5);
  return (
    <section className="receipt-stream">
      <h2>执行记录</h2>
      {rows.length === 0 ? (
        <p className="empty">
          还没有系统动作。你的语言与执行记录会在这里分开呈现。
        </p>
      ) : (
        rows.map((e) => (
          <div
            className={`receipt ${e.sourceKind.toLowerCase()}`}
            key={e.eventId}
          >
            <span className="kind">{labels[e.sourceKind]}</span>
            <strong>{e.title}</strong>
            <p>{e.content}</p>
            <time>
              {new Date(e.occurredAt).toLocaleTimeString("zh-CN", {
                hour: "2-digit",
                minute: "2-digit",
                second: "2-digit",
              })}
            </time>
          </div>
        ))
      )}
    </section>
  );
}

function Knowledge({
  data,
  refresh,
}: {
  data: SystemSnapshot;
  refresh: () => void;
}) {
  const [selected, setSelected] = useState<string | null>(
      data.documents[0]?.path ?? null,
    ),
    [doc, setDoc] = useState<KnowledgeDocument | null>(null),
    [body, setBody] = useState(""),
    [query, setQuery] = useState(""),
    [newTitle, setNewTitle] = useState<string | null>(null);
  useEffect(() => {
    if (selected)
      api.readDocument(selected).then((d) => {
        setDoc(d);
        setBody(d.body);
      });
  }, [selected]);
  const list = useMemo(
    () =>
      data.documents.filter((d) =>
        d.title.toLowerCase().includes(query.toLowerCase()),
      ),
    [data.documents, query],
  );
  const create = async () => {
    const title = newTitle?.trim();
    if (title) {
      await api.createDocument(title);
      setNewTitle(null);
      await refresh();
      setSelected(`${title.replace(/[\\/:*?\"<>|]/g, "-")}.md`);
    }
  };
  const save = async () => {
    if (doc) {
      await api.saveDocument(doc.path, body);
      refresh();
    }
  };
  const del = async () => {
    if (doc && confirm(`把“${doc.title}”移入回收站？`)) {
      await api.deleteDocument(doc.path);
      setSelected(null);
      setDoc(null);
      refresh();
    }
  };
  return (
    <div className="page knowledge-page">
      <header>
        <div>
          <h1>光湖知识库</h1>
          <p>预装模块 · HLP-MOD-KB-0001</p>
        </div>
        <div className="actions">
          <button
            className="soft"
            onClick={async () => {
              await api.importFolder();
              refresh();
            }}
          >
            导入文件夹
          </button>
          <button onClick={() => setNewTitle("")}>新建知识页</button>
        </div>
      </header>
      <div className="knowledge-workspace">
        <aside>
          <input
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="搜索知识库"
          />
          {list.length === 0 ? (
            <p className="empty">暂无知识页</p>
          ) : (
            list.map((d) => (
              <button
                className={selected === d.path ? "selected" : ""}
                key={d.path}
                onClick={() => setSelected(d.path)}
              >
                <strong>{d.title}</strong>
                <small>
                  {new Date(d.updatedAt).toLocaleDateString("zh-CN")}
                </small>
              </button>
            ))
          )}
        </aside>
        <section>
          {doc ? (
            <>
              <div className="editor-tools">
                <strong>{doc.title}</strong>
                <span />
                <button onClick={() => api.exportDocument(doc.path)}>
                  下载
                </button>
                <button className="danger" onClick={del}>
                  删除
                </button>
                <button onClick={save}>保存</button>
              </div>
              <textarea
                className="editor"
                value={body}
                onChange={(e) => setBody(e.target.value)}
              />
            </>
          ) : (
            <div className="welcome">
              <Icon name="book" />
              <h2>从第一条知识开始</h2>
              <p>新建页面，或导入一个外部文件夹。原文件不会被改写。</p>
              <button onClick={() => setNewTitle("")}>新建知识页</button>
            </div>
          )}
        </section>
      </div>
      {newTitle !== null && (
        <div className="modal-backdrop" onMouseDown={() => setNewTitle(null)}>
          <form
            className="modal"
            onSubmit={(e) => {
              e.preventDefault();
              create();
            }}
            onMouseDown={(e) => e.stopPropagation()}
          >
            <h2>新建知识页</h2>
            <p>名称将成为本地 Markdown 文件名，并进入私人 Git。</p>
            <label>
              知识页名称
              <input
                value={newTitle}
                onChange={(e) => setNewTitle(e.target.value)}
                placeholder="例如：第一条知识"
                autoFocus
              />
            </label>
            <div>
              <button
                type="button"
                className="soft"
                onClick={() => setNewTitle(null)}
              >
                取消
              </button>
              <button type="submit" disabled={!newTitle.trim()}>
                创建
              </button>
            </div>
          </form>
        </div>
      )}
    </div>
  );
}

function Market() {
  return (
    <div className="page simple">
      <header>
        <div>
          <h1>模块商城</h1>
          <p>能力按使用主体分开登记</p>
        </div>
      </header>
      <section className="split-list">
        <div>
          <h2>人格体使用</h2>
          <p>动态脑、技能和执行零件将在签名审核后出现。</p>
          <span>当前没有已发布模块</span>
        </div>
        <div>
          <h2>人类使用</h2>
          <p>行业工作模块将在完成独立验收后出现。</p>
          <span>光湖知识库为预装模块</span>
        </div>
      </section>
    </div>
  );
}
function History({ data }: { data: SystemSnapshot }) {
  return (
    <div className="page simple">
      <header>
        <div>
          <h1>系统演化史</h1>
          <p>事实与计划分开记录</p>
        </div>
      </header>
      <section className="timeline-list">
        {data.timeline.map((e) => (
          <article key={e.eventId}>
            <time>{new Date(e.occurredAt).toLocaleString("zh-CN")}</time>
            <div>
              <strong>
                {labels[e.sourceKind]} · {e.title}
              </strong>
              <p>{e.content}</p>
            </div>
          </article>
        ))}
      </section>
    </div>
  );
}
function Portal() {
  return (
    <div className="page simple">
      <header>
        <div>
          <h1>企业门户</h1>
          <p>公共四域的官方入口位于企业服务器</p>
        </div>
      </header>
      <section className="portal">
        <div className="origin-light" />
        <h2>公共内容不嵌入私人频道</h2>
        <p>
          官方通知、四域规则和团队发布由企业门户承载。HoloLake
          只读取经过签名审核的公共发行事实。
        </p>
        <a href="https://guanghu.chat" target="_blank" rel="noreferrer">
          打开企业门户 ↗
        </a>
      </section>
    </div>
  );
}
function Settings({
  data,
  refresh,
  busy,
  setBusy,
  setError,
}: {
  data: SystemSnapshot;
  refresh: () => void;
  busy: boolean;
  setBusy: (v: boolean) => void;
  setError: (v: string) => void;
}) {
  const [bridgeName, setBridgeName] = useState("");
  const update = async () => {
    setBusy(true);
    try {
      const u = await check();
      if (!u) throw new Error("当前已是最新版本，或公共发行尚未发布。");
      if (confirm(`发现 HoloLake ${u.version}，现在安装？`)) {
        await u.downloadAndInstall();
        await relaunch();
      }
    } catch (e) {
      setError(String(e));
    } finally {
      setBusy(false);
    }
  };
  return (
    <div className="page simple">
      <header>
        <div>
          <h1>设置</h1>
          <p>本机节点、公共更新与外部 AI</p>
        </div>
      </header>
      <section className="settings-list">
        <article>
          <div>
            <h2>私人 Git</h2>
            <p>{data.channel?.privateGitPath}</p>
          </div>
          <span className="status ok">已建立</span>
        </article>
        <article>
          <div>
            <h2>公共更新</h2>
            <p>{data.publicUpdateEndpoint}</p>
          </div>
          <button className="soft" onClick={update} disabled={busy}>
            {busy ? "正在检查…" : "检查更新"}
          </button>
        </article>
        <article className="bridge">
          <div>
            <h2>外部编程 AI</h2>
            <p>以来源明确的本地表达桥接入；不能取得人格或执行主控权。</p>
          </div>
          <div>
            <input
              value={bridgeName}
              onChange={(e) => setBridgeName(e.target.value)}
              placeholder="给这个 AI 入口起名"
            />
            <button
              onClick={async () => {
                if (bridgeName.trim()) {
                  await api.registerBridge(bridgeName.trim());
                  setBridgeName("");
                  refresh();
                }
              }}
            >
              建立入口
            </button>
          </div>
        </article>
        {data.externalAiBridges.map((b) => (
          <article key={b.bridgeId}>
            <div>
              <h2>{b.displayName}</h2>
              <p>
                {b.bridgeId} · {b.inboxPath}
              </p>
            </div>
            <span className="status">{b.state}</span>
          </article>
        ))}
      </section>
    </div>
  );
}
