"use client";

import Link from "next/link";
import { useEffect, useId, useRef, useState, type RefObject } from "react";
import {
  BookOpen,
  ClipboardCheck,
  FileText,
  Library,
  PanelLeft,
  PanelRight,
  PenLine,
  Square,
} from "lucide-react";

import { AppShell } from "@/components/AppShell";
import { Drawer } from "@/components/Drawer";
import { Button } from "@/components/ui/Button";
import { SectionHeader } from "@/components/ui/SectionHeader";
import { StatusNote } from "@/components/ui/StatusNote";
import { TextArea } from "@/components/ui/TextArea";
import type { ProjectResponse } from "@/lib/api/types";
import { friendlyError } from "@/lib/errors/messages";
import { useAutosave } from "@/lib/autosave/useAutosave";
import { useDraftStream } from "@/lib/stream/useDraftStream";
import {
  WORKBENCH_CHAPTER_NO,
  type ChapterEntry,
} from "@/lib/workbench/chapter";
import { composeDirective, STYLE_PRESETS } from "@/lib/workbench/directive";
import { buttonClass } from "@/lib/ui/variants";
import { ChapterList, ChapterListContent } from "./ChapterList";
import { ChapterAssistant, AssistantContent } from "./ChapterAssistant";
import { Editor } from "./Editor";

interface WorkbenchProps {
  project: ProjectResponse;
  // 当前章号（来自写作路由 `?chapter=N`）；缺省回退第 1 章。
  chapterNo?: number;
  // RSC 种入的已存草稿正文（GET .../draft）；无草稿（404）→ ""（空编辑器）。
  initialText?: string;
  // 大纲章节目录（GET .../outline）；无大纲 → 空数组（目录回退到仅当前章 + 去大纲提示）。
  chapters?: ChapterEntry[];
}

// 移动端右栏（目录/助手）经抽屉触达；桌面用三栏栅格。
type MobilePanel = "chapters" | "assistant" | null;

// M1：单章工作台。章节列表为占位（无章节列表端点）；默认第 1 章。
// WORKBENCH_CHAPTER_NO 移到 lib/workbench/chapter.ts（非客户端模块），供 Server Component 安全导入。

export function Workbench({
  project,
  chapterNo = WORKBENCH_CHAPTER_NO,
  initialText = "",
  chapters = [],
}: WorkbenchProps) {
  // 用已存草稿作初值；流式开始后由下方 effect 覆盖（流不会被初值反扑——
  // stream.state.text 起始为空，仅当 streaming/done/aborted 且变化才写回）。
  const [text, setText] = useState(initialText);
  const [mobilePanel, setMobilePanel] = useState<MobilePanel>(null);
  // 本章指令（T4-b）：自由文本 + 风格预设 → 写本章时组装传入 draft 生成。
  const [directive, setDirective] = useState("");
  const [presetIds, setPresetIds] = useState<string[]>([]);
  const autosave = useAutosave(project.id, chapterNo, initialText);
  const stream = useDraftStream();
  const lastStreamText = useRef("");
  const chapterTriggerRef = useRef<HTMLButtonElement>(null);
  const assistantTriggerRef = useRef<HTMLButtonElement>(null);

  // 流式 token 累积进编辑器（打字机）；停止/结束后已生成部分留在草稿。
  useEffect(() => {
    const streamed = stream.state.text;
    if (
      (stream.state.phase === "streaming" ||
        stream.state.phase === "done" ||
        stream.state.phase === "aborted") &&
      streamed !== lastStreamText.current
    ) {
      lastStreamText.current = streamed;
      setText(streamed);
      autosave.onChange(streamed);
    }
  }, [stream.state.phase, stream.state.text, autosave]);

  const onWrite = (): void => {
    void stream.start(
      project.id,
      chapterNo,
      composeDirective(directive, presetIds),
    );
  };

  const togglePreset = (id: string): void => {
    setPresetIds((prev) =>
      prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id],
    );
  };

  const onEditorChange = (value: string): void => {
    setText(value);
    autosave.onChange(value);
  };

  const wordCount = text.length;
  const closePanel = (): void => setMobilePanel(null);

  return (
    <AppShell
      title={`〈${project.title}〉`}
      subtitle={`第 ${chapterNo} 章`}
      projectId={project.id}
      activeNav="write"
    >
      <div className="grid min-h-[calc(100vh-var(--chrome,4rem))] grid-cols-1 lg:h-[calc(100vh-var(--chrome,4rem))] lg:grid-cols-[12rem_1fr_18rem]">
        <ChapterList
          projectId={project.id}
          chapters={chapters}
          currentChapterNo={chapterNo}
        />

        <section className="flex min-w-0 flex-col bg-bg">
          <MobileContextBar
            chapterNo={chapterNo}
            onOpenChapters={() => setMobilePanel("chapters")}
            onOpenAssistant={() => setMobilePanel("assistant")}
            chapterTriggerRef={chapterTriggerRef}
            assistantTriggerRef={assistantTriggerRef}
          />
          <DirectivePanel
            directive={directive}
            onDirectiveChange={setDirective}
            presetIds={presetIds}
            onTogglePreset={togglePreset}
          />
          <div className="flex-1 overflow-auto px-6 py-8">
            <Editor
              value={text}
              onChange={onEditorChange}
              streaming={stream.isStreaming}
            />
          </div>
          <Toolbar
            projectId={project.id}
            chapterNo={chapterNo}
            wordCount={wordCount}
            savedLabel={autosave.savedLabel}
            saveStatus={autosave.status}
            streaming={stream.isStreaming}
            streamError={stream.state.error}
            onWrite={onWrite}
            onStop={stream.stop}
          />
        </section>

        <ChapterAssistant projectId={project.id} chapterNo={chapterNo} />
      </div>

      {/* 移动端：目录 / 本章助手经抽屉触达（桌面已在栅格里，抽屉 lg:hidden）。 */}
      <Drawer
        open={mobilePanel === "chapters"}
        onClose={closePanel}
        side="left"
        label="目录"
        triggerRef={chapterTriggerRef}
      >
        <ChapterListContent
          projectId={project.id}
          chapters={chapters}
          currentChapterNo={chapterNo}
        />
      </Drawer>
      <Drawer
        open={mobilePanel === "assistant"}
        onClose={closePanel}
        side="right"
        label="本章助手"
        triggerRef={assistantTriggerRef}
      >
        <AssistantContent projectId={project.id} chapterNo={chapterNo} />
      </Drawer>
    </AppShell>
  );
}

interface MobileContextBarProps {
  chapterNo: number;
  onOpenChapters: () => void;
  onOpenAssistant: () => void;
  chapterTriggerRef: RefObject<HTMLButtonElement | null>;
  assistantTriggerRef: RefObject<HTMLButtonElement | null>;
}

function MobileContextBar({
  chapterNo,
  onOpenChapters,
  onOpenAssistant,
  chapterTriggerRef,
  assistantTriggerRef,
}: MobileContextBarProps) {
  return (
    <div className="flex items-center justify-between gap-2 border-b border-line bg-panel px-4 py-2 lg:hidden">
      <Button
        ref={chapterTriggerRef}
        onClick={onOpenChapters}
        variant="secondary"
        size="sm"
      >
        <PanelLeft className="h-4 w-4" aria-hidden="true" />
        目录
      </Button>
      <span className="min-w-0 truncate font-mono text-xs text-ink-soft">
        第 {chapterNo} 章
      </span>
      <Button
        ref={assistantTriggerRef}
        onClick={onOpenAssistant}
        variant="secondary"
        size="sm"
      >
        <PanelRight className="h-4 w-4" aria-hidden="true" />
        助手
      </Button>
    </div>
  );
}

interface DirectivePanelProps {
  directive: string;
  onDirectiveChange: (value: string) => void;
  presetIds: readonly string[];
  onTogglePreset: (id: string) => void;
}

// 本章指令面板（T4-b）：可折叠的 textarea + 风格快捷预设 chips。
// 默认折叠（不抢编辑视野）；指令覆盖/补充大纲节拍，写本章时组装传入生成。
function DirectivePanel({
  directive,
  onDirectiveChange,
  presetIds,
  onTogglePreset,
}: DirectivePanelProps) {
  const panelId = useId();
  const activeCount = presetIds.length + (directive.trim().length > 0 ? 1 : 0);
  return (
    <details className="border-b border-line bg-panel px-4 py-3 sm:px-6">
      <summary
        className="flex cursor-pointer list-none items-center justify-between gap-3 text-sm text-ink-soft hover:text-cinnabar"
        aria-controls={panelId}
      >
        <span className="font-serif text-base text-ink">本章生成控制台</span>
        <span className="rounded border border-line bg-bg px-2 py-0.5 text-xs text-ink-soft">
          {activeCount > 0 ? `${activeCount} 项指令` : "可选"}
        </span>
      </summary>
      <div id={panelId} className="mt-3 space-y-3">
        <SectionHeader
          title="写作指令"
          description="用于补充或覆盖本章大纲节拍，只影响本次生成。"
        />
        <label className="block">
          <span className="sr-only">本章指令</span>
          <TextArea
            value={directive}
            onChange={(e) => onDirectiveChange(e.target.value)}
            rows={2}
            placeholder="本章想怎么写？（可选，覆盖/补充大纲节拍）"
          />
        </label>
        <div className="flex flex-wrap gap-2" role="group" aria-label="风格预设">
          {STYLE_PRESETS.map((preset) => {
            const active = presetIds.includes(preset.id);
            return (
              <Button
                key={preset.id}
                type="button"
                aria-pressed={active}
                onClick={() => onTogglePreset(preset.id)}
                variant={active ? "outline" : "secondary"}
                size="sm"
              >
                {preset.label}
              </Button>
            );
          })}
        </div>
        {activeCount > 0 ? (
          <StatusNote variant="info">
            写本章时会把已选预设和自由指令合并进本次生成请求。
          </StatusNote>
        ) : null}
      </div>
    </details>
  );
}

// 写章失败提示：友好文案（不暴露 raw code）+ 可选「去设置」动作（F4）。
function StreamErrorNote({
  streamError,
}: {
  streamError: { code: string; message: string };
}) {
  const friendly = friendlyError(streamError.code, streamError.message);
  return (
    <p className="mb-2 text-sm text-conflict">
      {friendly.text}
      {friendly.actionHref ? (
        <>
          {" "}
          <Link
            href={friendly.actionHref}
            className="underline hover:text-cinnabar"
          >
            {friendly.actionLabel}
          </Link>
        </>
      ) : null}
    </p>
  );
}

interface ToolbarProps {
  projectId: string;
  chapterNo: number;
  wordCount: number;
  savedLabel: string | null;
  saveStatus: ReturnType<typeof useAutosave>["status"];
  streaming: boolean;
  streamError: { code: string; message: string } | null;
  onWrite: () => void;
  onStop: () => void;
}

function Toolbar({
  projectId,
  chapterNo,
  wordCount,
  savedLabel,
  saveStatus,
  streaming,
  streamError,
  onWrite,
  onStop,
}: ToolbarProps) {
  return (
    <div className="sticky bottom-0 z-10 border-t border-line bg-panel/95 px-4 py-2 backdrop-blur sm:px-6 sm:py-3">
      {streamError ? <StreamErrorNote streamError={streamError} /> : null}
      <div className="grid gap-2 sm:flex sm:flex-wrap sm:items-center sm:gap-3">
        <div className="flex min-w-0 flex-wrap items-center gap-2">
        {streaming ? (
          <Button onClick={onStop} variant="danger" size="sm">
            <Square className="h-4 w-4" aria-hidden="true" />
            停
          </Button>
        ) : (
          <Button onClick={onWrite} variant="primary" size="sm">
            <PenLine className="h-4 w-4" aria-hidden="true" />
            写本章
          </Button>
        )}
        {streaming ? (
          <span className="font-mono text-xs text-cinnabar motion-safe:animate-pulse">
            生成中… {wordCount.toLocaleString("en-US")} 字
          </span>
        ) : (
          <span className="font-mono text-xs text-ink-soft">
            字数 {wordCount.toLocaleString("en-US")}
          </span>
        )}
        <Link
          href={`/projects/${projectId}/outline`}
          className={buttonClass({ variant: "secondary", size: "sm" })}
        >
          <BookOpen className="h-4 w-4" aria-hidden="true" />
          大纲
        </Link>
        <Link
          href={`/projects/${projectId}/foreshadow`}
          className={buttonClass({
            variant: "secondary",
            size: "sm",
            className: "hidden sm:inline-flex",
          })}
        >
          <Library className="h-4 w-4" aria-hidden="true" />
          伏笔
        </Link>
        <Link
          href={`/projects/${projectId}/review?chapter=${chapterNo}`}
          className={buttonClass({ variant: "outline", size: "sm" })}
        >
          <ClipboardCheck className="h-4 w-4" aria-hidden="true" />
          审稿
        </Link>
        </div>
        <span className="min-w-0 font-mono text-xs text-ink-soft sm:ml-auto">
          <FileText className="mr-1 inline h-3.5 w-3.5" aria-hidden="true" />
          {saveStatus === "saving"
            ? "保存中…"
            : saveStatus === "error"
              ? "保存失败"
              : (savedLabel ?? "尚未保存")}
        </span>
      </div>
    </div>
  );
}
