import { lazy, Suspense, useEffect, useMemo, useState } from "react";

import type {
  ChangeDetail,
  CollectionSummaryResponse,
  DocumentComparisonResponse,
  ModifierStageResponse,
  RunStatus,
} from "../shared/api.js";
import { fetchCollection, fetchDocument, fetchModifierStage } from "./api-client.js";

const DiffView = lazy(async () => {
  const module = await import("./DiffView.js");
  return { default: module.DiffView };
});

interface AsyncState<T> {
  loading: boolean;
  value: T | null;
  error: string | null;
}

const emptyState = <T,>(): AsyncState<T> => ({ loading: true, value: null, error: null });

function statusLabel(status: RunStatus): string {
  switch (status) {
    case "success":
      return "成功";
    case "failed":
      return "失败";
    case "unstable":
      return "不稳定";
  }
}

function shortHash(hash: string): string {
  return `${hash.slice(0, 8)}…${hash.slice(-6)}`;
}

function ErrorPanel({ message }: { message: string }) {
  return (
    <div className="state-panel state-panel--error" role="alert">
      <span className="eyebrow">无法显示</span>
      <p>{message}</p>
    </div>
  );
}

function LoadingPanel() {
  return (
    <div className="state-panel" role="status">
      <span className="loading-dot" />
      <p>正在校验本地评审数据…</p>
    </div>
  );
}

function ChangeList({
  changes,
  onSelect,
  canJump,
}: {
  changes: ChangeDetail[];
  onSelect: (change: ChangeDetail) => void;
  canJump: boolean;
}) {
  if (changes.length === 0) {
    return <p className="quiet-message">这个 Modifier 运行过，但没有修改当前文档。</p>;
  }
  return (
    <ol className="change-list">
      {changes.map((change) => (
        <li
          key={`${change.modifier_position}-${change.proposal_index}-${change.edit_index}`}
        >
          <button type="button" onClick={() => onSelect(change)} disabled={!canJump}>
            <span className="change-location">
              第 {change.location.line} 行，第 {change.location.column} 列 · 候选
              {change.proposal_index + 1} / 编辑 {change.edit_index + 1}
            </span>
            <strong>{change.reason}</strong>
            <span className="change-sample">
              <del>{change.before || "∅"}</del>
              <span aria-hidden="true">→</span>
              <ins>{change.after || "∅"}</ins>
            </span>
          </button>
        </li>
      ))}
    </ol>
  );
}

export function App() {
  const [collectionState, setCollectionState] =
    useState<AsyncState<CollectionSummaryResponse>>(emptyState);
  const [selectedDocument, setSelectedDocument] = useState<string | null>(null);
  const [documentState, setDocumentState] = useState<AsyncState<DocumentComparisonResponse>>({
    loading: false,
    value: null,
    error: null,
  });
  const [selectedModifier, setSelectedModifier] = useState<number | null>(null);
  const [stageState, setStageState] = useState<AsyncState<ModifierStageResponse>>({
    loading: false,
    value: null,
    error: null,
  });
  const [focusRange, setFocusRange] = useState<{ start: number; end: number } | null>(null);

  useEffect(() => {
    const controller = new AbortController();
    fetchCollection(controller.signal)
      .then((collection) => {
        setCollectionState({ loading: false, value: collection, error: null });
        setSelectedDocument(collection.documents[0]?.document_id ?? null);
      })
      .catch((error: unknown) => {
        if (!controller.signal.aborted) {
          setCollectionState({
            loading: false,
            value: null,
            error: error instanceof Error ? error.message : "无法读取评审集合摘要。",
          });
        }
      });
    return () => controller.abort();
  }, []);

  useEffect(() => {
    setSelectedModifier(null);
    setFocusRange(null);
    if (selectedDocument === null) {
      setDocumentState({ loading: false, value: null, error: null });
      return undefined;
    }
    const controller = new AbortController();
    setDocumentState(emptyState());
    fetchDocument(selectedDocument, controller.signal)
      .then((document) => setDocumentState({ loading: false, value: document, error: null }))
      .catch((error: unknown) => {
        if (!controller.signal.aborted) {
          setDocumentState({
            loading: false,
            value: null,
            error: error instanceof Error ? error.message : "无法读取文档。",
          });
        }
      });
    return () => controller.abort();
  }, [selectedDocument]);

  useEffect(() => {
    if (selectedDocument === null || selectedModifier === null) {
      setStageState({ loading: false, value: null, error: null });
      return undefined;
    }
    const controller = new AbortController();
    setStageState(emptyState());
    fetchModifierStage(selectedDocument, selectedModifier, controller.signal)
      .then((stage) => setStageState({ loading: false, value: stage, error: null }))
      .catch((error: unknown) => {
        if (!controller.signal.aborted) {
          setStageState({
            loading: false,
            value: null,
            error: error instanceof Error ? error.message : "无法读取 Modifier 阶段。",
          });
        }
      });
    return () => controller.abort();
  }, [selectedDocument, selectedModifier]);

  const visibleChanges = useMemo(() => {
    const document = documentState.value;
    if (document === null) {
      return [];
    }
    if (selectedModifier === null) {
      return document.changes;
    }
    return document.changes.filter((change) => change.modifier_position === selectedModifier);
  }, [documentState.value, selectedModifier]);

  const selectChange = (change: ChangeDetail): void => {
    setSelectedModifier(change.modifier_position);
    setFocusRange(change.editor_range);
  };

  if (collectionState.loading) {
    return <LoadingPanel />;
  }
  if (collectionState.error !== null || collectionState.value === null) {
    return <ErrorPanel message={collectionState.error ?? "评审集合摘要为空。"} />;
  }

  const collection = collectionState.value;
  const document = documentState.value;
  const selectedSummary = collection.documents.find(
    (item) => item.document_id === selectedDocument,
  );
  const selectedStage = stageState.value;
  const canCompare =
    document?.document.status === "success" && document.current_markdown !== null;
  const beforeText = selectedStage?.before_markdown ?? document?.input_markdown ?? "";
  const afterText = selectedStage?.after_markdown ?? document?.current_markdown ?? "";
  const beforeLabel =
    selectedStage === null
      ? "清洗前"
      : `Modifier ${selectedStage.modifier.modifier_position + 1} 执行前`;
  const afterLabel =
    selectedStage === null
      ? "清洗后"
      : `Modifier ${selectedStage.modifier.modifier_position + 1} 执行后`;

  return (
    <div className="app-shell">
      <header className="topbar">
        <div>
          <span className="brand-mark">md</span>
          <div>
            <p className="eyebrow">本地清洗评审器</p>
            <h1>{collection.collection.label}</h1>
          </div>
        </div>
        <div className="run-facts">
          <span className={`status status--${collection.collection.status}`}>
            {statusLabel(collection.collection.status)}
          </span>
          <span>{collection.summary.document_count} 份文档</span>
          <span>{collection.summary.change_count} 条修改</span>
        </div>
      </header>

      <div className="layout">
        <aside className="sidebar" aria-label="评审导航">
          <section>
            <div className="section-heading">
              <h2>文档</h2>
              <span>{collection.documents.length}</span>
            </div>
            <nav className="document-list" aria-label="文档列表">
              {collection.documents.map((item) => (
                <button
                  type="button"
                  key={item.document_id}
                  className={item.document_id === selectedDocument ? "is-active" : ""}
                  onClick={() => setSelectedDocument(item.document_id)}
                  aria-current={item.document_id === selectedDocument ? "page" : undefined}
                >
                  <span className={`status-dot status-dot--${item.status}`} />
                  <span>
                    <strong>{item.source_label}</strong>
                    <small>{item.change_count} 条修改</small>
                  </span>
                </button>
              ))}
            </nav>
          </section>

          <section className="modifier-section">
            <div className="section-heading">
              <h2>Modifier 时间线</h2>
              <button
                type="button"
                className="text-button"
                onClick={() => {
                  setSelectedModifier(null);
                  setFocusRange(null);
                }}
                disabled={selectedModifier === null}
              >
                查看总结果
              </button>
            </div>
            <ol className="modifier-list">
              {(document?.modifiers ?? []).map((modifier) => (
                <li key={`${modifier.modifier_position}-${modifier.modifier_id}`}>
                  <button
                    type="button"
                    className={modifier.modifier_position === selectedModifier ? "is-active" : ""}
                    onClick={() => {
                      setSelectedModifier(modifier.modifier_position);
                      setFocusRange(null);
                    }}
                    disabled={!canCompare || !modifier.stage_available}
                  >
                    <span className="modifier-index">{modifier.modifier_position + 1}</span>
                    <span>
                      <strong>{modifier.modifier_id}</strong>
                      <small>
                        v{modifier.modifier_version} · {modifier.change_count} 条
                      </small>
                    </span>
                  </button>
                </li>
              ))}
            </ol>
          </section>
        </aside>

        <main className="workspace">
          <section className="document-header">
            <div>
              <p className="eyebrow">当前文档</p>
              <h2>{selectedSummary?.source_label ?? "未选择"}</h2>
            </div>
            {selectedSummary === undefined ? null : (
              <div className="document-meta">
                <span className={`status status--${selectedSummary.status}`}>
                  {statusLabel(selectedSummary.status)}
                </span>
                <span title={selectedSummary.input_sha256}>
                  输入 {shortHash(selectedSummary.input_sha256)}
                </span>
                <span title={selectedSummary.current_sha256}>
                  当前 {shortHash(selectedSummary.current_sha256)}
                </span>
              </div>
            )}
          </section>

          {documentState.loading || stageState.loading ? <LoadingPanel /> : null}
          {documentState.error !== null ? <ErrorPanel message={documentState.error} /> : null}
          {stageState.error !== null ? <ErrorPanel message={stageState.error} /> : null}

          {!documentState.loading && document !== null && document.document.status !== "success" ? (
            <div className="diagnostic-panel">
              <p className="eyebrow">没有正式清洗结果</p>
              <h3>{statusLabel(document.document.status)}文档只展示审计证据</h3>
              <p>partial output 不会在这里命名为清洗结果。</p>
              {document.errors.map((error) => (
                <article key={`${error.modifier_position}-${error.stage}-${error.code}`}>
                  <strong>{error.diagnostic_type}</strong>
                  <span>{error.message}</span>
                </article>
              ))}
              {document.residual_proposals.map((proposal) => (
                <article key={`${proposal.modifier_position}-${proposal.proposal_index}`}>
                  <strong>最终复查仍有 {proposal.edits.length} 项候选编辑</strong>
                  <span>{proposal.reason}</span>
                </article>
              ))}
            </div>
          ) : null}

          {!documentState.loading && !stageState.loading && canCompare && stageState.error === null ? (
            <Suspense fallback={<LoadingPanel />}>
              <DiffView
                before={beforeText}
                after={afterText}
                beforeLabel={beforeLabel}
                afterLabel={afterLabel}
                focusRange={focusRange}
              />
            </Suspense>
          ) : null}

          {document !== null ? (
            <section className="changes-panel" aria-label="修改详情">
              <div className="changes-heading">
                <div>
                  <p className="eyebrow">实际修改</p>
                  <h3>
                    {selectedModifier === null
                      ? `全部 Modifier · ${visibleChanges.length} 条`
                      : `${document.modifiers[selectedModifier]?.modifier_id ?? "Modifier"} · ${
                          visibleChanges.length
                        } 条`}
                  </h3>
                </div>
                {selectedStage === null ? null : <p>{selectedStage.modifier.applicability}</p>}
              </div>
              <ChangeList changes={visibleChanges} onSelect={selectChange} canJump={canCompare} />
            </section>
          ) : null}
        </main>
      </div>
    </div>
  );
}
